diff --git a/assets/teey/frames/teey 0.png b/assets/teey/frames/teey 0.png new file mode 100644 index 0000000..571a7b7 Binary files /dev/null and b/assets/teey/frames/teey 0.png differ diff --git a/assets/teey/frames/teey 1.png b/assets/teey/frames/teey 1.png new file mode 100644 index 0000000..c2ebcae Binary files /dev/null and b/assets/teey/frames/teey 1.png differ diff --git a/assets/teey/frames/teey 10.png b/assets/teey/frames/teey 10.png new file mode 100644 index 0000000..6d1ef61 Binary files /dev/null and b/assets/teey/frames/teey 10.png differ diff --git a/assets/teey/frames/teey 11.png b/assets/teey/frames/teey 11.png new file mode 100644 index 0000000..205094c Binary files /dev/null and b/assets/teey/frames/teey 11.png differ diff --git a/assets/teey/frames/teey 12.png b/assets/teey/frames/teey 12.png new file mode 100644 index 0000000..ff584a5 Binary files /dev/null and b/assets/teey/frames/teey 12.png differ diff --git a/assets/teey/frames/teey 13.png b/assets/teey/frames/teey 13.png new file mode 100644 index 0000000..d5d540b Binary files /dev/null and b/assets/teey/frames/teey 13.png differ diff --git a/assets/teey/frames/teey 14.png b/assets/teey/frames/teey 14.png new file mode 100644 index 0000000..911e2ce Binary files /dev/null and b/assets/teey/frames/teey 14.png differ diff --git a/assets/teey/frames/teey 15.png b/assets/teey/frames/teey 15.png new file mode 100644 index 0000000..68a0c93 Binary files /dev/null and b/assets/teey/frames/teey 15.png differ diff --git a/assets/teey/frames/teey 16.png b/assets/teey/frames/teey 16.png new file mode 100644 index 0000000..9cfe7c1 Binary files /dev/null and b/assets/teey/frames/teey 16.png differ diff --git a/assets/teey/frames/teey 17.png b/assets/teey/frames/teey 17.png new file mode 100644 index 0000000..0959b54 Binary files /dev/null and b/assets/teey/frames/teey 17.png differ diff --git a/assets/teey/frames/teey 18.png b/assets/teey/frames/teey 18.png new file mode 100644 index 0000000..febf7f7 Binary files /dev/null and b/assets/teey/frames/teey 18.png differ diff --git a/assets/teey/frames/teey 19.png b/assets/teey/frames/teey 19.png new file mode 100644 index 0000000..d1eaa98 Binary files /dev/null and b/assets/teey/frames/teey 19.png differ diff --git a/assets/teey/frames/teey 2.png b/assets/teey/frames/teey 2.png new file mode 100644 index 0000000..d3146fd Binary files /dev/null and b/assets/teey/frames/teey 2.png differ diff --git a/assets/teey/frames/teey 20.png b/assets/teey/frames/teey 20.png new file mode 100644 index 0000000..b6c4089 Binary files /dev/null and b/assets/teey/frames/teey 20.png differ diff --git a/assets/teey/frames/teey 21.png b/assets/teey/frames/teey 21.png new file mode 100644 index 0000000..e89dc8d Binary files /dev/null and b/assets/teey/frames/teey 21.png differ diff --git a/assets/teey/frames/teey 22.png b/assets/teey/frames/teey 22.png new file mode 100644 index 0000000..ca4ce04 Binary files /dev/null and b/assets/teey/frames/teey 22.png differ diff --git a/assets/teey/frames/teey 23.png b/assets/teey/frames/teey 23.png new file mode 100644 index 0000000..4646793 Binary files /dev/null and b/assets/teey/frames/teey 23.png differ diff --git a/assets/teey/frames/teey 3.png b/assets/teey/frames/teey 3.png new file mode 100644 index 0000000..2a21759 Binary files /dev/null and b/assets/teey/frames/teey 3.png differ diff --git a/assets/teey/frames/teey 4.png b/assets/teey/frames/teey 4.png new file mode 100644 index 0000000..657b6bc Binary files /dev/null and b/assets/teey/frames/teey 4.png differ diff --git a/assets/teey/frames/teey 5.png b/assets/teey/frames/teey 5.png new file mode 100644 index 0000000..3a19846 Binary files /dev/null and b/assets/teey/frames/teey 5.png differ diff --git a/assets/teey/frames/teey 6.png b/assets/teey/frames/teey 6.png new file mode 100644 index 0000000..8997f49 Binary files /dev/null and b/assets/teey/frames/teey 6.png differ diff --git a/assets/teey/frames/teey 7.png b/assets/teey/frames/teey 7.png new file mode 100644 index 0000000..683d00a Binary files /dev/null and b/assets/teey/frames/teey 7.png differ diff --git a/assets/teey/frames/teey 8.png b/assets/teey/frames/teey 8.png new file mode 100644 index 0000000..b51c7e2 Binary files /dev/null and b/assets/teey/frames/teey 8.png differ diff --git a/assets/teey/frames/teey 9.png b/assets/teey/frames/teey 9.png new file mode 100644 index 0000000..e69440e Binary files /dev/null and b/assets/teey/frames/teey 9.png differ diff --git a/commands.config b/commands.config new file mode 100644 index 0000000..4d9a56c --- /dev/null +++ b/commands.config @@ -0,0 +1,35 @@ +indicator=1 +boop=1 +tony, stark, dontfeelgood, dontfeelsogood=1 +yeet=1 +role=1 +ping=1 +rating=1 +roll=1 +blur=1 +choose=1 +poll=1 +rpstart=1 +bet=1 +perish, thenperish=1 +teey=1 +stats=1 +beans=1 +eightball, 8ball=1 +vote=1 +results=1 +wolfram=1 +map=1 +info, about=1 +givebeans=1 +c++, g++, cplus, cpp=1 +work=1 +showpoll=1 +rpend=1 +rpg=1 +tweet=1 +java, jdoodle=1 +help=1 +buildHelp=1 +invite=1 +shutdown=1 diff --git a/locCommands.config b/locCommands.config new file mode 100644 index 0000000..f60a1b9 --- /dev/null +++ b/locCommands.config @@ -0,0 +1,38 @@ +[ObjectBuilderFactory] +indicator= +boop= +tony, stark, dontfeelgood, dontfeelsogood= +yeet= +role= +ping= +rating= +roll= +blur= +choose= +poll= +rpstart= +bet= +perish, thenperish= +teey= +stats= +beans= +eightball, 8ball= +vote= +results= +wolfram= +map= +info, about= +givebeans= +c++, g++, cplus, cpp= +work= +showpoll= +rpend= +rpg= +tweet= +java, jdoodle= +help= +buildHelp= +invite= +shutdown= + + diff --git a/locStrings.config b/locStrings.config new file mode 100644 index 0000000..d0ce6f8 --- /dev/null +++ b/locStrings.config @@ -0,0 +1,177 @@ +[CommandPollManage] +PollManageInfo='start' will start a new poll with the query of the line you put after, 'choice' will add a choice to the poll, 'stop' will end the poll + +[CommandBeansShow] +BeansShowDisplay=You have %s beans! +BeansShowInfo=Displays how many beans you have + +[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 + +[CommandStats] +StatsInfo=Displays the actively running KittyBot application information + +[CommandTweet] +TweetInfo=Kitty will tweet to her personal twitter account +TweetError=Tweet command failed! + +[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 +RoleError=You aren't allowed to do that! You must have the KittyRole '%' or higher! +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! + +[CommandChangeIndicator] +ChangeIndicatorInfo=Changes the command indicator to any single character. By default, it's '!'. If more than one character is provided, the first one is used! +ChangeIndicatorError=Please specify a letter or symbol to use! +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 @! + +[CommandPollVote] +PollVoteNotValidNumber=That's not a vaild number! +PollVoteInfo=Vote in a poll with the choice number, won't work if no poll is running, you can't change your vote once you have cast it! Be careful! +PollVoteNoPoll=There is no poll running! +PollVoteAlreadyVoted=You already voted +PollVoteNotValidVote=%s That's not a vaild vote! +PollVoteSuccess=You successfully voted for + +[CommandShutdown] +ShutdownInfo=Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown. + +[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! + +[CommandDoWork] +DoWorkFinished=I finished with my work! :D +DoWorkInfo=Occupies a core for a few seconds + +[CommandRPStart] +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! +RatingChanged=Kittybot content set to +RatingInvalid=Invalid content rating + +[CommandGiveBeans] +GiveBeansNoneMentioned=You didn't mention anyone! +GiveBeansSuccess=Gave %s %s beans! +GiveBeansInvalid=That's not a valid number! +GiveBeansInfo=Gives beans to the mentioned users! + +[CommandPollShow] +PollShowNoPoll=There is no poll running! +PollShowInfo=Will show the current poll running +PollShowPoll=The current poll is `%s`\n +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 +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! + +[CommandInfo] +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 + +[CommandPing] +PingResponse=Pong! +PingInfo=Will respond with Pong! + +[CommandChoose] +ChooseChoice=I chooooooose %s! +ChooseOne=I can't choose from *one* thing! +ChooseInfo=With an input of x,y,z where x y and z are all choices, kitty will choose one + +[CommandEightBall] +EightBallYes4=Yes - definitely. +EightBallYes3=Without a doubt. +EightBallYes2=It is decidedly so. +EightBallYes1=It is certain. +EightBallYes8=Outlook good. +EightBallYes7=Most likely. +EightBallYes6=As I see it, yes. +EightBallYes5=You may rely on it. +EightBallMaybe1=Reply hazy, try again. +EightBallMaybe2=Ask again later. +EightBallError=Hmm? You'll need to ask a question! +EightBallMaybe3=Better not tell you now. +EightBallMaybe4=Cannot predict now. +EightBallMaybe5=Concentrate and ask again. +EightBallInfo=Answers a yes or no question! Warning: Kitty can not actually tell the future, she claims no responsibility for any lion mauling, lack of lottery wins, or felony charges. +EightBallNo5=Very doubtful. +EightBallNo3=My sources say no. +EightBallNo4=Outlook not so good. +EightBallNo1=Don't count on it. +EightBallNo2=My reply is no. +EightBallYes9=Yes. +EightBallYes10=Signs point to yes. + +[CommandInvite] +InviteInfo=Provides a direct invite link for KittyBot + +[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-w-h`. 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 + + diff --git a/localization.config b/localization.config deleted file mode 100644 index 8970ef7..0000000 --- a/localization.config +++ /dev/null @@ -1,173 +0,0 @@ -[CommandPollManage] -'start' will start a new poll with the query of the line you put after, 'choice' will add a choice to the poll, 'stop' will end the poll= - -[CommandBeansShow] -You have %s beans!= -Displays how many beans you have= - -[CommandHelp] -Lets you look up specific commands, or get a link to a list of all commands.= -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] -Didn't work ;3;= -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= - -[CommandStats] -Displays the actively running KittyBot application information= - -[CommandTweet] -With an input of x,y,z where x y and z are all choices, kitty will choose one= -Tweet command failed!= - -[CommandRole] -Please enter `general`, `mod`, or `admin`!= -You aren't allowed to do that! You must have the KittyRole '%' or higher!= -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.= -Your role is= -Changed %s to role `%s`!= - -[CommandColiru] -Please provide some c++ code to attempt to compile!= -Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++.= - -[CommandJDoodle] -Please provide some java code to get it compiled!= -Will compile any java code you put in! Supports Java 1.8= - -[CommandChangeIndicator] -Changes the command indicator to any single character. By default, it's '!'. If more than one character is provided, the first one is used!= -Indicator changed to `%s`= - -[CommandPerish] -Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned= - -[CommandStark] -Snaps your icon or the icon of a friend you mentioned= - -[CommandYeet] -Yeet yourself or yeet a friend with @!= - -[CommandPollVote] -There is no poll running!= -%s That's not a vaild vote!= -That's not a vaild number!= -Vote in a poll with the choice number, won't work if no poll is running, you can't change your vote once you have cast it! Be careful!= -You already voted!= -You successfully voted for= - -[CommandShutdown] -Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown.= -Forced shutdown, database synced before abandoning threads.= -Forced immediate shutdown, threads abandoned without sync.= - -[CommandBetBeans] -That's not a valid bet!= -Please bet with at least 50 beans!= -Allows you to bet your beans, set your amount after the command! Warning! House always wins!\nSets of 3 will get 5x, 4 will get 10x, and 5 will get 1000x= -Sorry, you didn't win, try again!= -You don't have enough beans!= -You won %s beans!= - -[CommandDoWork] -I finished with my work! :D= -Occupies a core for a few seconds= - -[CommandRPStart] -Starts an rp, add people to it by mentioning them!= - -[CommandBlurry] -Blurs your icon or the icon of a friend you mentioned= - -[CommandPollResults] -Will show current results of a poll and percentages of votes per choice= -%s people voted for %s `%s` with `%s%` !\n = - -[CommandRating] -Kittybot content set to= -Warning: NSFW may slip through, images are only based on tags on their respective sites!= -Invalid content rating= - -[CommandGiveBeans] -That's not a valid number!= -Gave %s %s beans!= -Gives beans to the mentioned users!= -You didn't mention anyone!= - -[CommandPollShow] -There is no poll running!= -And the choices are:\n= -Will show the current poll running= -The current poll is `%s`\n= - -[CommandHelpBuilder] -Emit help for all commands as formatted HTML= -commands= - -[CommandRPEnd] -Here's your file!= -You can't end this RP!= -Ends RP in channel= - -[CommandRPG] -Invalid RPG Command!= -Admin+ command only right now - experimental text RPG! Format is !rpg = - -[CommandBoop] -%s booped %s!= -Kitty will react with a counter= -Woah! %s booped me! That's %s total!= -%s booped several others - %s!= - -[CommandInfo] -I'm a Java application written with JDA! Check out my repo at = -Provides some extra info about KittyBot= - -[CommandPing] -Pong!= -Will respond with Pong!= - -[CommandChoose] -With an input of x,y,z where x y and z are all choices, kitty will choose one= -I chooooooose %s!= - -[CommandEightBall] -It is certain.= -Ask again later.= -Cannot predict now.= -My sources say no.= -You may rely on it.= -Answers a yes or no question! Warning: Kitty can not actually tell the future, she claims no responsibility for any lion mauling, lack of lottery wins, or felony charges.= -Concentrate and ask again.= -Signs point to yes.= -Don't count on it.= -Yes.= -Hmm? You'll need to ask a question!= -My reply is no.= -Most likely.= -Reply hazy, try again.= -Without a doubt.= -Yes - definitely.= -Very doubtful.= -As I see it, yes.= -Better not tell you now.= -Outlook good.= -Outlook not so good.= -It is decidedly so.= - -[CommandInvite] -Provies a direct invite link for KittyBot= - -[CommandWolfram] -Something went wrong!= -Will query wolframalpha with your question and give a full image output of the answer= -You need to provide some arguments!= - -[CommandMap] -Seed= -Invalid arguments provided!= -Height= -Using mapgen v0.1= -Width= - - diff --git a/src/commands/CommandBeansShow.java b/src/commands/CommandBeansShow.java index e832ddb..16d3f62 100644 --- a/src/commands/CommandBeansShow.java +++ b/src/commands/CommandBeansShow.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; public class CommandBeansShow extends Command @@ -9,11 +9,11 @@ public class CommandBeansShow extends Command public CommandBeansShow(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Displays how many beans you have"); }; + public String HelpText() { return LocStrings.Stub("BeansShowInfo"); }; @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { - res.Call(String.format(Localizer.Stub("You have %s beans!"), user.GetBeans())); + res.Call(String.format(LocStrings.Stub("BeansShowDisplay"), user.GetBeans())); } } diff --git a/src/commands/CommandBetBeans.java b/src/commands/CommandBetBeans.java index 2019ee0..06df15a 100644 --- a/src/commands/CommandBetBeans.java +++ b/src/commands/CommandBetBeans.java @@ -1,7 +1,9 @@ package commands; +import java.util.Random; + import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; public class CommandBetBeans extends Command @@ -9,7 +11,7 @@ public class CommandBetBeans extends Command public CommandBetBeans(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Allows you to bet your beans, set your amount after the command! Warning! House always wins!\nSets of 3 will get 5x, 4 will get 10x, and 5 will get 1000x"); } + public String HelpText() { return LocStrings.Stub("BetBeansInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -22,19 +24,19 @@ public class CommandBetBeans extends Command bet = Integer.parseInt(input.args); if(bet < 50) { - res.Call(Localizer.Stub("Please bet with at least 50 beans!")); + res.Call(LocStrings.Stub("BetBeansLowBet")); return; } } catch (NumberFormatException e) { - res.Call(Localizer.Stub("That's not a valid bet!")); + res.Call(LocStrings.Stub("BetBeansNotValid")); return; } if(user.GetBeans() < bet) { - res.Call(Localizer.Stub("You don't have enough beans!")); + res.Call(LocStrings.Stub("BetBeansNotEnough")); return; } @@ -49,12 +51,12 @@ public class CommandBetBeans extends Command if(win == 0) { - res.Call(Localizer.Stub("Sorry, you didn't win, try again!")); + res.Call(LocStrings.Stub("BetBeansLose")); return; } user.ChangeBeans(bet*win); - res.Call(String.format(Localizer.Stub("You won %s beans!"), "" + (bet*win))); + res.Call(String.format(LocStrings.Stub("BetBeansWin"), "" + (bet*win))); } private int getWinning(int [] slots) @@ -69,7 +71,7 @@ public class CommandBetBeans extends Command counter = 1; if(counter == 3) - winning = 5; + winning = 2; if(counter == 4) winning = 10; @@ -83,10 +85,12 @@ public class CommandBetBeans extends Command private int[] getSlots() { + Random gen = new Random(); int[] nums = new int[5]; for (int i = 0; i < nums.length; i++) { - nums[i] = (int) (Math.random() * 5) + 1; + nums[i] = Math.abs(gen.nextInt() % 7) + 1; + System.out.println(nums [i]); } return nums; } @@ -138,6 +142,12 @@ public class CommandBetBeans extends Command case 5: slotHearts += ":purple_heart:"; break; + case 6: + slotHearts += ":black_heart:"; + break; + case 7: + slotHearts += ":broken_heart:"; + break; } } diff --git a/src/commands/CommandBlurry.java b/src/commands/CommandBlurry.java index 5bb6ef5..c875ff2 100644 --- a/src/commands/CommandBlurry.java +++ b/src/commands/CommandBlurry.java @@ -8,7 +8,7 @@ import java.io.IOException; import javax.imageio.ImageIO; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; import utils.ImageUtils; @@ -17,7 +17,7 @@ public class CommandBlurry extends Command public CommandBlurry(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Blurs your icon or the icon of a friend you mentioned"); }; + public String HelpText() { return LocStrings.Stub("BlurryInfo"); }; private static Long num = 0l; diff --git a/src/commands/CommandBoop.java b/src/commands/CommandBoop.java index df81882..ccd0a41 100644 --- a/src/commands/CommandBoop.java +++ b/src/commands/CommandBoop.java @@ -60,7 +60,7 @@ public class CommandBoop extends Command } @Override - public String HelpText() { return Localizer.Stub("Kitty will react with a counter"); } + public String HelpText() { return LocStrings.Stub("BoopInfo"); } // Called when the command is run! @Override @@ -69,14 +69,14 @@ public class CommandBoop extends Command if(input.mentions == null) { boopTracker.ApplyBoop(); - res.Call(String.format(Localizer.Stub("Woah! %s booped me! That's %s total!"), user.name, boopTracker.HowMany())); + res.Call(String.format(LocStrings.Stub("BoopStandard"), user.name, boopTracker.HowMany())); } else { if(input.mentions.length == 1) { boopTracker.ApplyBoop(); - res.Call(String.format(Localizer.Stub("%s booped %s!"), user.name, input.mentions[0].name)); + res.Call(String.format(LocStrings.Stub("BoopPerson"), user.name, input.mentions[0].name)); return; } @@ -90,7 +90,7 @@ public class CommandBoop extends Command booped += "and " + input.mentions[i].name; } - res.Call(String.format(Localizer.Stub("%s booped several others - %s!"), user.name, booped)); + res.Call(String.format(LocStrings.Stub("BoopMultiple"), user.name, booped)); } } } \ No newline at end of file diff --git a/src/commands/CommandChangeIndicator.java b/src/commands/CommandChangeIndicator.java index da25d8d..babdc4d 100644 --- a/src/commands/CommandChangeIndicator.java +++ b/src/commands/CommandChangeIndicator.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; public class CommandChangeIndicator extends Command @@ -9,7 +9,7 @@ public class CommandChangeIndicator extends Command public CommandChangeIndicator(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Changes the command indicator to any single character. By default, it's '!'. If more than one character is provided, the first one is used!"); } + public String HelpText() { return LocStrings.Stub("ChangeIndicatorInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -17,11 +17,11 @@ public class CommandChangeIndicator extends Command String arg = input.args.trim(); if(arg.length() == 0) { - res.Call("Please specify a letter or symbol to use!"); + res.Call(LocStrings.Stub("ChangeIndicatorError")); return; } guild.SetCommandIndicator(arg.substring(0, 1)); - res.Call(String.format(Localizer.Stub("Indicator changed to `%s`"), guild.GetCommandIndicator())); + res.Call(String.format(LocStrings.Stub("ChangeIndicatorChanged"), guild.GetCommandIndicator())); } } diff --git a/src/commands/CommandChoose.java b/src/commands/CommandChoose.java index 842e341..e68f783 100644 --- a/src/commands/CommandChoose.java +++ b/src/commands/CommandChoose.java @@ -14,7 +14,7 @@ public class CommandChoose extends Command public CommandChoose(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("With an input of x,y,z where x y and z are all choices, kitty will choose one"); } + public String HelpText() { return LocStrings.Stub("ChooseInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -22,10 +22,10 @@ public class CommandChoose extends Command String [] choices = input.args.split(","); if(choices.length == 1) { - res.Call("I can't choose from *one* thing!"); + res.Call(LocStrings.Stub("ChooseOne")); return; } - res.Call(String.format(Localizer.Stub("I chooooooose %s!"), (choices[(int) (Math.random()*choices.length)]).toString())); + res.Call(String.format(LocStrings.Stub("ChooseChoice"), (choices[(int) (Math.random()*choices.length)]).toString())); } } diff --git a/src/commands/CommandColiru.java b/src/commands/CommandColiru.java index 047f5cc..b2f5f8e 100644 --- a/src/commands/CommandColiru.java +++ b/src/commands/CommandColiru.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; import network.NetworkColiru; @@ -12,14 +12,14 @@ public class CommandColiru extends Command public CommandColiru(KittyRole level, KittyRating rating) { super(level, rating);} @Override - public String HelpText() { return Localizer.Stub("Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++."); } + public String HelpText() { return LocStrings.Stub("ColiruInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { if(input.args.trim().length() < 1) { - res.Call(Localizer.Stub("Please provide some c++ code to attempt to compile!")); + res.Call(LocStrings.Stub("ColiruError")); return; } diff --git a/src/commands/CommandDoWork.java b/src/commands/CommandDoWork.java index b1466e3..c37f85f 100644 --- a/src/commands/CommandDoWork.java +++ b/src/commands/CommandDoWork.java @@ -15,7 +15,7 @@ public class CommandDoWork extends Command public CommandDoWork(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Occupies a core for a few seconds"); } + public String HelpText() { return LocStrings.Stub("DoWorkInfo"); } // Called when the command is run! @Override @@ -28,6 +28,6 @@ public class CommandDoWork extends Command thispieceofshit += Math.log((double)i); } - res.Call(Localizer.Stub("I finished with my work! :D")); + res.Call(LocStrings.Stub("DoWorkFinished")); } } \ No newline at end of file diff --git a/src/commands/CommandEightBall.java b/src/commands/CommandEightBall.java index 81dd865..2e90413 100644 --- a/src/commands/CommandEightBall.java +++ b/src/commands/CommandEightBall.java @@ -1,47 +1,47 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; public class CommandEightBall extends Command { String [] answers = { - Localizer.Stub("It is certain.") - , Localizer.Stub("It is decidedly so.") - , Localizer.Stub("Without a doubt.") - , Localizer.Stub("Yes - definitely.") - , Localizer.Stub("You may rely on it.") - , Localizer.Stub("As I see it, yes.") - , Localizer.Stub("Most likely.") - , Localizer.Stub("Outlook good.") - , Localizer.Stub("Yes.") - , Localizer.Stub("Signs point to yes.") + LocStrings.Stub("EightBallYes1") + , LocStrings.Stub("EightBallYes2") + , LocStrings.Stub("EightBallYes3") + , LocStrings.Stub("EightBallYes4") + , LocStrings.Stub("EightBallYes5") + , LocStrings.Stub("EightBallYes6") + , LocStrings.Stub("EightBallYes7") + , LocStrings.Stub("EightBallYes8") + , LocStrings.Stub("EightBallYes9") + , LocStrings.Stub("EightBallYes10") - , Localizer.Stub("Reply hazy, try again.") - , Localizer.Stub("Ask again later.") - , Localizer.Stub("Better not tell you now.") - , Localizer.Stub("Cannot predict now.") - , Localizer.Stub("Concentrate and ask again.") + , LocStrings.Stub("EightBallMaybe1") + , LocStrings.Stub("EightBallMaybe2") + , LocStrings.Stub("EightBallMaybe3") + , LocStrings.Stub("EightBallMaybe4") + , LocStrings.Stub("EightBallMaybe5") - , Localizer.Stub("Don't count on it.") - , Localizer.Stub("My reply is no.") - , Localizer.Stub("My sources say no.") - , Localizer.Stub("Outlook not so good.") - , Localizer.Stub("Very doubtful.") + , LocStrings.Stub("EightBallNo1") + , LocStrings.Stub("EightBallNo2") + , LocStrings.Stub("EightBallNo3") + , LocStrings.Stub("EightBallNo4") + , LocStrings.Stub("EightBallNo5") }; public CommandEightBall(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Answers a yes or no question! Warning: Kitty can not actually tell the future, she claims no responsibility for any lion mauling, lack of lottery wins, or felony charges."); } + public String HelpText() { return LocStrings.Stub("EightBallInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { if(input.args.trim().length() < 1) - res.Call(Localizer.Stub("Hmm? You'll need to ask a question!")); + res.Call(LocStrings.Stub("EightBallError")); res.Call(answers[(int) (Math.random()*answers.length)]); } diff --git a/src/commands/CommandGiveBeans.java b/src/commands/CommandGiveBeans.java index e22cc28..a1469e9 100644 --- a/src/commands/CommandGiveBeans.java +++ b/src/commands/CommandGiveBeans.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; public class CommandGiveBeans extends Command @@ -9,7 +9,7 @@ public class CommandGiveBeans extends Command public CommandGiveBeans (KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Gives beans to the mentioned users!"); } + public String HelpText() { return LocStrings.Stub("GiveBeansInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -20,20 +20,20 @@ public class CommandGiveBeans extends Command } catch (NumberFormatException e) { - res.Call(Localizer.Stub("That's not a valid number!")); + res.Call(LocStrings.Stub("GiveBeansInvalid")); return; } if(input.mentions == null) { - res.Call(Localizer.Stub("You didn't mention anyone!")); + res.Call(LocStrings.Stub("GiveBeansNoneMentioned")); return; } for(int i = 0; i < input.mentions.length; i++) { input.mentions[i].ChangeBeans(beans); - res.Call(String.format(Localizer.Stub("Gave %s %s beans!"), input.mentions[i].name, "" + beans)); + res.Call(String.format(LocStrings.Stub("GiveBeansSuccess"), input.mentions[i].name, "" + beans)); } } } diff --git a/src/commands/CommandHelp.java b/src/commands/CommandHelp.java index 0621b26..fd5bd0f 100644 --- a/src/commands/CommandHelp.java +++ b/src/commands/CommandHelp.java @@ -15,7 +15,7 @@ public class CommandHelp extends Command public CommandHelp(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Lets you look up specific commands, or get a link to a list of all commands."); } + public String HelpText() { return LocStrings.Stub("HelpInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -24,7 +24,7 @@ public class CommandHelp extends Command if(help == null) { - help = Localizer.Stub("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`"); + help = LocStrings.Stub("HelpDisplay"); } else { diff --git a/src/commands/CommandHelpBuilder.java b/src/commands/CommandHelpBuilder.java index 9b77b55..89ef69b 100644 --- a/src/commands/CommandHelpBuilder.java +++ b/src/commands/CommandHelpBuilder.java @@ -7,7 +7,7 @@ import java.util.ArrayList; import java.util.HashMap; import core.Command; -import core.Localizer; +import core.LocStrings; import core.Stats; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -26,7 +26,7 @@ public class CommandHelpBuilder extends Command { } @Override - public String HelpText() { return Localizer.Stub("Emit help for all commands as formatted HTML"); } + public String HelpText() { return LocStrings.Stub("HelpBuilderInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -96,7 +96,7 @@ public class CommandHelpBuilder extends Command { roleStr = roleStr.substring(0, 1).toUpperCase() + roleStr.toLowerCase().substring(1); // Section header - accumulated += headerStart + roleStr + " " + Localizer.Stub("commands") + headerEnd; + accumulated += headerStart + roleStr + " commands" + headerEnd; accumulated += sectionStart; // Section content diff --git a/src/commands/CommandInfo.java b/src/commands/CommandInfo.java index 0de7bc5..7fee7bf 100644 --- a/src/commands/CommandInfo.java +++ b/src/commands/CommandInfo.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -15,11 +15,11 @@ public class CommandInfo extends Command public CommandInfo(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Provides some extra info about KittyBot"); } + public String HelpText() { return LocStrings.Stub("InfoInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { - res.Call(Localizer.Stub("I'm a Java application written with JDA! Check out my repo at ")); + res.Call(LocStrings.Stub("InfoResponse")); } } \ No newline at end of file diff --git a/src/commands/CommandInvite.java b/src/commands/CommandInvite.java index 75080e4..d74dda5 100644 --- a/src/commands/CommandInvite.java +++ b/src/commands/CommandInvite.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; import offline.Ref; @@ -10,7 +10,7 @@ public class CommandInvite extends Command public CommandInvite(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Provies a direct invite link for KittyBot"); } + public String HelpText() { return LocStrings.Stub("InviteInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) diff --git a/src/commands/CommandJDoodle.java b/src/commands/CommandJDoodle.java index 0873c7f..ae244e4 100644 --- a/src/commands/CommandJDoodle.java +++ b/src/commands/CommandJDoodle.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; import network.NetworkJDoodle; @@ -12,14 +12,14 @@ public class CommandJDoodle extends Command public CommandJDoodle(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Will compile any java code you put in! Supports Java 1.8"); } + public String HelpText() { return LocStrings.Stub("JDoodleInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { if(input.args.trim().length() < 1) { - res.Call(Localizer.Stub("Please provide some java code to get it compiled!")); + res.Call(LocStrings.Stub("JDoodleError")); return; } diff --git a/src/commands/CommandMap.java b/src/commands/CommandMap.java index 02aca37..803b93b 100644 --- a/src/commands/CommandMap.java +++ b/src/commands/CommandMap.java @@ -3,7 +3,7 @@ package commands; import java.util.Random; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -23,7 +23,7 @@ public class CommandMap extends Command public CommandMap(KittyRole roleLevel, KittyRating contentRating) { super(roleLevel, contentRating); } @Override - public String HelpText() { return String.format(Localizer.Stub("Generates a map! You can pass additional information if you want with the flags `-s -w -h`. 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)"), "" + MaxWidth, "" + MaxHeight); } + public String HelpText() { return String.format(LocStrings.Stub("MapInfo"), "" + MaxWidth, "" + MaxHeight); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -60,7 +60,7 @@ public class CommandMap extends Command } catch(NumberFormatException e) { - res.Call(Localizer.Stub("Invalid arguments provided!")); + res.Call(LocStrings.Stub("MapInvalid")); return; } @@ -76,10 +76,10 @@ public class CommandMap extends Command } // Response header creation - header += Localizer.Stub("Using mapgen v0.1") + "\n"; - header += Localizer.Stub("Seed") + ": `" + seed + "`, "; - header += Localizer.Stub("Width") + "`"+ width +"`, "; - header += Localizer.Stub("Height") + ": `"+ height + "`\n"; + header += LocStrings.Stub("MapVersion") + "\n"; + header += LocStrings.Stub("MapSeed") + ": `" + seed + "`, "; + header += LocStrings.Stub("MapWidth") + "`"+ width +"`, "; + header += LocStrings.Stub("MapHeight") + ": `"+ height + "`\n"; // Response body creation body += "```\n"; diff --git a/src/commands/CommandPerish.java b/src/commands/CommandPerish.java index b51080e..73ca6e6 100644 --- a/src/commands/CommandPerish.java +++ b/src/commands/CommandPerish.java @@ -8,7 +8,7 @@ import java.io.IOException; import javax.imageio.ImageIO; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -23,7 +23,7 @@ public class CommandPerish extends Command public CommandPerish(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned"); }; + public String HelpText() { return LocStrings.Stub("PerishInfo"); }; private static Long num = 0l; diff --git a/src/commands/CommandPing.java b/src/commands/CommandPing.java index 51b6212..7de6205 100644 --- a/src/commands/CommandPing.java +++ b/src/commands/CommandPing.java @@ -15,12 +15,12 @@ public class CommandPing extends Command public CommandPing(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Will respond with Pong!"); } + public String HelpText() { return LocStrings.Stub("PingInfo"); } // Called when the command is run! @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { - res.Call(Localizer.Stub("Pong!")); + res.Call(LocStrings.Stub("PingResponse")); } } diff --git a/src/commands/CommandPollManage.java b/src/commands/CommandPollManage.java index a1d9976..1a0114d 100644 --- a/src/commands/CommandPollManage.java +++ b/src/commands/CommandPollManage.java @@ -14,7 +14,7 @@ public class CommandPollManage extends Command public CommandPollManage(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("'start' will start a new poll with the query of the line you put after, 'choice' will add a choice to the poll, 'stop' will end the poll"); } + public String HelpText() { return LocStrings.Stub("PollManageInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) diff --git a/src/commands/CommandPollResults.java b/src/commands/CommandPollResults.java index 3312009..ac36aff 100644 --- a/src/commands/CommandPollResults.java +++ b/src/commands/CommandPollResults.java @@ -10,7 +10,7 @@ public class CommandPollResults extends Command public CommandPollResults(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Will show current results of a poll and percentages of votes per choice"); } + public String HelpText() { return LocStrings.Stub("PollResultsInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -24,9 +24,11 @@ public class CommandPollResults extends Command totalVotes += votes.get(i).votes; } + results += "The poll was " + guild.poll + "\n"; + for(int i = 0; i < votes.size(); i++) { - results += String.format(Localizer.Stub("%s people voted for %s `%s` with `%s%` !\n "), votes.get(i).votes, votes.get(i).choice, (int)(((double)votes.get(i).votes) / ((double)totalVotes) * 100)); + results += String.format(LocStrings.Stub("PollResultsResponse"), votes.get(i).votes, votes.get(i).choice, (int)(((double)votes.get(i).votes) / ((double)totalVotes) * 100)); } res.Call(results); diff --git a/src/commands/CommandPollShow.java b/src/commands/CommandPollShow.java index 06c3a1c..08cde19 100644 --- a/src/commands/CommandPollShow.java +++ b/src/commands/CommandPollShow.java @@ -8,18 +8,18 @@ public class CommandPollShow extends Command public CommandPollShow(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Will show the current poll running"); } + public String HelpText() { return LocStrings.Stub("PollShowInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { if(!guild.polling) { - res.Call(Localizer.Stub("There is no poll running!")); + res.Call(LocStrings.Stub("PollShowNoPoll")); return; } - String poll = String.format(Localizer.Stub("The current poll is `%s`\n"), guild.poll); - poll += Localizer.Stub("And the choices are:\n"); + String poll = String.format(LocStrings.Stub("PollShowPoll"), guild.poll); + poll += LocStrings.Stub("PollShowChoices"); for(int i = 0; i < guild.choices.size(); i++) { poll += (i+1) + ": `" + guild.choices.get(i).choice + "`\n"; diff --git a/src/commands/CommandPollVote.java b/src/commands/CommandPollVote.java index 6ddde95..d3b48f5 100644 --- a/src/commands/CommandPollVote.java +++ b/src/commands/CommandPollVote.java @@ -8,7 +8,7 @@ public class CommandPollVote extends Command public CommandPollVote(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Vote in a poll with the choice number, won't work if no poll is running, you can't change your vote once you have cast it! Be careful!"); } + public String HelpText() { return LocStrings.Stub("PollVoteInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -17,7 +17,7 @@ public class CommandPollVote extends Command { if(guild.hasVoted.contains(user.uniqueID)) { - res.Call(Localizer.Stub("You already voted!")); + res.Call(LocStrings.Stub("PollVoteAlreadyVoted")); return; } try @@ -25,23 +25,23 @@ public class CommandPollVote extends Command int voteNum = Integer.parseInt(input.args)-1; if(voteNum >= guild.choices.size() || voteNum < 0) { - res.Call(String.format(Localizer.Stub("%s That's not a vaild vote!"), voteNum)); + res.Call(String.format(LocStrings.Stub("PollVoteNotValidVote"), voteNum)); return; } KittyPoll polled = guild.choices.get(voteNum); polled.votes++; guild.hasVoted.add(user.uniqueID); - res.Call(Localizer.Stub("You successfully voted for") + " `" + polled.choice + "`!"); + res.Call(LocStrings.Stub("PollVoteSuccess") + " `" + polled.choice + "`!"); return; } catch (NumberFormatException e) { - res.Call(Localizer.Stub("That's not a vaild number!")); + res.Call(LocStrings.Stub("PollVoteNotValidNumber")); return; } } - res.Call(Localizer.Stub("There is no poll running!")); + res.Call(LocStrings.Stub("PollVoteNoPoll")); } } diff --git a/src/commands/CommandRPEnd.java b/src/commands/CommandRPEnd.java index 5fa72b3..17005d6 100644 --- a/src/commands/CommandRPEnd.java +++ b/src/commands/CommandRPEnd.java @@ -5,7 +5,7 @@ import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import core.Command; -import core.Localizer; +import core.LocStrings; import core.RPManager; import dataStructures.*; @@ -14,7 +14,7 @@ public class CommandRPEnd extends Command public CommandRPEnd (KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Ends RP in channel"); } + public String HelpText() { return LocStrings.Stub("RPEndInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -33,11 +33,11 @@ public class CommandRPEnd extends Command if(sending != null) { res.CallFile(sending, "txt"); - res.Call(Localizer.Stub("Here's your file!")); + res.Call(LocStrings.Stub("RPEndFileOut")); } else { - res.Call(Localizer.Stub("You can't end this RP!")); + res.Call(LocStrings.Stub("RPEndError")); } } } diff --git a/src/commands/CommandRPG.java b/src/commands/CommandRPG.java index 7821812..306aac8 100644 --- a/src/commands/CommandRPG.java +++ b/src/commands/CommandRPG.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import core.rpg.RPGFramework; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -23,7 +23,7 @@ public class CommandRPG extends Command } @Override - public String HelpText() { return Localizer.Stub("Admin+ command only right now - experimental text RPG! Format is !rpg "); }; + public String HelpText() { return LocStrings.Stub("RPGInfo"); }; @Override @@ -45,7 +45,7 @@ public class CommandRPG extends Command if(result == null) { - res.Call(Localizer.Stub("Invalid RPG Command!")); + res.Call(LocStrings.Stub("RPGInvalid")); return; } diff --git a/src/commands/CommandRPStart.java b/src/commands/CommandRPStart.java index 4045a4f..b433cd0 100644 --- a/src/commands/CommandRPStart.java +++ b/src/commands/CommandRPStart.java @@ -3,7 +3,7 @@ package commands; import java.util.ArrayList; import core.Command; -import core.Localizer; +import core.LocStrings; import core.RPManager; import dataStructures.*; @@ -12,7 +12,7 @@ public class CommandRPStart extends Command public CommandRPStart (KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Starts an rp, add people to it by mentioning them!"); } + public String HelpText() { return LocStrings.Stub("RPStartInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) diff --git a/src/commands/CommandRating.java b/src/commands/CommandRating.java index 8ca7a6d..0adaae6 100644 --- a/src/commands/CommandRating.java +++ b/src/commands/CommandRating.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -15,7 +15,7 @@ public class CommandRating extends Command public CommandRating(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("'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."); } + public String HelpText() { return LocStrings.Stub("RatingInfo"); } // Called when the command is run! @Override @@ -55,11 +55,11 @@ public class CommandRating extends Command } if(newRating != null) - res.Call(Localizer.Stub("Kittybot content set to") + " " + newRating); + res.Call(LocStrings.Stub("RatingChanged") + " " + newRating); else - res.Call(Localizer.Stub("Invalid content rating") + " `" + input.args + "`"); + res.Call(LocStrings.Stub("RatingInvalid") + " `" + input.args + "`"); if(newRating.equals("Filtered")) - res.Call(Localizer.Stub("Warning: NSFW may slip through, images are only based on tags on their respective sites!")); + res.Call(LocStrings.Stub("RatingWarning")); } } \ No newline at end of file diff --git a/src/commands/CommandRole.java b/src/commands/CommandRole.java index 8497e27..e9633b8 100644 --- a/src/commands/CommandRole.java +++ b/src/commands/CommandRole.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; public class CommandRole extends Command @@ -9,20 +9,20 @@ public class CommandRole extends Command public CommandRole (KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("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."); } + public String HelpText() { return LocStrings.Stub("RoleInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { if(input.args.isEmpty()) { - res.Call(Localizer.Stub("Your role is") + " " + user.GetRole().name() + "!"); + res.Call(LocStrings.Stub("RoleStandardResponse") + " " + user.GetRole().name() + "!"); return; } if(user.GetRole().getValue() < KittyRole.Admin.getValue()) { - res.Call(String.format(Localizer.Stub("You aren't allowed to do that! You must have the KittyRole '%' or higher!"), KittyRole.Admin.toString())); + res.Call(String.format(LocStrings.Stub("RoleError"), KittyRole.Admin.toString())); return; } @@ -46,7 +46,7 @@ public class CommandRole extends Command break; default: - res.Call(Localizer.Stub("Please enter `general`, `mod`, or `admin`!")); + res.Call(LocStrings.Stub("RoleNeededRole")); return; } String users = ""; @@ -56,6 +56,6 @@ public class CommandRole extends Command users += input.mentions[i].name + " "; } - res.Call(String.format(Localizer.Stub("Changed %s to role `%s`!"), users, newRole.name())); + res.Call(String.format(LocStrings.Stub("RoleChanged"), users, newRole.name())); } } diff --git a/src/commands/CommandRoll.java b/src/commands/CommandRoll.java index fd7e7f6..5a9ef7e 100644 --- a/src/commands/CommandRoll.java +++ b/src/commands/CommandRoll.java @@ -16,7 +16,7 @@ public class CommandRoll extends Command public CommandRoll(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("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"); } + public String HelpText() { return LocStrings.Stub("RollInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -27,7 +27,7 @@ public class CommandRoll extends Command } catch(Exception e) { - res.Call(Localizer.Stub("Didn't work ;3;")); + res.Call(LocStrings.Stub("RollError")); } } diff --git a/src/commands/CommandShutdown.java b/src/commands/CommandShutdown.java index 0963d7a..812aed5 100644 --- a/src/commands/CommandShutdown.java +++ b/src/commands/CommandShutdown.java @@ -2,7 +2,7 @@ package commands; import core.Command; import core.DatabaseManager; -import core.Localizer; +import core.LocStrings; import core.Stats; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -11,6 +11,8 @@ import dataStructures.KittyRole; import dataStructures.KittyUser; import dataStructures.Response; import dataStructures.UserInput; +import utils.GlobalLog; +import utils.LogFilter; // NOTE(wisp): This is a sort of special command. public class CommandShutdown extends Command @@ -18,7 +20,7 @@ public class CommandShutdown extends Command public CommandShutdown(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown."); } + public String HelpText() { return LocStrings.Stub("ShutdownInfo"); } // Called when the command is run! @Override @@ -41,13 +43,14 @@ public class CommandShutdown extends Command if(isSafe) { - DatabaseManager.instance.Upkeep(); // Force upkeep, this works so long as on main thread. - res.CallImmediate(Localizer.Stub("Forced shutdown, database synced before abandoning threads.")); + // Force upkeep, this works so long as upkeep is on the main thread. + DatabaseManager.instance.Upkeep(); + GlobalLog.Error(LogFilter.Command, "Forced shutdown, database synced before abandoning threads."); System.exit(0); } else { - res.CallImmediate(Localizer.Stub("Forced immediate shutdown, threads abandoned without sync.")); + GlobalLog.Error(LogFilter.Command, "Forced immediate shutdown, threads abandoned without sync."); System.exit(0); } } diff --git a/src/commands/CommandStark.java b/src/commands/CommandStark.java index 3507c3d..16378c8 100644 --- a/src/commands/CommandStark.java +++ b/src/commands/CommandStark.java @@ -8,7 +8,7 @@ import java.io.IOException; import javax.imageio.ImageIO; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; import utils.ImageUtils; @@ -17,7 +17,7 @@ public class CommandStark extends Command public CommandStark(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Snaps your icon or the icon of a friend you mentioned"); }; + public String HelpText() { return LocStrings.Stub("StarkInfo"); }; private static Long num = 0l; diff --git a/src/commands/CommandStats.java b/src/commands/CommandStats.java index fad2086..7f4f254 100644 --- a/src/commands/CommandStats.java +++ b/src/commands/CommandStats.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import core.CommandManager.ThreadData; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -17,7 +17,7 @@ public class CommandStats extends Command public CommandStats(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("Displays the actively running KittyBot application information"); } + public String HelpText() { return LocStrings.Stub("StatsInfo"); } // Called when the command is run! @Override diff --git a/src/commands/CommandTeey.java b/src/commands/CommandTeey.java new file mode 100644 index 0000000..6a3394a --- /dev/null +++ b/src/commands/CommandTeey.java @@ -0,0 +1,71 @@ +package commands; + +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; +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; +import utils.ImageOverlayBuilder; +import utils.ImageUtils; + +public class CommandTeey extends Command +{ + // Required constructor + public CommandTeey(KittyRole level, KittyRating rating) { super(level, rating); } + + private static Long num = 0l; + + @Override + public String HelpText() { return LocStrings.Stub("TeeyInfo"); } + + // Called when the command is run! + @Override + public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) + { + String name = null; + File teeyFile = null; + File teeyeeFile = null; + + synchronized(num) + { + name = "teey_" + num + ".gif"; + ++num; + } + + try + { + KittyUser person = null; + + if(input.mentions == null) + person = user; + else + person = input.mentions[0]; + + String yeeteeFilename = ImageUtils.DownloadFromURL(person.avatarID, ".png"); + if(yeeteeFilename == null) + return; + + teeyeeFile = new File(yeeteeFilename); + ImageOverlayBuilder builder = new ImageOverlayBuilder("assets/teey/frames/", "teey ", 24, 18); + builder.Overlay(ImageIO.read(teeyeeFile), name); + } + catch (IOException e) + { + e.printStackTrace(); + } + + teeyFile = new File (name); + res.CallFile(teeyFile, "gif"); + + // Thread cleanup... + ImageUtils.BlockingFileDelete(teeyFile); + ImageUtils.BlockingFileDelete(teeyeeFile); + } +} diff --git a/src/commands/CommandTweet.java b/src/commands/CommandTweet.java index 8a0bb40..8c9770a 100644 --- a/src/commands/CommandTweet.java +++ b/src/commands/CommandTweet.java @@ -1,7 +1,7 @@ package commands; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; import network.NetworkTwitter; @@ -11,15 +11,16 @@ public class CommandTweet extends Command public CommandTweet(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return Localizer.Stub("With an input of x,y,z where x y and z are all choices, kitty will choose one"); } + public String HelpText() { return LocStrings.Stub("TweetInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { + //TODO: Figure out how to pass pictures correctly try { res.Call(tweet.tweet(input.args)); } catch (Exception e) { - res.Call(Localizer.Stub("Tweet command failed!")); + res.Call(LocStrings.Stub("TweetError")); } } } diff --git a/src/commands/CommandWolfram.java b/src/commands/CommandWolfram.java index 80d6163..4947261 100644 --- a/src/commands/CommandWolfram.java +++ b/src/commands/CommandWolfram.java @@ -3,7 +3,7 @@ package commands; import java.io.File; import java.io.IOException; import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.*; import network.*; import utils.ImageUtils; @@ -15,13 +15,13 @@ public class CommandWolfram extends Command public CommandWolfram(KittyRole level, KittyRating rating) { super(level, rating);} @Override - public String HelpText() { return Localizer.Stub("Will query wolframalpha with your question and give a full image output of the answer"); } + public String HelpText() { return LocStrings.Stub("WolframInfo"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { if(input.args == null || input.args.trim().length() == 0) - res.Call(Localizer.Stub("You need to provide some arguments!")); + res.Call(LocStrings.Stub("WolframNoArgs")); try { @@ -31,7 +31,7 @@ public class CommandWolfram extends Command } catch (IOException e) { - res.Call(Localizer.Stub("Something went wrong!")); + res.Call(LocStrings.Stub("WolframError")); } } } \ No newline at end of file diff --git a/src/commands/CommandYeet.java b/src/commands/CommandYeet.java index 7b29add..65ea728 100644 --- a/src/commands/CommandYeet.java +++ b/src/commands/CommandYeet.java @@ -1,26 +1,10 @@ package commands; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; -import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; -import java.util.Calendar; -import java.util.Iterator; - -import javax.imageio.IIOException; -import javax.imageio.IIOImage; import javax.imageio.ImageIO; -import javax.imageio.ImageTypeSpecifier; -import javax.imageio.ImageWriteParam; -import javax.imageio.ImageWriter; -import javax.imageio.metadata.IIOMetadata; -import javax.imageio.metadata.IIOMetadataNode; -import javax.imageio.stream.FileImageOutputStream; -import javax.imageio.stream.ImageOutputStream; - import core.Command; -import core.Localizer; +import core.LocStrings; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -28,18 +12,18 @@ import dataStructures.KittyRole; import dataStructures.KittyUser; import dataStructures.Response; import dataStructures.UserInput; +import utils.ImageOverlayBuilder; import utils.ImageUtils; public class CommandYeet extends Command { - // Required constructor public CommandYeet(KittyRole level, KittyRating rating) { super(level, rating); } private static Long num = 0l; @Override - public String HelpText() { return Localizer.Stub("Yeet yourself or yeet a friend with @!"); } + public String HelpText() { return LocStrings.Stub("YeetInfo"); } // Called when the command is run! @Override @@ -60,20 +44,17 @@ public class CommandYeet extends Command KittyUser person = null; if(input.mentions == null) - { person = user; - } else - { person = input.mentions[0]; - } String yeeteeFilename = ImageUtils.DownloadFromURL(person.avatarID, ".png"); if(yeeteeFilename == null) return; yeeteeFile = new File(yeeteeFilename); - YEET(ImageIO.read(yeeteeFile), name); + ImageOverlayBuilder builder = new ImageOverlayBuilder("assets/yeet/frames/", "yeet ", 24, 18); + builder.Overlay(ImageIO.read(yeeteeFile), name); } catch (IOException e) { @@ -87,251 +68,4 @@ public class CommandYeet extends Command ImageUtils.BlockingFileDelete(yeetFile); ImageUtils.BlockingFileDelete(yeeteeFile); } - - // Lets get some trash established for the yeet - public static final boolean VERBOSE = false; - public static final int NONE = -1; - public static final int PIXEL_BYTE_LENGTH = 4; // 32-bit PNG, RGBA - public static final String YEET_BASE_PATH = "assets/yeet/frames/"; - public static final int YEET_BASE_SIZE = 24; - public static final int YEET_FPS = 18; - - // Some small logging functions... cause we're professionals... - public static void Verbose(String str) { if(VERBOSE) Log("[Verbose] " + str); } - public static void Log(String str) { System.out.println("[Log] " + str); } - public static void Warn(String str) { System.out.println("[Warn] " + str); } - public static void Error(String str) { System.out.println("[Error] " + str); } - - // Performs the Y E E T (image overlay per frame specified, catches IO errors as a note.) - public static void YEET(BufferedImage overlay, String outpath) - { - try - { - long start = Calendar.getInstance().getTimeInMillis(); - - ProcessYeet(overlay, outpath); - - long end = Calendar.getInstance().getTimeInMillis(); - Log("Took " + (end - start) + "ms"); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - // Processing the image frames to construct a gif. Relies on (0,255,0) pixel for image center specification. - public static void ProcessYeet(BufferedImage overlay, String outfileName) throws IOException - { - BufferedImage[] frames = new BufferedImage[YEET_BASE_SIZE]; - - for(int i = 0; i < YEET_BASE_SIZE; ++i) - { - BufferedImage out = CombineImages(YEET_BASE_PATH + "yeet " + i + ".png", overlay); - - if(out != null) - frames[i] = out; - else - Error("There was an issue with frame " + i); - } - - Verbose("Processed " + YEET_BASE_SIZE + " frames, writing..."); - ImageOutputStream output = new FileImageOutputStream(new File(outfileName)); - GifSequenceWriter writer = new GifSequenceWriter(output, frames[0].getType(), YEET_FPS, true); - - for(int i = 0; i < YEET_BASE_SIZE; ++i) - writer.writeToSequence(frames[i]); - - writer.close(); - output.close(); - } - - // Performs an overlay at a pixel location. We're making some assumptions here, mostly that there is going - // to be an RGBA-32-bit encoded PNG image read in for our parsing purposes. We then look for a 0, 255, 0 - // green pixel on the base frame to apply the overlay buffer to, centered. - public static BufferedImage CombineImages(String pathBase, BufferedImage overlay) throws IOException - { - // Acquire images - BufferedImage imageBase = null; - BufferedImage imageOverlay = overlay; - - imageBase = ImageIO.read(new File(pathBase)); - - // Grab data we know won't change. As a side note, I discovered you can get specific pixels a bit - // differently later, but it was too late, I wrote the pixel specific code already. - final byte[] pixelsBase = ((DataBufferByte) imageBase.getRaster().getDataBuffer()).getData(); - final int baseWidth = imageBase.getWidth(); - final int overlayWidth = imageOverlay.getWidth(); - final int baseHeight = imageBase.getHeight(); - final int overlayHeight = imageOverlay.getHeight(); - - // Warn about odd sizing when applicable - if(overlayHeight > baseHeight || overlayWidth > baseWidth) - Warn("Size mismatch, overlay is larger. May function, but not supported."); - - // Skim base picture for solid green pixel to use as target center - int targetX = NONE; - int targetY = NONE; - for(int i = 0; i < pixelsBase.length; i += PIXEL_BYTE_LENGTH) - { - final int x = ((i / PIXEL_BYTE_LENGTH) % baseWidth); - final int y = ((i / PIXEL_BYTE_LENGTH) / baseWidth); - - final int r = (pixelsBase[i]); - final int g = (pixelsBase[i + 1]); - final int b = (pixelsBase[i + 2]); - //final int a = (pixelsBase[i + 3]); - - // Max contrast in 32-bit PNG for green is no red no blue, max green (ratio), max alpha (implied 0 here) - if(r == -1 && g == 0 && b == -1) - { - //Log("Found target pixel at x: " + x + " y: " + y); - targetX = x; - targetY = y; - break; - } - } - - // Skip overlay if we have no target location - if(targetX == NONE || targetY == NONE) - { - Verbose("No overlay required for this frame."); - return imageBase; - } - - // Re-create a new byte array and establish overlay bounds - final int left = targetX - overlayWidth / 2; - final int right = targetX + overlayWidth / 2; - final int top = targetY - overlayHeight / 2; - final int bottom = targetY + overlayHeight / 2; - - // Apply overlay when appropriate - for(int i = 0; i < pixelsBase.length; i += PIXEL_BYTE_LENGTH) - { - final int x = ((i / PIXEL_BYTE_LENGTH) % baseWidth); - final int y = ((i / PIXEL_BYTE_LENGTH) / baseWidth); - - // If we're within the bounds of where the overlay picture should go... - if(x > left && x < right && y > top && y < bottom) - { - final int overlayX = x - left; - final int overlayY = y - top; - - // Skip out of bounds pixels - if(overlayX < 0 || overlayY < 0 || overlayX >= baseWidth || overlayY >= baseHeight) - continue; - - // Re-write bytes as overlay - imageBase.setRGB(x, y, imageOverlay.getRGB(overlayX, overlayY)); - } - } - - // Give the frame back - return imageBase; - } - - - // GifSequenceWriter.java - // - // Created by Elliot Kroo on 2009-04-25, - // (Small modifications by wisp in 2018) - // - // This work is licensed under the Creative Commons Attribution 3.0 Unported License. - // To view a copy of this license visit http://creativecommons.org/licenses/by/3.0/ - // NOTE(wisp): This is Elliot's original license - public static class GifSequenceWriter - { - protected ImageWriter gifWriter; - protected ImageWriteParam imageWriteParam; - protected IIOMetadata imageMetaData; - - // NOTE: This is limited to things that divide into 1000 cleanly as multiples of 10. - public GifSequenceWriter(ImageOutputStream outputStream, int imageType, int framesPerSecond, boolean isLooping) throws IIOException, IOException - { - gifWriter = getWriter(); - imageWriteParam = gifWriter.getDefaultWriteParam(); - ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType); - - imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam); - - String metaFormatName = imageMetaData.getNativeMetadataFormatName(); - - IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName); - IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension"); - graphicsControlExtensionNode.setAttribute("disposalMethod", "none"); - graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE"); - graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE"); - graphicsControlExtensionNode.setAttribute("delayTime", "" + (int) ((1000.0 / framesPerSecond) / 10.0)); // THis line isn't super well honored - graphicsControlExtensionNode.setAttribute("transparentColorIndex","0"); - - IIOMetadataNode appEntensionsNode = getNode( root, "ApplicationExtensions"); - IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension"); - child.setAttribute("applicationID", "NETSCAPE"); - child.setAttribute("authenticationCode", "2.0"); - - int loopValue = isLooping ? 0 : 1; - child.setUserObject(new byte[]{ 0x1, (byte) (loopValue & 0xFF), (byte) ((loopValue >> 8) & 0xFF)}); - appEntensionsNode.appendChild(child); - - imageMetaData.setFromTree(metaFormatName, root); - - gifWriter.setOutput(outputStream); - gifWriter.prepareWriteSequence(null); - } - - public void writeToSequence(RenderedImage img) throws IOException - { - gifWriter.writeToSequence(new IIOImage(img, null, imageMetaData), imageWriteParam); - } - - /** - * Close this GifSequenceWriter object. This does not close the underlying - * stream, just finishes off the GIF. - */ - public void close() throws IOException - { - gifWriter.endWriteSequence(); - } - - /** - * Returns the first available GIF ImageWriter using - * ImageIO.getImageWritersBySuffix("gif"). - * - * @return a GIF ImageWriter object - * @throws IIOException if no GIF image writers are returned - */ - private static ImageWriter getWriter() throws IIOException - { - Iterator iter = ImageIO.getImageWritersBySuffix("gif"); - - if(!iter.hasNext()) - throw new IIOException("No GIF Image Writers Exist"); - else - return iter.next(); - } - - /** - * Returns an existing child node, or creates and returns a new child node (if - * the requested node does not exist). - * - * @param rootNode the IIOMetadataNode to search for the child node. - * @param nodeName the name of the child node. - * - * @return the child node, if found or a new node created with the given name. - */ - private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName) - { - int nodeCount = rootNode.getLength(); - for (int i = 0; i < nodeCount; i++) - { - if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0) - return((IIOMetadataNode) rootNode.item(i)); - } - - IIOMetadataNode node = new IIOMetadataNode(nodeName); - rootNode.appendChild(node); - - return(node); - } - } } diff --git a/src/core/CommandEnabler.java b/src/core/CommandEnabler.java new file mode 100644 index 0000000..a45f047 --- /dev/null +++ b/src/core/CommandEnabler.java @@ -0,0 +1,124 @@ +package core; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +import utils.FileUtils; +import utils.GlobalLog; +import utils.LogFilter; + +// While some of the patterns in this file are similar to the localization files, +// commands that are being looked up will behave slightly differently so trimming +// rules for this file are different than the localization ones - this is more +// aggresive with whitespace removal. +public class CommandEnabler +{ + // Config/const variables + public static final String filename = "commands.config"; + public static final String pairSplit = "="; + public static final char pairSeparator = '\n'; + public static final String enabled = "1"; + public static final String disabled = "0"; + public static final boolean defaultEnabledState = true; + + // Local variables + private HashMap enabledMap; // Quick lookup + private ArrayList keyList; // Tracking ordering for later + + public CommandEnabler() + { + GlobalLog.Log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName()); + enabledMap = new HashMap<>(); + keyList = new ArrayList<>(); + + ReadIn(); + GetTrackedCommands(); + WriteOut(); + } + + // Reads in the config file and parses it, keeping tabs on the order it read things + private void ReadIn() + { + File f = new File(filename); + if(f.isFile() && f.canRead()) + { + String content = FileUtils.ReadContent(f).trim(); + String[] lines = content.split("" + pairSeparator); + + for(int i = 0; i < lines.length; ++i) + { + String[] pair = lines[i].split(pairSplit); + + if(pair.length < 2) + continue; + + String key = pair[0].trim(); + String value = pair[1].trim().toLowerCase(); + + keyList.add(key); + + if(value.equalsIgnoreCase(enabled)) + enabledMap.putIfAbsent(key, true); + else + enabledMap.putIfAbsent(key, false); + } + } + } + + // Look up the already scraped values from the localizer and store them if they + // don't already exist in the lookup. Defaults to defaultEnabledState. + private void GetTrackedCommands() + { + ArrayList unloc = LocCommands.GetUnlocalizedCommands(); + + for(int i = 0; i < unloc.size(); ++i) + { + String command = unloc.get(i); + if(enabledMap.putIfAbsent(command, defaultEnabledState) == null) + { + GlobalLog.Log(LogFilter.Strings, "Identified new toggleable raw command: " + command); + keyList.add(command); + } + } + } + + // Write out enabled/disabled file info. + private void WriteOut() + { + try + { + String outString = ""; + for(int i = 0; i < keyList.size(); ++i) + { + String key = keyList.get(i); + String value = enabled; + + if(enabledMap.get(key) == false) + value = disabled; + + outString += key + pairSplit + value + pairSeparator; + } + + BufferedWriter writer = new BufferedWriter(new FileWriter(filename)); + writer.write(outString); + writer.close(); + } + catch (IOException e) + { + GlobalLog.Error(LogFilter.Core, "Command enabler issue writing file! " + e.getMessage()); + } + } + + // Looks up a key to see if it's enabled or not + public boolean IsEnabled(String key) + { + if(enabledMap.containsKey(key)) + return enabledMap.get(key); + + return true; + } +} diff --git a/src/core/CommandManager.java b/src/core/CommandManager.java index e3e8970..dac2714 100644 --- a/src/core/CommandManager.java +++ b/src/core/CommandManager.java @@ -6,6 +6,7 @@ import java.util.Map.Entry; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyUser; +import dataStructures.Pair; import dataStructures.Response; import dataStructures.UserInput; import utils.GlobalLog; @@ -16,22 +17,40 @@ public class CommandManager // Variables private HashMap commands; private ArrayList threadAccumulator; + private CommandEnabler commandEnabler; private long invokeCount; - // Default Constructor - public CommandManager() + public CommandManager(CommandEnabler commandEnabler) { - commands = new HashMap(); - threadAccumulator = new ArrayList(); - invokeCount = 0; + this.commands = new HashMap(); + this.threadAccumulator = new ArrayList(); + this.invokeCount = 0; + this.commandEnabler = commandEnabler; } - // Allows the command manager to keep track of a command. - public void Register(String key, Command command) - { - if(key == null) - return; + // Allows the command manager to keep track of a command. Takes a pair (the un-localized and localzied commands) + // and the command associated with the localized commands. + public void Register(Pair pair, Command command) + { + if(pair == null || pair.Second == null) + return; + + // If we haven't already split a multisplit command (or even assessed that), + // then verify if we even need to register the commands at all. If it's + // not enabled, don't register it. + if(pair.First != null && !commandEnabler.IsEnabled(pair.First)) + return; + + String key = pair.Second; + + if(key.contains(",")) + { + + String[] keys = key.split(","); + Register(keys, command); + return; + } key = key.toLowerCase(); command.registeredNames.add(key); @@ -51,7 +70,7 @@ public class CommandManager public void Register(String[] keys, Command command) { for(int i = 0; i < keys.length; ++i) - Register(keys[i], command); + Register(new Pair(null, keys[i].trim()), command); } // Calls the command but on a whole new thread! diff --git a/src/core/Localizer.java b/src/core/LocBase.java similarity index 65% rename from src/core/Localizer.java rename to src/core/LocBase.java index beb86a0..8106779 100644 --- a/src/core/Localizer.java +++ b/src/core/LocBase.java @@ -8,32 +8,40 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import dataStructures.SectionedKeyValueStore; +import dataStructures.TaggedPairStore; import utils.FileUtils; import utils.GlobalLog; import utils.LogFilter; // A quick-and-dirty localization tool that scrapes the project for calls to itself, then -// generates/updates a file externally (phrases.config) with all the stub values as keys that -// can then be localized. -public class Localizer +// generates/updates a file externally with all the stub values as keys that are localized. +public abstract class LocBase { + // Pre-defined values + public static final String KittySourceDirectory = "./src"; + // Filename - public final static String filename = "localization.config"; - public final static String functionName = "Localizer.Stub"; + public final String filename; // Example: "localization.config"; + public final String functionName; // Example: "Localizer.Stub"; // Local translation storage - private static SectionedKeyValueStore stringStore; + protected TaggedPairStore stringStore; // Logging - private static void Log(String str) { GlobalLog.Log(LogFilter.Strings, str); } - private static void Warn(String str) { GlobalLog.Warn(LogFilter.Strings, str); } - private static void Error(String str) { GlobalLog.Error(LogFilter.Strings, str); } + private void Log(String str) { GlobalLog.Log(LogFilter.Strings, str); } + private void Warn(String str) { GlobalLog.Warn(LogFilter.Strings, str); } + private void Error(String str) { GlobalLog.Error(LogFilter.Strings, str); } + // Ok... so this is an array because if it's not an array, the parser will parse the string + public LocBase(String filename, String functionName) + { + this.filename = filename; + this.functionName = functionName; + } // Structure used for holding a pair of strings and any other info we need // about localized information that is being looked up. - private static class LocInfo + private class LocInfo { public String file; public String phrase; @@ -46,7 +54,7 @@ public class Localizer } // Do processing on each path in the scraped directory here, assuming it's .java - public static void StripForContents(Path path, ArrayList strings) + public void StripForContents(Path path, ArrayList strings) { String filename = path.getFileName().toString(); if(filename.contains(".java")) @@ -58,10 +66,11 @@ public class Localizer for(int i = 1; i < split.length; ++i) { int loc = split[i].indexOf(")"); + String noWhitespace = split[i].replaceAll("\\s+",""); if(loc != -1) { - if(split[i].charAt(loc - 1) == '"' && split[i].charAt(loc - 2) != '\\') + if(noWhitespace.charAt(noWhitespace.indexOf(")") - 1) == '"' && split[i].charAt(loc - 2) != '\\') { // At this point, we find the first ), then verify there's a ") behind it, and that // the " is not an escaped character. @@ -71,7 +80,7 @@ public class Localizer strings.add(new LocInfo(filename.substring(0, filename.lastIndexOf('.')), toLocalize)); - Log("Found stubbed phrase in " + path + " : " + toLocalize); + Log("Found lookup call in " + path + ": " + toLocalize); } catch(IndexOutOfBoundsException e) { @@ -86,7 +95,7 @@ public class Localizer // Nothing for now, but in the future will return a parsed and localized version of // the string in question if one can be found. If the localized string is empty, // returns a the key instead which is the default phrase. - public static String Stub(String input) + public String GetKey(String input) { if(stringStore == null) return input; @@ -99,7 +108,7 @@ public class Localizer } // Reads a file to string, adapted from https://stackoverflow.com/a/326440/5383198 - static String ReadFileAsString(String path, Charset encoding) + private String ReadFileAsString(String path, Charset encoding) { try { @@ -116,9 +125,9 @@ public class Localizer // Update localization from the disk on file. Creates the file if it doesn't exist. // This file is internally formatted as an ini file. - public static void UpdateLocFromDisk() + public void UpdateLocFromDisk() { - Log("Attempting to read localization file"); + Log("Attempting to read localization file: " + filename); try { @@ -129,10 +138,8 @@ public class Localizer File file = new File(filename); file.createNewFile(); } - else - { - stringStore = new SectionedKeyValueStore(fileContents); - } + + stringStore = new TaggedPairStore(fileContents); } catch(IOException e) { @@ -142,7 +149,7 @@ public class Localizer // Rewrites out at the specified filename with existing stubs. // This preserves existing localized phrases. - public static void SaveLocToDisk() + public void SaveLocToDisk() { Log("Attempting to write updated localization file"); @@ -158,14 +165,26 @@ public class Localizer } } + private void TryStripSpecified(Path path, ArrayList toFill) + { + try + { + StripForContents(path, toFill); + } + catch(Exception e) + { + Error("issue with file: " + path.toString()); + } + } + // Scrape the project and generate all the possible localizeable phrases. // This stubs out phrases to be localized. - public static void ScrapeAll() + public void ScrapeAll() { ArrayList localizeList = new ArrayList(); - FileUtils.AcquireAllFiles(".\\src").forEach((path) -> StripForContents(path, localizeList)); - + FileUtils.AcquireAllFiles(KittySourceDirectory).forEach((path) -> TryStripSpecified(path, localizeList)); + for(LocInfo toStub : localizeList) stringStore.AddKeyValue(toStub.file, toStub.phrase, toStub.phrase); } -} \ No newline at end of file +} diff --git a/src/core/LocCommands.java b/src/core/LocCommands.java new file mode 100644 index 0000000..04c6ed5 --- /dev/null +++ b/src/core/LocCommands.java @@ -0,0 +1,50 @@ +package core; + +import java.util.ArrayList; +import utils.GlobalLog; +import utils.LogFilter; +import dataStructures.Pair; + +// Performs the same localization for the strings associated with command names as +// is performed with general strings in the application +public class LocCommands extends LocBase +{ + public static final String fileName = "locCommands.config"; + public static final String function = "LocCommands.Stub"; + + private static LocCommands instance; + + public LocCommands() + { + super(fileName, function); + + GlobalLog.Log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName()); + + if(instance == null) + { + instance = this; + + UpdateLocFromDisk(); + ScrapeAll(); + SaveLocToDisk(); + } + else + { + GlobalLog.Error(LogFilter.Core, "You can't have two of the following: " + this.getClass().getSimpleName()); + } + } + + // Returns a pair, the raw key and the stub key + public static Pair Stub(String toStub) + { + return new Pair(toStub, instance.GetKey(toStub)); + } + + // Gets all of the un-translated defaults in the commands list. + public static ArrayList GetUnlocalizedCommands() + { + ArrayList raw = new ArrayList<>(); + instance.stringStore.ForEach((pair) -> raw.add((String)((Pair)pair).First )); + return raw; + } +} diff --git a/src/core/LocStrings.java b/src/core/LocStrings.java new file mode 100644 index 0000000..2cee4ed --- /dev/null +++ b/src/core/LocStrings.java @@ -0,0 +1,40 @@ +package core; + +import utils.GlobalLog; +import utils.LogFilter; + +// A quick-and-dirty localization tool that scrapes the project for calls to itself, then +// generates/updates a file externally (phrases.config) with all the stub values as keys that +// can then be localized. +public class LocStrings extends LocBase +{ + public static final String fileName = "locStrings.config"; + public static final String function = "LocStrings.Stub"; + + private static LocStrings instance; + + public LocStrings() + { + super(fileName, function); + + GlobalLog.Log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName()); + + if(instance == null) + { + instance = this; + + UpdateLocFromDisk(); + ScrapeAll(); + SaveLocToDisk(); + } + else + { + GlobalLog.Error(LogFilter.Core, "You can't have two of the following: " + this.getClass().getSimpleName()); + } + } + + public static String Stub(String toStub) + { + return instance.GetKey(toStub); + } +} \ No newline at end of file diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index 448e3cf..730ddaf 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -13,7 +13,7 @@ import utils.LogFilter; // NOTE(wisp): Isolated factory to assist with storage and caching if needed. // This also minimizes the number of places JDA interacts with our codebase. // As it stands, if the object name begins with Kitty, it's constructed here. -// TODO: Make all methods ID based instead of event based +// TODO: Make all methods ID based instead of event based public class ObjectBuilderFactory { // Key: guild string id, Value: guild information @@ -34,9 +34,20 @@ public class ObjectBuilderFactory // RPManger for tracking RP system private static RPManager rpManager; - // Lazy initialization style for + // Localization classes - these are singletons, but should be initialized before almost all other + // things so their inclusion in the factory is to ensure they're started at the correct time. + @SuppressWarnings("unused") private static LocStrings locStrings; + @SuppressWarnings("unused") private static LocCommands locCommands; + + // Handles if we can or can't use specific commands, parsing a config file based on loc data to do so. + private static CommandEnabler commandEnabler; + + // Lazy initialization multithreaded mutex stuff to prevent explosions. + // TODO: Investigate using 'synchronized' instead potentially private static boolean hasInitialized; private static Semaphore initMutex = new Semaphore(1); + + // This is it, this is how the lazy init starts! private static void LazyInit() { if(hasInitialized) @@ -47,26 +58,31 @@ public class ObjectBuilderFactory initMutex.acquire(); try { - // Initialization here. This is where we could read from something external. + // structure initialization + // Construct necessary data structures. guildCache = new HashMap(); userCache = new HashMap(); channelCache = new HashMap(); database = null; stats = null; + + // Start by reading from things that are external. Because + // we require these things to be resolved before the rest of the application, + // we place them here. + locStrings = new LocStrings(); + locCommands = new LocCommands(); } finally { initMutex.release(); + hasInitialized = true; } } catch(InterruptedException ie) { GlobalLog.Error(LogFilter.Core, "Issue during object builder lazy initialization." - + " The factory was not initialized, " - + "and kitty will not be able to continue functionally."); + + " The factory was not initialized, and kitty will not be able to continue functionally."); } - - hasInitialized = true; } // Explicitly locks: guildCache @@ -276,58 +292,70 @@ public class ObjectBuilderFactory user.avatarID = member.getUser().getAvatarUrl(); } - // Default construction of the command manager. - // TODO(wisp): We want to be able to keep all this data - // stored off in a file at some point, so we can reflect it onto the - // project and build it per-guild. That's for later now tho. - public static CommandManager ConstructCommandManager() + // Constructs a CommandEnabler if it doesn't exist, and gets the existing one if it does. + public static CommandEnabler ConstructCommandEnabler() + { + LazyInit(); + + if(commandEnabler == null) + commandEnabler = new CommandEnabler(); + + return commandEnabler; + } + + // Default construction of the command manager. In order to remotely resolve command enabling + // and disabling, what we do is construct the commands with a localized pair that is checked against + // the CommandEnabler object passed in. In theory, we could have multiple CommandManagers, tho we can + // only have one CommandEnabler. + public static CommandManager ConstructCommandManager(CommandEnabler commandEnabler) { LazyInit(); - CommandManager manager = new CommandManager(); + CommandManager manager = new CommandManager(commandEnabler); - manager.Register("work", new CommandDoWork(KittyRole.Dev, KittyRating.Safe)); - manager.Register("shutdown", new CommandShutdown(KittyRole.Dev, KittyRating.Safe)); - manager.Register("stats", new CommandStats(KittyRole.Dev, KittyRating.Safe)); - manager.Register("invite", new CommandInvite(KittyRole.Dev, KittyRating.Safe)); - manager.Register("buildHelp", new CommandHelpBuilder(KittyRole.Dev, KittyRating.Safe)); - manager.Register("tweet", new CommandTweet(KittyRole.Dev, KittyRating.Safe)); + manager.Register(LocCommands.Stub("work"), new CommandDoWork(KittyRole.Dev, KittyRating.Safe)); + manager.Register(LocCommands.Stub("shutdown"), new CommandShutdown(KittyRole.Dev, KittyRating.Safe)); + manager.Register(LocCommands.Stub("stats"), new CommandStats(KittyRole.Dev, KittyRating.Safe)); + manager.Register(LocCommands.Stub("invite"), new CommandInvite(KittyRole.Dev, KittyRating.Safe)); + manager.Register(LocCommands.Stub("buildHelp"), new CommandHelpBuilder(KittyRole.Dev, KittyRating.Safe)); + manager.Register(LocCommands.Stub("tweet"), new CommandTweet(KittyRole.Dev, KittyRating.Safe)); - manager.Register("rating", new CommandRating(KittyRole.Admin, KittyRating.Safe)); - manager.Register("indicator", new CommandChangeIndicator(KittyRole.Admin, KittyRating.Safe)); + manager.Register(LocCommands.Stub("rating"), new CommandRating(KittyRole.Admin, KittyRating.Safe)); + manager.Register(LocCommands.Stub("indicator"), new CommandChangeIndicator(KittyRole.Admin, KittyRating.Safe)); - manager.Register("poll", new CommandPollManage(KittyRole.Mod, KittyRating.Safe)); - manager.Register("givebeans", new CommandGiveBeans(KittyRole.Mod, KittyRating.Safe)); - manager.Register("rpg", new CommandRPG(KittyRole.Mod, KittyRating.Safe)); + 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(new String[]{"perish", "thenperish"}, new CommandPerish(KittyRole.General, KittyRating.Safe)); - manager.Register("yeet", new CommandYeet(KittyRole.General, KittyRating.Safe)); - manager.Register("ping", new CommandPing(KittyRole.General, KittyRating.Safe)); - manager.Register("boop", new CommandBoop(KittyRole.General, KittyRating.Safe)); - manager.Register("roll", new CommandRoll(KittyRole.General, KittyRating.Safe)); - manager.Register("choose", new CommandChoose(KittyRole.General, KittyRating.Safe)); - manager.Register("help", new CommandHelp(KittyRole.General, KittyRating.Safe)); - manager.Register(new String[] {"info", "about"}, new CommandInfo(KittyRole.General, KittyRating.Safe)); - manager.Register("vote", new CommandPollVote(KittyRole.General, KittyRating.Safe)); - manager.Register("results", new CommandPollResults(KittyRole.General, KittyRating.Safe)); - manager.Register("showpoll", new CommandPollShow(KittyRole.General, KittyRating.Safe)); - manager.Register("wolfram", new CommandWolfram(KittyRole.General, KittyRating.Safe)); - manager.Register(new String[] {"c++", "g++", "cplus","cpp"}, new CommandColiru(KittyRole.General, KittyRating.Safe)); - manager.Register(new String[] {"java", "jdoodle" }, new CommandJDoodle(KittyRole.General, KittyRating.Safe)); - manager.Register("beans", new CommandBeansShow(KittyRole.General, KittyRating.Safe)); - manager.Register("role", new CommandRole(KittyRole.General, KittyRating.Safe)); - manager.Register("bet", new CommandBetBeans(KittyRole.General, KittyRating.Safe)); - manager.Register("map", new CommandMap(KittyRole.General, KittyRating.Safe)); - manager.Register("rpstart", new CommandRPStart(KittyRole.General, KittyRating.Safe)); - manager.Register("rpend", new CommandRPEnd(KittyRole.General, KittyRating.Safe)); - manager.Register(new String[] {"tony", "stark", "dontfeelgood", "dontfeelsogood"}, new CommandStark(KittyRole.General, KittyRating.Safe)); - manager.Register("blur", new CommandBlurry(KittyRole.General, KittyRating.Safe)); - manager.Register(new String [] {"eightball", "8ball"}, new CommandEightBall(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("teey"), new CommandTeey(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("perish, thenperish"), new CommandPerish(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("yeet"), new CommandYeet(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("ping"), new CommandPing(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("boop"), new CommandBoop(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("roll"), new CommandRoll(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("choose"), new CommandChoose(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("help"), new CommandHelp(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("info, about"), new CommandInfo(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("vote"), new CommandPollVote(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("results"), new CommandPollResults(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("showpoll"), new CommandPollShow(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("wolfram"), new CommandWolfram(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("c++, g++, cplus, cpp"), new CommandColiru(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("java, jdoodle"), new CommandJDoodle(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("beans"), new CommandBeansShow(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("role"), new CommandRole(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("bet"), new CommandBetBeans(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("map"), new CommandMap(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("rpstart"), new CommandRPStart(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("rpend"), new CommandRPEnd(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("tony, stark, dontfeelgood, dontfeelsogood"), new CommandStark(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("blur"), new CommandBlurry(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("eightball, 8ball"), new CommandEightBall(KittyRole.General, KittyRating.Safe)); return manager; } - // NOTE(wisp): Default database manager construction. It can be constructed + // Default database manager construction. It can be constructed // in different ways, and so we construct it outside of the constructor for // the factory since it doesn't have to be present / can be elsewhere. // Effectively we cache the database here. diff --git a/src/dataStructures/SectionedKeyValueStore.java b/src/dataStructures/TaggedPairStore.java similarity index 78% rename from src/dataStructures/SectionedKeyValueStore.java rename to src/dataStructures/TaggedPairStore.java index 0f67458..25b6a87 100644 --- a/src/dataStructures/SectionedKeyValueStore.java +++ b/src/dataStructures/TaggedPairStore.java @@ -18,25 +18,25 @@ import java.util.function.Consumer; // Note that the sections are NOT designed to allow for duplicate keys across them. // This is a restriction of the structure, but can be changed later potentially. // The only value not allowed in a key or value is the KeyValueSplit. -public class SectionedKeyValueStore +public class TaggedPairStore { // Variables public final char SectionStart = '['; public final char SectionEnd = ']'; - public final char KeyValueLineSeparator = '\n'; - public final String KeyValueSplit = "="; + public final char PairLineSeparator = '\n'; + public final String PairSplit = "="; // [Key: SectionName, [Key: KeyString, Value: ValueString]] - private HashMap> sectionKeyValue; + private HashMap> taggedPairs; // [Key: KeyString, Value: ValueString]] - private HashMap keyValue; + private HashMap allPairs; // String constructor that parses the input string into the object - public SectionedKeyValueStore(String input) + public TaggedPairStore(String input) { - sectionKeyValue = new HashMap>(); - keyValue = new HashMap(); + taggedPairs = new HashMap>(); + allPairs = new HashMap(); Parse(input); } @@ -44,7 +44,7 @@ public class SectionedKeyValueStore @SuppressWarnings({"rawtypes", "unchecked"}) public void ForEach(BiConsumer> action) { - Iterator it = sectionKeyValue.entrySet().iterator(); + Iterator it = taggedPairs.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); @@ -62,7 +62,7 @@ public class SectionedKeyValueStore @SuppressWarnings({"rawtypes"}) public void ForEach(Consumer> action) { - Iterator it = keyValue.entrySet().iterator(); + Iterator it = allPairs.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); @@ -79,11 +79,11 @@ public class SectionedKeyValueStore String out = ""; // Iterates over the sections and - Iterator it = sectionKeyValue.entrySet().iterator(); + Iterator it = taggedPairs.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); - out += ("" + SectionStart + pair.getKey() + SectionEnd + KeyValueLineSeparator); + out += ("" + SectionStart + pair.getKey() + SectionEnd + PairLineSeparator); Iterator internal = ((HashMap)pair.getValue()).entrySet().iterator(); while(internal.hasNext()) @@ -93,12 +93,12 @@ public class SectionedKeyValueStore String value = (String)internalPair.getValue(); if(key == value) - out += (key + KeyValueSplit) + KeyValueLineSeparator; + out += (key + PairSplit) + PairLineSeparator; else - out += (key + KeyValueSplit + value) + KeyValueLineSeparator; + out += (key + PairSplit + value) + PairLineSeparator; } - out += KeyValueLineSeparator; + out += PairLineSeparator; } return out; @@ -109,6 +109,9 @@ public class SectionedKeyValueStore // account of some characters having specific regex meanings. private void Parse(String input) { + if(input == null) + return; + String[] sections = input.split("\\" + SectionStart); for(int sec = 0; sec < sections.length; ++sec) @@ -128,21 +131,21 @@ public class SectionedKeyValueStore // Parse out the pairs within the section, split them all out. String unparsedPairs = section.substring(pos + 1); - String[] pairs = unparsedPairs.split("\\" + KeyValueLineSeparator); + String[] pairs = unparsedPairs.split("\\" + PairLineSeparator); // Parse out valid key-value pairs, and store them in the specified section. // At this point, we can be guarenteed that sectionName is in the Hashmap. for(int pair = 0; pair < pairs.length; ++pair) { String line = pairs[pair]; - int splitPos = line.indexOf(KeyValueSplit); + int splitPos = line.indexOf(PairSplit); if(splitPos < 0) continue; String key = line.substring(0, splitPos); - String value = line.substring(splitPos + KeyValueSplit.length()); - sectionKeyValue.get(sectionName).putIfAbsent(key, value); - keyValue.putIfAbsent(key, value); + String value = line.substring(splitPos + PairSplit.length()); + taggedPairs.get(sectionName).putIfAbsent(key, value); + allPairs.putIfAbsent(key, value); } } } @@ -162,28 +165,28 @@ public class SectionedKeyValueStore public void AddKeyValue(String sectionName, String key, String value) { AddSection(sectionName); - sectionKeyValue.get(sectionName).putIfAbsent(key, value); - keyValue.putIfAbsent(key, value); + taggedPairs.get(sectionName).putIfAbsent(key, value); + allPairs.putIfAbsent(key, value); } // Adds a given section to the hashmap if it's not already present public void AddSection(String sectionName) { - sectionKeyValue.putIfAbsent(sectionName, new HashMap()); + taggedPairs.putIfAbsent(sectionName, new HashMap()); } // Returns a HashMap of Keys to Values for a given section @SuppressWarnings("unchecked") public HashMap GetSection(String sectionName) { - return (HashMap) sectionKeyValue.get(sectionName).clone(); + return (HashMap) taggedPairs.get(sectionName).clone(); } // Look up a global key public String GetKey(String key) { - if(keyValue.containsKey(key)) - return keyValue.get(key); + if(allPairs.containsKey(key)) + return allPairs.get(key); return null; } diff --git a/src/main/Main.java b/src/main/Main.java index ff780a7..2b7bc6a 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -13,7 +13,6 @@ import net.dv8tion.jda.core.entities.*; import net.dv8tion.jda.core.events.message.guild.*; import net.dv8tion.jda.core.hooks.ListenerAdapter; import offline.*; -import core.Localizer; import utils.GlobalLog; import net.dv8tion.jda.core.*; @@ -26,21 +25,18 @@ public class Main extends ListenerAdapter // Variables and stuff private static JDA kitty; private static CommandManager commandManager; + private static CommandEnabler commandEnabler; private static DatabaseManager databaseManager; private static Stats stats; private static RPManager rpManager; - + // Main test location public static void main(String[] args) throws InterruptedException, LoginException, Exception { - // Localizer startup - Potentially integrate with the factory. Needs to happen first tho. - Localizer.UpdateLocFromDisk(); - Localizer.ScrapeAll(); - Localizer.SaveLocToDisk(); - - // Factory startup + // Factory startup. The ordering is intentional. databaseManager = ObjectBuilderFactory.ConstructDatabaseManager(); - commandManager = ObjectBuilderFactory.ConstructCommandManager(); + commandEnabler = ObjectBuilderFactory.ConstructCommandEnabler(); + commandManager = ObjectBuilderFactory.ConstructCommandManager(commandEnabler); rpManager = ObjectBuilderFactory.ConstructRPManager(); stats = ObjectBuilderFactory.ConstructStats(commandManager); diff --git a/src/utils/FileUtils.java b/src/utils/FileUtils.java index 4d3ef48..716fae3 100644 --- a/src/utils/FileUtils.java +++ b/src/utils/FileUtils.java @@ -1,5 +1,6 @@ package utils; +import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -11,6 +12,7 @@ import java.util.stream.Stream; public class FileUtils { // Reads all lines from a file as a string + public static String ReadContent(File file) { return ReadContent(file.toPath()); } public static String ReadContent(Path filePath) { StringBuilder contentBuilder = new StringBuilder(); @@ -24,7 +26,7 @@ public class FileUtils } catch (IOException e) { - e.printStackTrace(); + GlobalLog.Error(LogFilter.Util, e.getMessage()); } return contentBuilder.toString(); @@ -35,13 +37,18 @@ public class FileUtils { ArrayList items = new ArrayList(); + File tmpDir = new File(startingDir); + if(!tmpDir.exists()) + return new ArrayList(); + + try { Files.find(Paths.get(startingDir), 999, (path, attributes) -> attributes.isRegularFile()).forEach(items::add); } catch (IOException e) { - e.printStackTrace(); + GlobalLog.Error(LogFilter.Util, e.getMessage()); } return items; diff --git a/src/utils/GlobalLog.java b/src/utils/GlobalLog.java index f350d2d..2cf28b9 100644 --- a/src/utils/GlobalLog.java +++ b/src/utils/GlobalLog.java @@ -13,7 +13,7 @@ public class GlobalLog } public static void Log(String msg) { Write(log, LogFilter.Debug, msg); } - public static void Warn(String msg) {Write(warn, LogFilter.Debug, msg); } + public static void Warn(String msg) { Write(warn, LogFilter.Debug, msg); } public static void Error(String msg) { Write(error, LogFilter.Debug, msg); } public static void Fatal(String msg) throws Exception { Write(fatal, LogFilter.Debug, msg); throw new Exception(msg); } diff --git a/src/utils/ImageOverlayBuilder.java b/src/utils/ImageOverlayBuilder.java new file mode 100644 index 0000000..2ad0546 --- /dev/null +++ b/src/utils/ImageOverlayBuilder.java @@ -0,0 +1,294 @@ +package utils; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.RenderedImage; +import java.io.File; +import java.io.IOException; +import java.util.Calendar; +import java.util.Iterator; + +import javax.imageio.IIOException; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.stream.FileImageOutputStream; +import javax.imageio.stream.ImageOutputStream; + +// A class that overlays an image based on a series of frames that will be converted into a gif. +// The class targets a pixel with max Green value and no red or blue that's fully opaque (0, 255, 0) +// and then places the center of the overlay image on the specified location. Must be 32-bit PNGs with RGBA format. +public class ImageOverlayBuilder +{ + // Lets get some trash established for the yeet + public static final boolean VERBOSE = false; + public static final int NONE = -1; + public static final int PIXEL_BYTE_LENGTH = 4; // 32-bit PNG, RGBA + public static final int DEFAULT_FPS = 18; + public static final String FRAME_FILE_EXTENSION = ".png"; + public static final String LOG_HEADER = "[Overlay] "; + + // Logging intermediate functions + private static void Verbose(String str) { if(VERBOSE) Log("[Verbose] " + str); } + private static void Log(String str) { GlobalLog.Log(LogFilter.Util, LOG_HEADER + str); } + private static void Warn(String str) { GlobalLog.Warn(LogFilter.Util, LOG_HEADER + str); } + private static void Error(String str) { GlobalLog.Error(LogFilter.Util, LOG_HEADER + str); } + + // Local variables + private final String basePath; // The folder location of the files + private final String baseName; // This is the consistent part of the filename of each frame, for example "image " + private final int frameCount; // The number of frames in the image + private final int fps; // This doesn't quite line up, multiples of 10 are as specific as it gets. + + // Required minimal constructor + public ImageOverlayBuilder(String basePath, String baseName, int frameCount) + { + this(basePath, baseName, frameCount, DEFAULT_FPS); + } + + // Constructor with framerate specification + public ImageOverlayBuilder(String basePath, String baseName, int frameCount, int fps) + { + this.basePath = basePath; + this.baseName = baseName; + this.frameCount = frameCount; + this.fps = fps; + } + + // Performs a per-frame overlay, catches IO errors as a note.) + public void Overlay(BufferedImage overlay, String outpath) + { + try + { + long start = Calendar.getInstance().getTimeInMillis(); + + ProcessOverlay(overlay, outpath); + + long end = Calendar.getInstance().getTimeInMillis(); + Log("Took " + (end - start) + "ms"); + } + catch (IOException e) + { + Error(e.getMessage()); + } + } + + // Processing the image frames to construct a gif. Relies on (0,255,0) pixel for image center specification. + private void ProcessOverlay(BufferedImage overlay, String outfileName) throws IOException + { + BufferedImage[] frames = new BufferedImage[frameCount]; + + for(int i = 0; i < frameCount; ++i) + { + BufferedImage out = CombineImages(basePath + baseName + i + FRAME_FILE_EXTENSION , overlay); + + if(out != null) + frames[i] = out; + else + Error("There was an issue with overlaying frame " + i); + } + + Verbose("Processed " + frameCount + " frames, writing..."); + ImageOutputStream output = new FileImageOutputStream(new File(outfileName)); + GifSequenceWriter writer = new GifSequenceWriter(output, frames[0].getType(), fps, true); + + for(int i = 0; i < frameCount; ++i) + writer.writeToSequence(frames[i]); + + writer.close(); + output.close(); + } + + // Performs an overlay at a pixel location. We're making some assumptions here, mostly that there is going + // to be an RGBA-32-bit encoded PNG image read in for our parsing purposes. We then look for a 0, 255, 0 + // green pixel on the base frame to apply the overlay buffer to, centered. + private BufferedImage CombineImages(String pathBase, BufferedImage overlay) throws IOException + { + // Acquire images + BufferedImage imageBase = null; + BufferedImage imageOverlay = overlay; + + imageBase = ImageIO.read(new File(pathBase)); + + // Grab data we know won't change. As a side note, I discovered you can get specific pixels a bit + // differently later, but it was too late, I wrote the pixel specific code already. + final byte[] pixelsBase = ((DataBufferByte) imageBase.getRaster().getDataBuffer()).getData(); + final int baseWidth = imageBase.getWidth(); + final int overlayWidth = imageOverlay.getWidth(); + final int baseHeight = imageBase.getHeight(); + final int overlayHeight = imageOverlay.getHeight(); + + // Warn about odd sizing when applicable + if(overlayHeight > baseHeight || overlayWidth > baseWidth) + Warn("Size mismatch, overlay is larger. May function, but not supported."); + + // Skim base picture for solid green pixel to use as target center + int targetX = NONE; + int targetY = NONE; + for(int i = 0; i < pixelsBase.length; i += PIXEL_BYTE_LENGTH) + { + final int x = ((i / PIXEL_BYTE_LENGTH) % baseWidth); + final int y = ((i / PIXEL_BYTE_LENGTH) / baseWidth); + + final int r = (pixelsBase[i]); + final int g = (pixelsBase[i + 1]); + final int b = (pixelsBase[i + 2]); + //final int a = (pixelsBase[i + 3]); + + // Max contrast in 32-bit PNG for green is no red no blue, max green (ratio), max alpha (implied 0 here) + if(r == -1 && g == 0 && b == -1) + { + //Log("Found target pixel at x: " + x + " y: " + y); + targetX = x; + targetY = y; + break; + } + } + + // Skip overlay if we have no target location + if(targetX == NONE || targetY == NONE) + { + Verbose("No overlay required for this frame."); + return imageBase; + } + + // Re-create a new byte array and establish overlay bounds + final int left = targetX - overlayWidth / 2; + final int right = targetX + overlayWidth / 2; + final int top = targetY - overlayHeight / 2; + final int bottom = targetY + overlayHeight / 2; + + // Apply overlay when appropriate + for(int i = 0; i < pixelsBase.length; i += PIXEL_BYTE_LENGTH) + { + final int x = ((i / PIXEL_BYTE_LENGTH) % baseWidth); + final int y = ((i / PIXEL_BYTE_LENGTH) / baseWidth); + + // If we're within the bounds of where the overlay picture should go... + if(x > left && x < right && y > top && y < bottom) + { + final int overlayX = x - left; + final int overlayY = y - top; + + // Skip out of bounds pixels + if(overlayX < 0 || overlayY < 0 || overlayX >= baseWidth || overlayY >= baseHeight) + continue; + + // Re-write bytes as overlay + imageBase.setRGB(x, y, imageOverlay.getRGB(overlayX, overlayY)); + } + } + + // Give the frame back + return imageBase; + } + + + // GifSequenceWriter.java + // + // Created by Elliot Kroo on 2009-04-25, + // (Small modifications by wisp in 2018) + // + // This work is licensed under the Creative Commons Attribution 3.0 Unported License. + // To view a copy of this license visit http://creativecommons.org/licenses/by/3.0/ + // NOTE: ^ This is Elliot's original license + private static class GifSequenceWriter + { + protected ImageWriter gifWriter; + protected ImageWriteParam imageWriteParam; + protected IIOMetadata imageMetaData; + + // NOTE: This is limited to things that divide into 1000 cleanly as multiples of 10. + public GifSequenceWriter(ImageOutputStream outputStream, int imageType, int framesPerSecond, boolean isLooping) throws IIOException, IOException + { + gifWriter = getWriter(); + imageWriteParam = gifWriter.getDefaultWriteParam(); + ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType); + + imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam); + + String metaFormatName = imageMetaData.getNativeMetadataFormatName(); + + IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName); + IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension"); + graphicsControlExtensionNode.setAttribute("disposalMethod", "none"); + graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE"); + graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE"); + graphicsControlExtensionNode.setAttribute("delayTime", "" + (int) ((1000.0 / framesPerSecond) / 10.0)); // THis line isn't super well honored + graphicsControlExtensionNode.setAttribute("transparentColorIndex","0"); + + IIOMetadataNode appEntensionsNode = getNode( root, "ApplicationExtensions"); + IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension"); + child.setAttribute("applicationID", "NETSCAPE"); + child.setAttribute("authenticationCode", "2.0"); + + int loopValue = isLooping ? 0 : 1; + child.setUserObject(new byte[]{ 0x1, (byte) (loopValue & 0xFF), (byte) ((loopValue >> 8) & 0xFF)}); + appEntensionsNode.appendChild(child); + + imageMetaData.setFromTree(metaFormatName, root); + + gifWriter.setOutput(outputStream); + gifWriter.prepareWriteSequence(null); + } + + public void writeToSequence(RenderedImage img) throws IOException + { + gifWriter.writeToSequence(new IIOImage(img, null, imageMetaData), imageWriteParam); + } + + /** + * Close this GifSequenceWriter object. This does not close the underlying + * stream, just finishes off the GIF. + */ + public void close() throws IOException + { + gifWriter.endWriteSequence(); + } + + /** + * Returns the first available GIF ImageWriter using + * ImageIO.getImageWritersBySuffix("gif"). + * + * @return a GIF ImageWriter object + * @throws IIOException if no GIF image writers are returned + */ + private static ImageWriter getWriter() throws IIOException + { + Iterator iter = ImageIO.getImageWritersBySuffix("gif"); + + if(!iter.hasNext()) + throw new IIOException("No GIF Image Writers Exist"); + else + return iter.next(); + } + + /** + * Returns an existing child node, or creates and returns a new child node (if + * the requested node does not exist). + * + * @param rootNode the IIOMetadataNode to search for the child node. + * @param nodeName the name of the child node. + * + * @return the child node, if found or a new node created with the given name. + */ + private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName) + { + int nodeCount = rootNode.getLength(); + for (int i = 0; i < nodeCount; i++) + { + if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0) + return((IIOMetadataNode) rootNode.item(i)); + } + + IIOMetadataNode node = new IIOMetadataNode(nodeName); + rootNode.appendChild(node); + + return(node); + } + } +} diff --git a/src/utils/LogFilter.java b/src/utils/LogFilter.java index eeb9d3a..22742fe 100644 --- a/src/utils/LogFilter.java +++ b/src/utils/LogFilter.java @@ -2,7 +2,8 @@ package utils; public enum LogFilter { - Debug(0), Command(1), Core(2), Database(4), Response(8), Network(16), Strings(32); //8, 16, 32... (flags, so we can | together later) + // Assign numbers as flags, so we can | ('or') them together as necessary + Debug(0), Command(1), Core(2), Util(4), Database(8), Response(16), Network(32), Strings(64); private final int value; private LogFilter(int value)