Merge branch 'master' into feature/format_refactor

This commit is contained in:
Matthew Cech
2019-06-02 17:13:07 -07:00
25 changed files with 615 additions and 198 deletions
+4
View File
@@ -29,6 +29,10 @@ map=1
perish, thenperish=1
ping=1
poll=1
raffleend=1
rafflejoin=1
rafflespin=1
rafflestart=1
rating=1
results=1
role=1
+27 -23
View File
@@ -1,50 +1,54 @@
[ObjectBuilderFactory]
indicator=
boop=
tony, stark, dontfeelgood, dontfeelsogood=
yeet=
role=
guildroleremove=
ping=
bethistory=
benchmark, bench=
rating=
roll=
blur=
choose=
poll=
rpstart=
guildrolenotallowed=
rafflespin=
bet=
perish, thenperish=
teey=
guildrolelist=
stats=
dbstats=
beans=
eightball, 8ball=
catch=
guildroleadd=
vote=
results=
wolfram=
map=
info, about=
givebeans=
c++, g++, cplus, cpp=
work=
showpoll=
rpend=
java, jdoodle=
rafflejoin=
guildroleallowed=
buildHelp=
dbflush=
shutdown=
boop=
tony, stark, dontfeelgood, dontfeelsogood=
role=
raffleend=
ping=
roll=
blur=
choose=
rpstart=
guildrolenotallowed=
perish, thenperish=
teey=
dbstats=
rafflestart=
beans=
eightball, 8ball=
vote=
map=
info, about=
showpoll=
rpg=
tweet=
java, jdoodle=
guildroleallowed=
help=
buildHelp=
fetch=
crouton=
invite=
dbflush=
shutdown=
+95 -74
View File
@@ -17,20 +17,11 @@ BetHistoryInfo=Sees the amount of beans Kitty has earned through your bets!
[CommandCatch]
CatchInfo=Play catch with yourself or with a friend with @!
[CommandBeansShow]
BeansShowDisplay=You have %s beans!
BeansShowMentioned=I looked it up and %sbeans!
BeansShowInfo=Displays how many beans you have
[CommandGuildRoleList]
GuildRoleListOutput=The allowed roles are %s!
GuildRoleListEmpty=There are no roles allowed!
GuildRoleListInfo=Outputs a list of the roles you are allowed to add to yourself!
[CommandHelp]
HelpInfo=Lets you look up specific commands, or get a link to a list of all commands.
HelpDisplay=You can get help with a specific command by typing `!help command`!\nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`
[CommandRoll]
RollError=Didn't work ;3;
RollInfo=Based on input of xdy where x is number of dice and y is faces kitty will roll that amount of dice, display the individual rolls and total
@@ -43,16 +34,6 @@ GuildRoleAllowedDuplicate=Can't add the same role twice!
[CommandStats]
StatsInfo=Displays the actively running KittyBot application information
[CommandTweet]
TweetInfo=Kitty will tweet to her personal twitter account
TweetError=Tweet command failed!
[CommandGuildRoleAdd]
GuildRoleAddSuccess=Added %s to %s
GuildRoleAddFailure=Failed to add %s to %s
GuildRoleAddNotAllowed=You are not allowed to add %s!
GuildRoleAddInfo=Add a role to yourself!
[CommandRole]
RoleInfo=Will show the current role you have, Admins can change others roles with input of 'role x @y' with x being blacklist, general, mod, or admin. Blacklist will not allow the user to interact with kitty anymore, general mod and admin will give the user access to those commands.
RoleStandardResponse=Your role is %s
@@ -60,10 +41,6 @@ RoleError=You aren't allowed to do that! You must have the KittyRole '%s' or hig
RoleChanged=Changed %s to role `%s`!
RoleNeededRole=Please enter `general`, `mod`, or `admin`!
[CommandColiru]
ColiruError=Please provide some c++ code to attempt to compile!
ColiruInfo=Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++.
[CommandJDoodle]
JDoodleInfo=Will compile any java code you put in! Supports Java 1.8
JDoodleError=Please provide some java code to get it compiled!
@@ -76,12 +53,6 @@ ChangeIndicatorChanged=Indicator changed to `%s`
[CommandPerish]
PerishInfo=Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned
[CommandStark]
StarkInfo=Snaps your icon or the icon of a friend you mentioned
[CommandYeet]
YeetInfo=Yeet yourself or yeet a friend with @!
[CommandTradeBeans]
TradeBeanseStealingBeans=Stealing is wrong! *Steals 10 beans from %s*
TradeBeansNoTargetError=You have to give *someone* your beans!
@@ -104,19 +75,15 @@ ShutdownSafe=Shutting down, but first syncing database and finishing current thr
ShutdownUnsafe=Shutting down and immediately and abandoning all threads without sync.
ShutdownInfo=Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown.
[CommandCrouton]
CroutonInfo=Crouton
[CommandRaffleSpin]
RaffleSpinInfo=
RaffleSpinSuccess=The winner issssssss %s!
RaffleSpinFailure=I can't choose a winner D:
[CommandTeey]
TeeyInfo=Teey yourself back into existance, or teey a friend with @!
[CommandBetBeans]
BetBeansLowBet=Please bet with at least 50 beans!
BetBeansInfo=Allows you to bet your beans, set your amount after the command! Warning! House always wins!\nSets of 3 will get 2x, 4 will get 10x, and 5 will get 1000x
BetBeansNotValid=That's not a valid bet!
BetBeansLose=Sorry, you didn't win, try again!
BetBeansNotEnough=You don't have enough beans!
BetBeansWin=You won %s beans!
[CommandRaffleEnd]
RaffleEndSuccess=
RaffleEndInfo=
RaffleEndFailure=I don't think there's one going!
[CommandDoWork]
DoWorkFinished=I finished with my work! :D
@@ -128,10 +95,6 @@ RPStartInfo=Starts an rp, add people to it by mentioning them!
[CommandBlurry]
BlurryInfo=Blurs your icon or the icon of a friend you mentioned
[CommandPollResults]
PollResultsResponse=%s people voted for %s `%s` with `%s%` !\n
PollResultsInfo=Will show current results of a poll and percentages of votes per choice
[CommandRating]
RatingInfo='0' is fully sfw (Derpi and e621 searches are disabled), '1' is filtered (kitty auto appends a sfw tag on any searches), '2' is nsfw (any search will go through). Some other words are supported for setting filter as well.
RatingWarning=Warning: NSFW may slip through, images are only based on tags on their respective sites!
@@ -156,21 +119,10 @@ PollShowChoices=And the choices are:\n
[CommandHelpBuilder]
HelpBuilderInfo=Emit help for all commands as formatted HTML
[CommandRPEnd]
RPEndError=You can't end this RP!
RPEndInfo=Ends RP in channel and gives you a .txt file!
RPEndFileOut=Here's your file!
[CommandRPG]
RPGInfo=Admin+ command only right now - experimental text RPG! Format is !rpg <rpg command>
RPGInvalid=Invalid RPG Command!
[CommandBoop]
BoopPerson=%s booped %s!
BoopInfo=Kitty will react with a counter
BoopStandard=Woah! %s booped me! That's %s total!
BoopMultiple=%s booped several others - %s!
[CommandFetch]
FetchError=That no picture!
FetchEat=Me eat now *monch %s*
@@ -185,6 +137,89 @@ FetchStare=*Stares at %s*
InfoResponse=I'm made by `Rin#8904` and `Reverie Wisp#3703`!\nYou can find more info about me along with a Patreon link to support us and GitHub link for filing bugs https://www.rinsnowmew.com/bot/
InfoInfo=Provides author info and a link to Kitty's website
[CommandGuildRoleRemove]
GuildRoleRemoveNotAllowed=You're not allowed to add %s
GuildRoleRemoveFailure=Couldn't remove %s from %s
GuildRoleRemoveSuccess=Removed %s from %s!
GuildRoleRemoveInfo=
[CommandWolfram]
WolframError=Something went wrong!
WolframInfo=Will query wolframalpha with your question and give a full image output of the answer
WolframNoArgs=You need to provide some arguments!
[CommandMap]
MapInfo=Generates a map! You can pass additional information if you want with the flags `-s<seed>-w<width>-h<height>`. If one of the fields isn't provided, its default will be used. Note that adjusting the width and height impacts the map outcomes.\n\nDefault seed: Random,\nDefault Width: 35(max %s),\nDefault Height: 25(max %s)
MapSeed=Seed
MapInvalid=Invalid arguments provided!
MapVersion=Using mapgen v0.1
MapWidth=Width
MapHeight=Height
[CommandBeansShow]
BeansShowDisplay=You have %s beans!
BeansShowMentioned=I looked it up and %sbeans!
BeansShowInfo=Displays how many beans you have
[CommandRaffleStart]
RaffleStartSuccess=Started a raffle with an entrance fee of %s beans!
RaffleStartFailure=There's already a raffle going!
RaffleStart=
RaffleStartInfo=
[CommandHelp]
HelpInfo=Lets you look up specific commands, or get a link to a list of all commands.
HelpDisplay=You can get help with a specific command by typing `!help command`!\nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`
[CommandTweet]
TweetInfo=Kitty will tweet to her personal twitter account
TweetError=Tweet command failed!
[CommandGuildRoleAdd]
GuildRoleAddSuccess=Added %s to %s
GuildRoleAddFailure=Failed to add %s to %s
GuildRoleAddNotAllowed=You are not allowed to add %s!
GuildRoleAddInfo=Add a role to yourself!
[CommandColiru]
ColiruError=Please provide some c++ code to attempt to compile!
ColiruInfo=Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++.
[CommandStark]
StarkInfo=Snaps your icon or the icon of a friend you mentioned
[CommandYeet]
YeetInfo=Yeet yourself or yeet a friend with @!
[CommandCrouton]
CroutonInfo=Crouton
[CommandTeey]
TeeyInfo=Teey yourself back into existance, or teey a friend with @!
[CommandBetBeans]
BetBeansLowBet=Please bet with at least 50 beans!
BetBeansInfo=Allows you to bet your beans, set your amount after the command! Warning! House always wins!\nSets of 3 will get 2x, 4 will get 10x, and 5 will get 1000x
BetBeansNotValid=That's not a valid bet!
BetBeansLose=Sorry, you didn't win, try again!
BetBeansNotEnough=You don't have enough beans!
BetBeansWin=You won %s beans!
[CommandPollResults]
PollResultsResponse=%s people voted for %s `%s` with `%s%` !\n
PollResultsInfo=Will show current results of a poll and percentages of votes per choice
[CommandRPEnd]
RPEndError=You can't end this RP!
RPEndInfo=Ends RP in channel and gives you a .txt file!
RPEndFileOut=Here's your file!
[CommandBoop]
BoopPerson=%s booped %s!
BoopInfo=Kitty will react with a counter
BoopStandard=Woah! %s booped me! That's %s total!
BoopMultiple=%s booped several others - %s!
[CommandPing]
PingResponse=Pong!
PingInfo=Will respond with Pong!
@@ -221,26 +256,12 @@ EightBallYes10=Signs point to yes.
[CommandInvite]
InviteInfo=Provides a direct invite link for KittyBot
[CommandGuildRoleRemove]
GuildRoleRemoveNotAllowed=You're not allowed to add %s
GuildRoleRemoveFailure=Couldn't remove %s from %s
GuildRoleRemoveSuccess=Removed %s from %s!
GuildRoleRemoveInfo=
[CommandWolfram]
WolframError=Something went wrong!
WolframInfo=Will query wolframalpha with your question and give a full image output of the answer
WolframNoArgs=You need to provide some arguments!
[CommandRaffleJoin]
RaffleJoinFailure=You can't join the raffle ;3;
RaffleJoinInfo=
RaffleJoinSuccess=You joined the raffle!
[CommandDBFlush]
DBFlushInfo=
[CommandMap]
MapInfo=Generates a map! You can pass additional information if you want with the flags `-s<seed>-w<width>-h<height>`. If one of the fields isn't provided, its default will be used. Note that adjusting the width and height impacts the map outcomes.\n\nDefault seed: Random,\nDefault Width: 35(max %s),\nDefault Height: 25(max %s)
MapSeed=Seed
MapInvalid=Invalid arguments provided!
MapVersion=Using mapgen v0.1
MapWidth=Width
MapHeight=Height
+1 -1
View File
@@ -56,7 +56,7 @@ public class CommandBoop extends Command
{
super(level, rating);
boopTracker = new BoopTracker();
DatabaseManager.instance.Register(boopTracker);
DatabaseManager.instance.globalRegister(boopTracker);
}
@Override
+1 -1
View File
@@ -24,7 +24,7 @@ public class CommandDBFlush extends Command
@Override
public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
{
int numUpdated = DatabaseManager.instance.Upkeep();
int numUpdated = DatabaseManager.instance.upkeep();
KittyEmbed embed = new KittyEmbed();
embed.title = "Database queue flushed";
+2 -2
View File
@@ -33,9 +33,9 @@ public class CommandDBStats extends Command
{
KittyEmbed embed = new KittyEmbed();
embed.title = "Database Info";
embed.descriptionText = "**Tracked Items:** " + DatabaseManager.instance.GetTrackedObjectsSize();
embed.descriptionText = "**Tracked Items:** " + DatabaseManager.instance.getTrackedObjectsSize();
embed.descriptionText += "\n";
embed.descriptionText += "**Last Upkeep:** " + dateFormat.format(DatabaseManager.instance.GetLastUpkeep()) + " UTC-7";
embed.descriptionText += "**Last Upkeep:** " + dateFormat.format(DatabaseManager.instance.getLastUpkeep()) + " UTC-7";
embed.color = new Color(7*16, 8*16, 9*16);
res.CallEmbed(embed);
+32
View File
@@ -0,0 +1,32 @@
package commands;
import core.Command;
import core.LocStrings;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
import dataStructures.KittyRating;
import dataStructures.KittyRole;
import dataStructures.KittyUser;
import dataStructures.Response;
import dataStructures.UserInput;
public class CommandRaffleEnd extends Command
{
public CommandRaffleEnd(KittyRole level, KittyRating rating) { super(level, rating); }
@Override
public String HelpText() { return LocStrings.Stub("RaffleEndInfo"); }
@Override
public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
{
if(guild.endRaffle())
{
res.Call(LocStrings.Stub("RaffleEndSuccess"));
}
else
{
res.Call(LocStrings.Stub("RaffleEndFailure"));
}
}
}
+32
View File
@@ -0,0 +1,32 @@
package commands;
import core.Command;
import core.LocStrings;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
import dataStructures.KittyRating;
import dataStructures.KittyRole;
import dataStructures.KittyUser;
import dataStructures.Response;
import dataStructures.UserInput;
public class CommandRaffleJoin extends Command
{
public CommandRaffleJoin(KittyRole level, KittyRating rating) { super(level, rating); }
@Override
public String HelpText() { return LocStrings.Stub("RaffleJoinInfo"); }
@Override
public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
{
if(guild.joinRaffle(user))
{
res.Call(LocStrings.Stub("RaffleJoinSuccess"));
}
else
{
res.Call(LocStrings.Stub("RaffleJoinFailure"));
}
}
}
+32
View File
@@ -0,0 +1,32 @@
package commands;
import core.Command;
import core.LocStrings;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
import dataStructures.KittyRating;
import dataStructures.KittyRole;
import dataStructures.KittyUser;
import dataStructures.Response;
import dataStructures.UserInput;
public class CommandRaffleSpin extends Command
{
public CommandRaffleSpin(KittyRole level, KittyRating rating) { super(level, rating); }
@Override
public String HelpText() { return LocStrings.Stub("RaffleSpinInfo"); }
@Override
public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
{
try
{
res.Call(String.format(LocStrings.Stub("RaffleSpinSuccess"), guild.chooseRaffleWinner().name));
}
catch(Exception e)
{
res.Call(LocStrings.Stub("RaffleSpinFailure"));
}
}
}
+42
View File
@@ -0,0 +1,42 @@
package commands;
import core.Command;
import core.LocStrings;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
import dataStructures.KittyRating;
import dataStructures.KittyRole;
import dataStructures.KittyUser;
import dataStructures.Response;
import dataStructures.UserInput;
public class CommandRaffleStart extends Command
{
public CommandRaffleStart(KittyRole level, KittyRating rating) { super(level, rating); }
@Override
public String HelpText() { return LocStrings.Stub("RaffleStartInfo"); }
public int beanCost;
@Override
public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
{
try
{
beanCost = Integer.parseInt(input.args);
}
catch(Exception e)
{
beanCost = 100;
}
if(guild.startRaffle(beanCost))
{
res.Call(String.format(LocStrings.Stub("RaffleStartSuccess"), beanCost));
}
else
{
res.Call(LocStrings.Stub("RaffleStartFailure"));
}
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ public class CommandShutdown extends Command
{
// Force upkeep, this works so long as upkeep is on the main thread.
res.CallImmediate(LocStrings.Stub("ShutdownSafe"));
DatabaseManager.instance.Upkeep();
DatabaseManager.instance.upkeep();
GlobalLog.Warn(LogFilter.Command, LocStrings.Lookup("ShutdownSafe"));
System.exit(0);
@@ -13,19 +13,21 @@ import utils.LogFilter;
// This is where we put everything and swap out the moving parts,
// ie MySQL, PostgreSQL, SQLite, etc...
//
// Right now this can be messed up with SQL injection stuff if users
// are allowed to directly touch data. Leaving it like this temporarily,
// and is for prototyping only!
public class DatabaseDriver
// This isn't overly flexible though,
public class DatabaseDriverKeyValue
{
// Config and local varaibles
private JDBCDriver driver;
private final String globalTableName = "kitty_globals";
private final String globalKeyName = "GlobalKey";
private final String globalValueName = "GlobalValue";
private final String tableName; // Table name
private final String keyColumnName; // Column name for the key
private final String valueColumnName; // Column name for the value
public DatabaseDriver()
public DatabaseDriverKeyValue(String tableName, String keyColumnName, String valueColumnName)
{
this.tableName = tableName;
this.keyColumnName = keyColumnName;
this.valueColumnName = valueColumnName;
driver = null;
}
@@ -47,7 +49,7 @@ public class DatabaseDriver
}
// Verify tables we want to use exist
EnsureTableExists(globalTableName, globalKeyName, globalValueName); // General table. Do not remove.
EnsureTableExists(tableName, keyColumnName, valueColumnName); // General table. Do not remove.
return true;
}
@@ -87,7 +89,7 @@ public class DatabaseDriver
// Prototype formatting for key updating
private void UpdateKey(String key, String value)
{
String command = "UPDATE " + globalTableName + " SET " + globalValueName + " = ? WHERE " + globalKeyName + " = ?";
String command = "UPDATE " + tableName + " SET " + valueColumnName + " = ? WHERE " + keyColumnName + " = ?";
boolean status = driver.ExecuteStatement(JDBCStatementType.Update, command, new String[] { value, key });
GlobalLog.Log(LogFilter.Database, "UpdateKey status: " + status);
}
@@ -95,7 +97,7 @@ public class DatabaseDriver
// Protoype updating for seeing if a key exists
private boolean HasKey(String key)
{
String command = "SELECT COUNT(1) as count FROM " + globalTableName + " WHERE " + globalKeyName + " = ?";
String command = "SELECT COUNT(1) as count FROM " + tableName + " WHERE " + keyColumnName + " = ?";
ResultSet set = driver.ExecuteReturningStatement(JDBCStatementType.Select, command, new String[] { key });
String out = ResultAsString(set, "count");
return out.charAt(0) == '1';
@@ -104,7 +106,7 @@ public class DatabaseDriver
// Prototype for getting a key
private String GetKey(String key)
{
String command = "SELECT " + globalValueName + " as searchedKey FROM " + globalTableName +" WHERE " + globalKeyName + " = ?";
String command = "SELECT " + valueColumnName + " as searchedKey FROM " + tableName +" WHERE " + keyColumnName + " = ?";
ResultSet set = driver.ExecuteReturningStatement(JDBCStatementType.Select, command, new String[] { key });
return ResultAsString(set, "searchedKey");
}
@@ -112,7 +114,7 @@ public class DatabaseDriver
// Prototype for creating a key
private void CreateKey(String key, String value)
{
String command = "INSERT INTO " + globalTableName + " (GlobalKey, GlobalValue) VALUES (?, ?)";
String command = "INSERT INTO " + tableName + " (GlobalKey, GlobalValue) VALUES (?, ?)";
boolean status = driver.ExecuteStatement(JDBCStatementType.Insert, command, new String[] { key, value });
GlobalLog.Log(LogFilter.Database, "CreateKey status: " + status);
}
+124 -25
View File
@@ -5,16 +5,33 @@ import java.util.Vector;
import utils.GlobalLog;
import utils.LogFilter;
// This wrangles all of the differentiated storage systems. Internally, these may be tables,
// different databases, etc -- the goal is that it's abstracted away.
//
// TODO: Implement intermediate structure on account of duplicate patterns showing up.
public class DatabaseManager
{
// Singleton accessor
public static DatabaseManager instance = null;
// Database names and configs
private final String globalTableName = "kitty_globals"; // Table name
private final String globalKeyColumnName = "GlobalKey"; // Column name for the key
private final String globalValueColumnName = "GlobalValue"; // Column name for the value
private final String characterTableName = "kitty_characters"; // Table name
private final String characterKeyColumnName = "CharacterKey"; // Column name for the key
private final String characterValueColumnName = "CharacterValue"; // Column name for the value
// Private internal variables
private Vector<DatabaseTrackedObject> trackedObjects;
private DatabaseDriver driver;
private Vector<DatabaseTrackedObject> globalDataTrackedObjects;
private Vector<DatabaseTrackedObject> characterDataTrackedObjects;
private DatabaseDriverKeyValue globalDataDriver;
private DatabaseDriverKeyValue characterDataDriver;
private Date lastUpkeep;
// Constructor to enforce singleton.
public DatabaseManager()
{
GlobalLog.Log(LogFilter.Database, "Creating database manager");
@@ -29,75 +46,157 @@ public class DatabaseManager
return;
}
// Initialize variables
lastUpkeep = new Date();
trackedObjects = new Vector<DatabaseTrackedObject>();
driver = new DatabaseDriver();
globalDataTrackedObjects = new Vector<DatabaseTrackedObject>();
characterDataTrackedObjects = new Vector<DatabaseTrackedObject>();
if(driver.Connect() == false)
// Initialize data sets
globalDataDriver = new DatabaseDriverKeyValue(globalTableName, globalKeyColumnName, globalValueColumnName);
characterDataDriver = new DatabaseDriverKeyValue(characterTableName, characterKeyColumnName, characterValueColumnName);
// Connect data sets
if(globalDataDriver.Connect() == false)
{
GlobalLog.Error("Database failed to connect. Currently, without the DB, this bot can not run.");
GlobalLog.Error("Global database failed to connect. Without this DB, this bot can not run.");
System.exit(1);
}
if(characterDataDriver.Connect() == false)
{
GlobalLog.Error("Character database failed to connect. Without this DB, this bot can not run.");
System.exit(1);
}
}
// Thumbs through registered objects and syncs them with the database.
// Consider moving this operation to a separate thread.
public int Upkeep()
public int upkeep()
{
synchronized(trackedObjects)
int total = 0;
total += globalDataUpkeep();
total += characterDataUpkeep();
lastUpkeep = new Date();
return total;
}
// Global data management and updating, returns how many items were updated.
private int globalDataUpkeep()
{
synchronized(globalDataTrackedObjects)
{
int numUpdated = 0;
for(int i = 0 ; i < trackedObjects.size(); ++i)
for(int i = 0; i < globalDataTrackedObjects.size(); ++i)
{
DatabaseTrackedObject dto = trackedObjects.get(i);
DatabaseTrackedObject dto = globalDataTrackedObjects.get(i);
if(dto.IsDirty())
{
SetRemoteValue(dto.identifier, dto.Serialize());
globalSetRemoteValue(dto.identifier, dto.Serialize());
dto.Resolve();
++numUpdated;
}
}
lastUpkeep = new Date();
return numUpdated;
}
}
// Character data management and updating, returns how many items were updated.
private int characterDataUpkeep()
{
synchronized(characterDataTrackedObjects)
{
int numUpdated = 0;
for(int i = 0; i < characterDataTrackedObjects.size(); ++i)
{
DatabaseTrackedObject dto = characterDataTrackedObjects.get(i);
if(dto.IsDirty())
{
characterSetRemoteValue(dto.identifier, dto.Serialize());
dto.Resolve();
++numUpdated;
}
}
return numUpdated;
}
}
public void Register(DatabaseTrackedObject tracked)
/////////////////
// Global Data //
/////////////////
public void globalRegister(DatabaseTrackedObject tracked)
{
synchronized(trackedObjects)
synchronized(globalDataTrackedObjects)
{
trackedObjects.add(tracked);
tracked.DeSerialzie(GetRemoteValue(tracked.identifier));
globalDataTrackedObjects.add(tracked);
tracked.DeSerialzie(globalGetRemoteValue(tracked.identifier));
}
}
public String GetRemoteValue(String key)
private String globalGetRemoteValue(String key)
{
synchronized(driver)
synchronized(globalDataDriver)
{
return driver.CreateGetKey(key);
return globalDataDriver.CreateGetKey(key);
}
}
public void SetRemoteValue(String key, String value)
private void globalSetRemoteValue(String key, String value)
{
synchronized(driver)
synchronized(globalDataDriver)
{
driver.CreateSetKey(key, value);
globalDataDriver.CreateSetKey(key, value);
}
}
public Date GetLastUpkeep()
////////////////////
// Character Data //
////////////////////
public void characterRegister(DatabaseTrackedObject tracked)
{
synchronized(characterDataTrackedObjects)
{
characterDataTrackedObjects.add(tracked);
tracked.DeSerialzie(characterGetRemoteValue(tracked.identifier));
}
}
private String characterGetRemoteValue(String key)
{
synchronized(characterDataDriver)
{
return characterDataDriver.CreateGetKey(key);
}
}
private void characterSetRemoteValue(String key, String value)
{
synchronized(characterDataDriver)
{
characterDataDriver.CreateSetKey(key, value);
}
}
///////////////////////
// Utility functions //
///////////////////////
public Date getLastUpkeep()
{
return lastUpkeep;
}
public int GetTrackedObjectsSize()
public int getTrackedObjectsSize()
{
return trackedObjects.size();
return globalDataTrackedObjects.size();
}
}
+13 -4
View File
@@ -4,7 +4,7 @@ package core;
// have their data populated from database entries.
public abstract class DatabaseTrackedObject
{
private boolean isDirty;
private Boolean isDirty;
public final String identifier;
public DatabaseTrackedObject(String identifier)
@@ -15,17 +15,26 @@ public abstract class DatabaseTrackedObject
public final boolean IsDirty()
{
return isDirty;
synchronized(isDirty)
{
return isDirty;
}
}
public final void MarkDirty()
{
isDirty = true;
synchronized(isDirty)
{
isDirty = true;
}
}
public final void Resolve()
{
isDirty = false;
synchronized(isDirty)
{
isDirty = false;
}
}
// Consider an object factory instead of dedicated serialization methods
+7 -3
View File
@@ -131,7 +131,7 @@ public class ObjectBuilderFactory
{
// Construct a new guild with defaults
guild = new KittyGuild(uid, new AdminControl(event.getGuild()), emotesString);
DatabaseManager.instance.Register(guild);
DatabaseManager.instance.globalRegister(guild);
guildCache.put(uid, guild);
}
}
@@ -241,7 +241,7 @@ public class ObjectBuilderFactory
String discordID = event.getMember().getUser().getId();
String avatarID = event.getAuthor().getAvatarUrl();
user = new KittyUser(name, guild, role, uid, avatarID, discordID);
DatabaseManager.instance.Register(user);
DatabaseManager.instance.globalRegister(user);
userCache.put(uid, user);
}
}
@@ -285,7 +285,7 @@ public class ObjectBuilderFactory
KittyRole role = KittyRole.General;
KittyGuild guild = guildCache.get(guildID);
user = new KittyUser(name, guild, role, uid, avatarID, discordID);
DatabaseManager.instance.Register(user);
DatabaseManager.instance.globalRegister(user);
userCache.put(uid, user);
}
}
@@ -348,6 +348,9 @@ public class ObjectBuilderFactory
manager.Register(LocCommands.Stub("poll"), new CommandPollManage(KittyRole.Mod, KittyRating.Safe));
manager.Register(LocCommands.Stub("givebeans"), new CommandGiveBeans(KittyRole.Mod, KittyRating.Safe));
manager.Register(LocCommands.Stub("rpg"), new CommandRPG(KittyRole.Mod, KittyRating.Safe));
manager.Register(LocCommands.Stub("rafflestart"), new CommandRaffleStart(KittyRole.Mod, KittyRating.Safe));
manager.Register(LocCommands.Stub("rafflespin"), new CommandRaffleSpin(KittyRole.Mod, KittyRating.Safe));
manager.Register(LocCommands.Stub("raffleend"), new CommandRaffleEnd(KittyRole.Mod, KittyRating.Safe));
// General
manager.Register(LocCommands.Stub("fetch"), new CommandFetch(KittyRole.General, KittyRating.Safe));
@@ -382,6 +385,7 @@ public class ObjectBuilderFactory
manager.Register(LocCommands.Stub("bethistory"), new CommandBetHistory(KittyRole.General, KittyRating.Safe));
manager.Register(LocCommands.Stub("crouton"), new CommandCrouton(KittyRole.General, KittyRating.Safe));
manager.Register(LocCommands.Stub("benchmark, bench"), new CommandBenchmark(KittyRole.General, KittyRating.Safe));
manager.Register(LocCommands.Stub("rafflejoin"), new CommandRaffleJoin(KittyRole.General, KittyRating.Safe));
return manager;
}
+5
View File
@@ -0,0 +1,5 @@
package dataStructures;
public class KittyCharacter {
}
+54 -2
View File
@@ -15,10 +15,14 @@ public class KittyGuild extends DatabaseTrackedObject
public KittyUser guildOwner;
public boolean polling;
public String poll;
public boolean raffling;
public int raffleCost;
public ArrayList<String> hasVoted = new ArrayList<String>();
public ArrayList<String> emoji = new ArrayList<String>();
public ArrayList <KittyPoll> choices = new ArrayList<KittyPoll>();
public AdminControl control;
public ArrayList <KittyUser> raffleUsersUnchosen = new ArrayList<KittyUser>();
public ArrayList <KittyUser> raffleUsersChosen = new ArrayList<KittyUser>();
// Database synced info
private final String roleListName = "guildRoles";
@@ -31,8 +35,8 @@ public class KittyGuild extends DatabaseTrackedObject
private void RegisterTrackedObjects()
{
DatabaseManager.instance.Register(roleList);
DatabaseManager.instance.Register(beans);
DatabaseManager.instance.globalRegister(roleList);
DatabaseManager.instance.globalRegister(beans);
}
// Default content for a guild
@@ -88,6 +92,54 @@ public class KittyGuild extends DatabaseTrackedObject
return "Poll ended!";
}
//Raffle methods
public boolean startRaffle(int beanCost)
{
if(raffling)
{
return false;
}
raffleCost = beanCost;
raffling = true;
return true;
}
public boolean endRaffle()
{
if(raffling)
{
raffleCost = 0;
raffling = false;
raffleUsersChosen.removeAll(raffleUsersChosen);
raffleUsersUnchosen.removeAll(raffleUsersUnchosen);
return true;
}
return false;
}
public boolean joinRaffle(KittyUser user)
{
if(!raffleUsersChosen.contains(user) && !raffleUsersUnchosen.contains(user) && user.GetBeans() > raffleCost && raffling)
{
user.ChangeBeans(raffleCost);
raffleUsersUnchosen.add(user);
return true;
}
return false;
}
public KittyUser chooseRaffleWinner()
{
if(!raffleUsersUnchosen.isEmpty())
{
KittyUser chosen = raffleUsersUnchosen.get((int) (Math.random() * raffleUsersUnchosen.size()));
raffleUsersUnchosen.remove(chosen);
raffleUsersChosen.add(chosen);
return chosen;
}
return null;
}
@Override
public String Serialize()
{
+2 -4
View File
@@ -17,8 +17,7 @@ import utils.LogFilter;
//
public class KittyTrackedLong extends DatabaseTrackedObject
{
private long tracked; // Tracked value
private final String databaseID; // in-database ID of this value
private long tracked; // Tracked value
// Config
private final static String differentiator = "long-";
@@ -26,7 +25,6 @@ public class KittyTrackedLong extends DatabaseTrackedObject
public KittyTrackedLong(String readableName, String UniqueID)
{
super(differentiator + readableName + UniqueID);
databaseID = differentiator + readableName + UniqueID;
}
public long Add(long toAdd)
@@ -73,7 +71,7 @@ public class KittyTrackedLong extends DatabaseTrackedObject
catch(Exception e)
{
tracked = 0;
GlobalLog.Error(LogFilter.Core, "Falling back to default of 0 due to failure to deserialize long with database ID " + databaseID);
GlobalLog.Error(LogFilter.Core, "Falling back to default of 0 due to failure to deserialize long with database ID " + identifier);
}
}
else
@@ -0,0 +1,58 @@
package dataStructures;
import core.DatabaseTrackedObject;
import utils.GlobalLog;
import utils.LogFilter;
public class KittyTrackedString extends DatabaseTrackedObject
{
private String trackedString; // This is the string tracked in the database
private final static String differentiator = "string-"; // Lends a very slightly human-readable label to the database key
// Constructor with unique id and readable name
public KittyTrackedString(String readableName, String UniqueID)
{
super(differentiator + readableName + UniqueID);
}
// Sets the value of the string and marks it as dirty
public void set(String newValue)
{
synchronized(trackedString)
{
trackedString = newValue;
MarkDirty();
}
}
// Returns string. The string is copied because it is immutable.
public String get()
{
synchronized(trackedString)
{
return trackedString;
}
}
@Override
public String Serialize()
{
return trackedString;
}
@Override
public void DeSerialzie(String string)
{
if(string != null && !string.isEmpty())
{
trackedString = string;
}
else
{
GlobalLog.Log(LogFilter.Database, "String had null or empty value with identifier: " + identifier);
string = "";
MarkDirty();
}
}
}
+11 -15
View File
@@ -5,13 +5,10 @@ import java.util.Vector;
import core.DatabaseTrackedObject;
// Acts as a proxy of sorts for the allowedRole arraylist, keeping it tracked for a specific guild.
@SuppressWarnings("unused")
public class KittyTrackedVector extends DatabaseTrackedObject
{
// Variables
private Vector<String> allowedRole = new Vector<String>();
private final String databaseID; // in-database ID of this value
private Vector<String> trackedVector = new Vector<String>();
private final static String delimiter = "\n";
private final static String split = "\\n";
@@ -21,14 +18,13 @@ public class KittyTrackedVector extends DatabaseTrackedObject
public KittyTrackedVector(String readableName, String UniqueID)
{
super(differentiator + readableName + UniqueID);
databaseID = differentiator + readableName + UniqueID;
}
// See if the string is contined in the vector, regardless of case.
public boolean containsIgnoreCase(String str)
{
Iterator<String> value = allowedRole.iterator();
Iterator<String> value = trackedVector.iterator();
while (value.hasNext())
{
@@ -42,33 +38,33 @@ public class KittyTrackedVector extends DatabaseTrackedObject
// Mirrored behavior
public boolean contains(String str)
{
return allowedRole.contains(str);
return trackedVector.contains(str);
}
public void add(String str)
{
allowedRole.add(str);
trackedVector.add(str);
this.MarkDirty();
}
public boolean isEmpty()
{
return allowedRole.isEmpty();
return trackedVector.isEmpty();
}
public int size()
{
return allowedRole.size();
return trackedVector.size();
}
public String get(int index)
{
return allowedRole.get(index);
return trackedVector.get(index);
}
public void remove(String str)
{
allowedRole.remove(str);
trackedVector.remove(str);
this.MarkDirty();
}
@@ -78,12 +74,12 @@ public class KittyTrackedVector extends DatabaseTrackedObject
{
String toSerialize = "";
for(int i = 0; i < allowedRole.size(); ++i)
for(int i = 0; i < trackedVector.size(); ++i)
{
if(i != 0)
toSerialize += delimiter;
toSerialize += allowedRole.get(i);
toSerialize += trackedVector.get(i);
}
return toSerialize;
@@ -100,7 +96,7 @@ public class KittyTrackedVector extends DatabaseTrackedObject
String[] rolesSplit = string.split(split);
for(int i = 0; i < rolesSplit.length; ++i)
allowedRole.add(rolesSplit[i]);
trackedVector.add(rolesSplit[i]);
}
}
}
+7 -7
View File
@@ -9,13 +9,13 @@ import utils.LogFilter;
// two unique user objects associated with them.
public class KittyUser extends DatabaseTrackedObject
{
public KittyGuild guild;
public String name;
public String uniqueID;
public String discordID;
public String avatarID;
private KittyRole role;
private long beans;
public KittyGuild guild; // The guild this user is associated with. A KittyUser can not be associated with more than one guild.
public String name; // The 'friendly name' of the user (readable name).
public String uniqueID; // The combination of the guild ID that discord uses and the user-specific ID discord uses. (A discord account has one user per server).
public String discordID; // The user-specific ID only. This is the ID associated with the discord account.
public String avatarID; // The searchable ID of the current avatar image for the user.
private KittyRole role; // The command permissions role this user has for issuing bot commands for this bot.
private long beans; // A value incremented each time a user sends a message in a server they're in.
// Explicit Constructor
public KittyUser(String name, KittyGuild guild, KittyRole role, String uniqueID, String avatarID, String discordID)
+9
View File
@@ -60,6 +60,15 @@ public class UserInput
isValid = false;
}
}
//Used for injecting direct commands from plugins
public UserInput(String input, KittyGuild contextGuild)
{
int loc = FindFirstWhitespace(input);
key = input.substring(0, loc);
args = input.substring(loc);
isValid = true;
}
public boolean IsValid()
{
+10 -1
View File
@@ -92,7 +92,16 @@ public class Main extends ListenerAdapter
if(pluginOutput != null && pluginOutput.size() > 0)
{
for(int i = 0; i < pluginOutput.size(); ++i)
response.Call(pluginOutput.get(i));
{
if(pluginOutput.get(i).startsWith("!"))
{
commandManager.InvokeOnNewThread(guild, channel, user, new UserInput(pluginOutput.get(i).substring(1), guild), response);
}
else
{
response.Call(pluginOutput.get(i));
}
}
}
}
+1 -1
View File
@@ -92,7 +92,7 @@ public class Superintendent
// Upkeep database lazily on occasion
if(delayTimerCurrent.decrementAndGet() < 0)
{
databaseManager.Upkeep();
databaseManager.upkeep();
delayTimerCurrent.set(delayTimerReset);
}
+30 -21
View File
@@ -13,34 +13,41 @@ import utils.LogFilter;
// Only to be called by the generic driver.
public class JDBCDriverSQLite extends JDBCDriver
{
Connection connection = null;
String databaseFolder = "db/";
String databaseName = "catfood";
private static Connection connection = null;
public static final String databaseFolder = "db/";
public static final String databaseName = "catfood";
@Override
public boolean Connect()
{
try
{
if(connection == null)
{
{ // Scope to discard file...
File f = new File(databaseFolder);
if(!f.exists() || !f.isDirectory())
{
f.mkdir();
try
{
{ // Scope to discard file...
File f = new File(databaseFolder);
if(!f.exists() || !f.isDirectory())
{
f.mkdir();
}
}
// db parameters
String url = "jdbc:sqlite:" + databaseFolder + databaseName + ".db";
// create a connection to the database
connection = DriverManager.getConnection(url);
GlobalLog.Log(LogFilter.Database, "Connection to SQLite has been established.");
}
catch (SQLException e)
{
GlobalLog.Error(e.getMessage());
}
// db parameters
String url = "jdbc:sqlite:db/" + databaseName + ".db";
// create a connection to the database
connection = DriverManager.getConnection(url);
GlobalLog.Log(LogFilter.Database, "Connection to SQLite has been established.");
}
catch (SQLException e)
}
else
{
GlobalLog.Error(e.getMessage());
GlobalLog.Log(LogFilter.Database, "SQLite database asked to connect a second time. This is perfectly fine as this app has all its data tied together.");
}
return connection != null;
@@ -52,7 +59,9 @@ public class JDBCDriverSQLite extends JDBCDriver
try
{
if (connection != null)
{
connection.close();
}
return true;
}