From b04e26cbc62f9d87cdc849a2fc5c8a8518288e78 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 6 Apr 2019 22:51:09 -0700 Subject: [PATCH 01/25] = Localized past testing files for indicator, choose, coliru, 8ball --- localization.config | 42 ++++++++++++++++++++++-- src/commands/CommandChangeIndicator.java | 5 +-- src/commands/CommandChoose.java | 4 +-- src/commands/CommandColiru.java | 3 +- src/commands/CommandDoWork.java | 4 +-- src/commands/CommandEightBall.java | 36 +++++++++++++++----- 6 files changed, 77 insertions(+), 17 deletions(-) diff --git a/localization.config b/localization.config index b810ae8..4f11193 100644 --- a/localization.config +++ b/localization.config @@ -1,21 +1,59 @@ +[CommandEightBall] +It is certain. = +Ask again later. = +Cannot predict now. = +My sources say no. = +You may rely on it. = +Concentrate and ask again. = +Signs point to yes. = +Most likely. = +Reply hazy, try again. = +Without a doubt. = +Very doubtful. = +It is decidedly so. = +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. = +Don't count on it. = +Yes. = +My reply is no. = +Yes - definitely. = +As I see it, yes. = +Better not tell you now. = +Outlook good. = +Outlook not so good. = + +[CommandColiru] +Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++. = + [CommandBeansShow] Displays how many beans you have = You have %s beans! = [CommandBetBeans] 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 = That's not a valid bet! = Sorry, you didn't win, try again! = +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 = You don't have enough beans! = You won %s beans! = +[CommandChangeIndicator] +Indicator changed to `%s` = +Changes the command indicator to any single character. By default, it's '!'. If more than one character is provided, the first one is used! = + [CommandBoop] -%s booped %s! = Kitty will react with a counter = +%s booped %s! = Woah! %s booped me! That's %s total! = %s booped several others - %s! = +[CommandChoose] +With an input of x,y,z where x y and z are all choices, kitty will choose one = +I chooooooose %s! = + +[CommandDoWork] +I finished with my work! :D = +Occupies a core for a few seconds = + [CommandBlurry] Blurs your icon or the icon of a friend you mentioned = diff --git a/src/commands/CommandChangeIndicator.java b/src/commands/CommandChangeIndicator.java index 0a7a725..da25d8d 100644 --- a/src/commands/CommandChangeIndicator.java +++ b/src/commands/CommandChangeIndicator.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.*; public class CommandChangeIndicator extends Command @@ -8,7 +9,7 @@ public class CommandChangeIndicator extends Command public CommandChangeIndicator(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "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 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!"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -21,6 +22,6 @@ public class CommandChangeIndicator extends Command } guild.SetCommandIndicator(arg.substring(0, 1)); - res.Call("Indicator changed to `" + guild.GetCommandIndicator() +"`!"); + res.Call(String.format(Localizer.Stub("Indicator changed to `%s`"), guild.GetCommandIndicator())); } } diff --git a/src/commands/CommandChoose.java b/src/commands/CommandChoose.java index d65672e..842e341 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 "With an input of x,y,z where x y and z are all choices, kitty will choose one"; } + 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"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -26,6 +26,6 @@ public class CommandChoose extends Command return; } - res.Call("I chooooooose" + choices[(int) (Math.random()*choices.length)] + "!"); + res.Call(String.format(Localizer.Stub("I chooooooose %s!"), (choices[(int) (Math.random()*choices.length)]).toString())); } } diff --git a/src/commands/CommandColiru.java b/src/commands/CommandColiru.java index 25145fa..d16e066 100644 --- a/src/commands/CommandColiru.java +++ b/src/commands/CommandColiru.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.*; import network.NetworkColiru; @@ -11,7 +12,7 @@ public class CommandColiru extends Command public CommandColiru(KittyRole level, KittyRating rating) { super(level, rating);} @Override - public String HelpText() { return "Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++."; } + public String HelpText() { return Localizer.Stub("Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++."); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) diff --git a/src/commands/CommandDoWork.java b/src/commands/CommandDoWork.java index e219695..b1466e3 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 "Occupies a core for a few seconds"; } + public String HelpText() { return Localizer.Stub("Occupies a core for a few seconds"); } // Called when the command is run! @Override @@ -28,6 +28,6 @@ public class CommandDoWork extends Command thispieceofshit += Math.log((double)i); } - res.Call("I finished with my work! :D"); + res.Call(Localizer.Stub("I finished with my work! :D")); } } \ No newline at end of file diff --git a/src/commands/CommandEightBall.java b/src/commands/CommandEightBall.java index 642e943..9ec450f 100644 --- a/src/commands/CommandEightBall.java +++ b/src/commands/CommandEightBall.java @@ -1,21 +1,41 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.*; public class CommandEightBall extends Command { - String [] answers = {"It is certain.", "It is decidedly so.", "Without a doubt.", "Yes - definitely.", "You may rely on it.", "As I see it, yes.", "Most likely.", - "Outlook good.", "Yes.", "Signs point to yes.", "Reply hazy, try again.", "Ask again later.", "Better not tell you now.", "Cannot predict now.", - "Concentrate and ask again.", "Don't count on it.", "My reply is no.", "My sources say no.", "Outlook not so good.", "Very doubtful."}; - public CommandEightBall(KittyRole level, KittyRating rating) + String [] answers = { - super(level, rating); - } + 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.") + + , 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.") + + , 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.") + }; + + public CommandEightBall(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "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 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."); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) From 9ea68605a4aaa25875c20d3eacc70980c9bba8b3 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 6 Apr 2019 23:02:16 -0700 Subject: [PATCH 02/25] = Localized beans, help, help builder, info, invite help builder localization currently will collapse for header titles. This isn't too big of a deal, but the word for 'commands' at least can be localized. --- localization.config | 57 +++++++++++++++++++--------- src/commands/CommandGiveBeans.java | 9 +++-- src/commands/CommandHelp.java | 8 +--- src/commands/CommandHelpBuilder.java | 5 ++- src/commands/CommandInfo.java | 6 +-- src/commands/CommandInvite.java | 3 +- 6 files changed, 55 insertions(+), 33 deletions(-) diff --git a/localization.config b/localization.config index 4f11193..f2268ef 100644 --- a/localization.config +++ b/localization.config @@ -1,25 +1,26 @@ [CommandEightBall] It is certain. = Ask again later. = -Cannot predict now. = My sources say no. = You may rely on it. = Concentrate and ask again. = +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. = +Without a doubt. = +It is decidedly so. = +My reply is no. = +As I see it, yes. = +Outlook good. = +Outlook not so good. = +Cannot predict now. = Signs point to yes. = Most likely. = Reply hazy, try again. = -Without a doubt. = Very doubtful. = -It is decidedly so. = 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. = Don't count on it. = Yes. = -My reply is no. = Yes - definitely. = -As I see it, yes. = Better not tell you now. = -Outlook good. = -Outlook not so good. = [CommandColiru] Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++. = @@ -31,29 +32,51 @@ You have %s beans! = [CommandBetBeans] Please bet with at least 50 beans! = That's not a valid bet! = +You won %s beans! = Sorry, you didn't win, try again! = 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 = You don't have enough beans! = -You won %s beans! = [CommandChangeIndicator] -Indicator changed to `%s` = 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` = + +[CommandHelpBuilder] +commands = +Emit help for all commands as formatted HTML = + +[CommandDoWork] +I finished with my work! = D = +I finished with my work! :D = +Occupies a core for a few seconds = [CommandBoop] -Kitty will react with a counter = %s booped %s! = Woah! %s booped me! That's %s total! = +Kitty will react with a counter = %s booped several others - %s! = +[CommandInvite] +Provies a direct invite link for KittyBot = + +[CommandInfo] +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/ = +Provides author info and a link to Kitty's website = + +[CommandBlurry] +Blurs your icon or the icon of a friend you mentioned = + +[CommandHelp] +You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` = +Lets you look up specific commands, or get a link to a list of all commands. = + +[CommandGiveBeans] +That's not a valid number! = +Gave %s %s beans! = +Gives beans to the mentioned users! = +You didn't mention anyone! = + [CommandChoose] With an input of x,y,z where x y and z are all choices, kitty will choose one = I chooooooose %s! = -[CommandDoWork] -I finished with my work! :D = -Occupies a core for a few seconds = - -[CommandBlurry] -Blurs your icon or the icon of a friend you mentioned = - diff --git a/src/commands/CommandGiveBeans.java b/src/commands/CommandGiveBeans.java index 5f9a7a1..e22cc28 100644 --- a/src/commands/CommandGiveBeans.java +++ b/src/commands/CommandGiveBeans.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.*; public class CommandGiveBeans extends Command @@ -8,7 +9,7 @@ public class CommandGiveBeans extends Command public CommandGiveBeans (KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Gives beans to the mentioned users!"; } + public String HelpText() { return Localizer.Stub("Gives beans to the mentioned users!"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -19,20 +20,20 @@ public class CommandGiveBeans extends Command } catch (NumberFormatException e) { - res.Call("That's not a valid number!"); + res.Call(Localizer.Stub("That's not a valid number!")); return; } if(input.mentions == null) { - res.Call("You didn't mention anyone!"); + res.Call(Localizer.Stub("You didn't mention anyone!")); return; } for(int i = 0; i < input.mentions.length; i++) { input.mentions[i].ChangeBeans(beans); - res.Call("Gave " + input.mentions[i].name + " " + beans + " beans!"); + res.Call(String.format(Localizer.Stub("Gave %s %s beans!"), input.mentions[i].name, "" + beans)); } } } diff --git a/src/commands/CommandHelp.java b/src/commands/CommandHelp.java index 580554b..cb3ec42 100644 --- a/src/commands/CommandHelp.java +++ b/src/commands/CommandHelp.java @@ -16,7 +16,7 @@ public class CommandHelp extends Command public CommandHelp(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Lets you look up specific commands, or get a link to a list of all commands."; } + public String HelpText() { return Localizer.Stub("Lets you look up specific commands, or get a link to a list of all commands."); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -25,11 +25,7 @@ public class CommandHelp extends Command if(help == null) { - help = "You can get help with a specific command by typing `!help command`!" - + "\nYou can also look at " - + "\nGeneral Commands: `boop, roll, choose, help, info, vote, " - + "results, showpoll, wolfram, cplus, java," - + "beans, role, bet, yeet`"; + help = Localizer.Stub("You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`"); } else { diff --git a/src/commands/CommandHelpBuilder.java b/src/commands/CommandHelpBuilder.java index 968b949..9b77b55 100644 --- a/src/commands/CommandHelpBuilder.java +++ b/src/commands/CommandHelpBuilder.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.HashMap; import core.Command; +import core.Localizer; import core.Stats; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -25,7 +26,7 @@ public class CommandHelpBuilder extends Command { } @Override - public String HelpText() { return "Emit help for all commands as formatted HTML"; } + public String HelpText() { return Localizer.Stub("Emit help for all commands as formatted HTML"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -95,7 +96,7 @@ public class CommandHelpBuilder extends Command { roleStr = roleStr.substring(0, 1).toUpperCase() + roleStr.toLowerCase().substring(1); // Section header - accumulated += headerStart + roleStr + " commands" + headerEnd; + accumulated += headerStart + roleStr + " " + Localizer.Stub("commands") + headerEnd; accumulated += sectionStart; // Section content diff --git a/src/commands/CommandInfo.java b/src/commands/CommandInfo.java index 99ae8b8..568ad14 100644 --- a/src/commands/CommandInfo.java +++ b/src/commands/CommandInfo.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -14,13 +15,12 @@ public class CommandInfo extends Command public CommandInfo(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Provides author info and a link to Kitty's website"; } + public String HelpText() { return Localizer.Stub("Provides author info and a link to Kitty's website"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { - String info = "I'm made by `Rin#8904` and `Reverie Wisp#3703`!\n" - + "You 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/" ; + String info = Localizer.Stub("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/"); res.Call(info); } } \ No newline at end of file diff --git a/src/commands/CommandInvite.java b/src/commands/CommandInvite.java index 3bcb6a4..75080e4 100644 --- a/src/commands/CommandInvite.java +++ b/src/commands/CommandInvite.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.*; import offline.Ref; @@ -9,7 +10,7 @@ public class CommandInvite extends Command public CommandInvite(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Provies a direct invite link for KittyBot"; } + public String HelpText() { return Localizer.Stub("Provies a direct invite link for KittyBot"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) From e5a40ae329a232611d74af2f2a14896129f6ba66 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 6 Apr 2019 23:22:13 -0700 Subject: [PATCH 03/25] = Doodle, Map, Perish, Ping, Manage --- localization.config | 38 +++++++++++++++++++++++------ src/commands/CommandJDoodle.java | 3 ++- src/commands/CommandMap.java | 11 ++++++--- src/commands/CommandPerish.java | 3 ++- src/commands/CommandPing.java | 4 +-- src/commands/CommandPollManage.java | 2 +- 6 files changed, 44 insertions(+), 17 deletions(-) diff --git a/localization.config b/localization.config index f2268ef..e8bbecf 100644 --- a/localization.config +++ b/localization.config @@ -25,6 +25,9 @@ Better not tell you now. = [CommandColiru] Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++. = +[CommandPerish] +Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned = + [CommandBeansShow] Displays how many beans you have = You have %s beans! = @@ -37,14 +40,36 @@ Sorry, you didn't win, try again! = 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 = You don't have enough beans! = +[CommandPing] +Pong! = +Will respond with Pong! = + [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` = +[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 = + [CommandHelpBuilder] commands = Emit help for all commands as formatted HTML = +[CommandInfo] +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/ = +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/ = +Provides author info and a link to Kitty's website = + +[CommandJDoodle] +Will compile any java code you put in! Supports Java 1.8 = + +[CommandMap] +Invalid arguments provided! = +Seed = +Using mapgen v0.1 = +Height = +Width = + [CommandDoWork] I finished with my work! = D = I finished with my work! :D = @@ -56,20 +81,17 @@ Woah! %s booped me! That's %s total! = Kitty will react with a counter = %s booped several others - %s! = +[CommandHelp] +You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` = +You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` = +Lets you look up specific commands, or get a link to a list of all commands. = + [CommandInvite] Provies a direct invite link for KittyBot = -[CommandInfo] -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/ = -Provides author info and a link to Kitty's website = - [CommandBlurry] Blurs your icon or the icon of a friend you mentioned = -[CommandHelp] -You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` = -Lets you look up specific commands, or get a link to a list of all commands. = - [CommandGiveBeans] That's not a valid number! = Gave %s %s beans! = diff --git a/src/commands/CommandJDoodle.java b/src/commands/CommandJDoodle.java index a2add42..9d7b146 100644 --- a/src/commands/CommandJDoodle.java +++ b/src/commands/CommandJDoodle.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.*; import network.NetworkJDoodle; @@ -11,7 +12,7 @@ public class CommandJDoodle extends Command public CommandJDoodle(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Will compile any java code you put in! Supports Java 1.8"; } + public String HelpText() { return Localizer.Stub("Will compile any java code you put in! Supports Java 1.8"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) diff --git a/src/commands/CommandMap.java b/src/commands/CommandMap.java index d4fb4a9..02aca37 100644 --- a/src/commands/CommandMap.java +++ b/src/commands/CommandMap.java @@ -3,6 +3,7 @@ package commands; import java.util.Random; import core.Command; +import core.Localizer; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -22,7 +23,7 @@ public class CommandMap extends Command public CommandMap(KittyRole roleLevel, KittyRating contentRating) { super(roleLevel, contentRating); } @Override - public String HelpText() { return "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 "+ MaxWidth + "),\nDefault Height: 25(max " + MaxHeight + ")"; } + 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); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -59,7 +60,7 @@ public class CommandMap extends Command } catch(NumberFormatException e) { - res.Call("Invalid arguments provided!"); + res.Call(Localizer.Stub("Invalid arguments provided!")); return; } @@ -75,8 +76,10 @@ public class CommandMap extends Command } // Response header creation - header += "Using mapgen v0.1\n"; - header += "Seed: `" + seed + "`, Width: `"+ width +"`, Height: `"+ height + "`\n"; + header += Localizer.Stub("Using mapgen v0.1") + "\n"; + header += Localizer.Stub("Seed") + ": `" + seed + "`, "; + header += Localizer.Stub("Width") + "`"+ width +"`, "; + header += Localizer.Stub("Height") + ": `"+ height + "`\n"; // Response body creation body += "```\n"; diff --git a/src/commands/CommandPerish.java b/src/commands/CommandPerish.java index 475c099..b51080e 100644 --- a/src/commands/CommandPerish.java +++ b/src/commands/CommandPerish.java @@ -8,6 +8,7 @@ import java.io.IOException; import javax.imageio.ImageIO; import core.Command; +import core.Localizer; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -22,7 +23,7 @@ public class CommandPerish extends Command public CommandPerish(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "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 Localizer.Stub("Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned"); }; private static Long num = 0l; diff --git a/src/commands/CommandPing.java b/src/commands/CommandPing.java index 137d3a9..51b6212 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 "Will respond with Pong!"; } + public String HelpText() { return Localizer.Stub("Will respond with Pong!"); } // Called when the command is run! @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { - res.Call("Pong!"); + res.Call(Localizer.Stub("Pong!")); } } diff --git a/src/commands/CommandPollManage.java b/src/commands/CommandPollManage.java index 33230a0..a1d9976 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 "'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 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"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) From 52afd92db1bfc257584e1dc9e4f609fb7caadab3 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 6 Apr 2019 23:41:06 -0700 Subject: [PATCH 04/25] + Added poll results, poll show, poll vote, rating, role --- localization.config | 29 ++++++++++++++++++++++++++++ src/commands/CommandPollResults.java | 5 ++--- src/commands/CommandPollShow.java | 8 ++++---- src/commands/CommandPollVote.java | 13 +++++++------ src/commands/CommandRating.java | 9 +++++---- src/commands/CommandRole.java | 11 ++++++----- 6 files changed, 53 insertions(+), 22 deletions(-) diff --git a/localization.config b/localization.config index e8bbecf..c2f20c3 100644 --- a/localization.config +++ b/localization.config @@ -40,6 +40,19 @@ Sorry, you didn't win, try again! = 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 = You don't have enough beans! = +[CommandRole] +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. = +Changed %s to role `%s`! = +You aren't allowed to do that! You must have the KittyRole '%' or higher! = +Please enter `general`, `mod`, or `admin`! = +Your role is = + +[CommandPollShow] +There is no poll running! = +And the choices are:\n = +Will show the current poll running = +The current poll is `%s`\n = + [CommandPing] Pong! = Will respond with Pong! = @@ -55,6 +68,18 @@ Indicator changed to `%s` = commands = Emit help for all commands as formatted HTML = +[CommandPollVote] +You successfully voted for = +You already voted = +That's not a vaild number! = +%s That's not a vaild vote! = +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! = + +[CommandRating] +Kittybot content set to = +Warning: NSFW may slip through, images are only based on tags on their respective sites! = +Invalid content rating = + [CommandInfo] 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/ = 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/ = @@ -75,6 +100,10 @@ I finished with my work! = D = I finished with my work! :D = Occupies a core for a few seconds = +[CommandPollResults] +Will show current results of a poll and percentages of votes per choice = +%s people voted for %s `%s` with `%s%` !\n = + [CommandBoop] %s booped %s! = Woah! %s booped me! That's %s total! = diff --git a/src/commands/CommandPollResults.java b/src/commands/CommandPollResults.java index 8178955..3312009 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 "Will show current results of a poll and percentages of votes per choice"; } + public String HelpText() { return Localizer.Stub("Will show current results of a poll and percentages of votes per choice"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -26,8 +26,7 @@ public class CommandPollResults extends Command for(int i = 0; i < votes.size(); i++) { - - results += votes.get(i).votes + " people voted for `" + votes.get(i).choice + "` with `" + (int)(((double)votes.get(i).votes) / ((double)totalVotes) * 100) + "%`!\n"; + 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)); } res.Call(results); diff --git a/src/commands/CommandPollShow.java b/src/commands/CommandPollShow.java index 46df883..06c3a1c 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 "Will show the current poll running"; } + public String HelpText() { return Localizer.Stub("Will show the current poll running"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { if(!guild.polling) { - res.Call("There is no poll running!"); + res.Call(Localizer.Stub("There is no poll running!")); return; } - String poll = "The current poll is `" + guild.poll + "`\n"; - poll += "And the choices are:\n"; + String poll = String.format(Localizer.Stub("The current poll is `%s`\n"), guild.poll); + poll += Localizer.Stub("And the choices are:\n"); 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 120b371..761ff67 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 "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 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!"); } @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("You already voted"); + res.Call(Localizer.Stub("You already voted")); return; } try @@ -25,21 +25,22 @@ public class CommandPollVote extends Command int voteNum = Integer.parseInt(input.args)-1; if(voteNum >= guild.choices.size() || voteNum < 0) { - res.Call(voteNum + " That's not a vaild vote!"); + res.Call(String.format(Localizer.Stub("%s That's not a vaild vote!"), voteNum)); return; } + KittyPoll polled = guild.choices.get(voteNum); polled.votes++; guild.hasVoted.add(user.uniqueID); - res.Call("You successfully voted for `" + polled.choice + "`!"); + res.Call(Localizer.Stub("You successfully voted for") + " `" + polled.choice + "`!"); return; } catch (NumberFormatException e) { - res.Call("That's not a vaild number!"); + res.Call(Localizer.Stub("That's not a vaild number!")); return; } } - res.Call("There is no poll running!"); + res.Call(Localizer.Stub("There is no poll running!")); } } diff --git a/src/commands/CommandRating.java b/src/commands/CommandRating.java index c2a09c2..8ca7a6d 100644 --- a/src/commands/CommandRating.java +++ b/src/commands/CommandRating.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -14,7 +15,7 @@ public class CommandRating extends Command public CommandRating(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "'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 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."); } // Called when the command is run! @Override @@ -54,11 +55,11 @@ public class CommandRating extends Command } if(newRating != null) - res.Call("Kittybot content set to " + newRating); + res.Call(Localizer.Stub("Kittybot content set to") + " " + newRating); else - res.Call("Invalid content rating `" + input.args + "`"); + res.Call(Localizer.Stub("Invalid content rating") + " `" + input.args + "`"); if(newRating.equals("Filtered")) - res.Call("Warning: NSFW may slip through, images are only based on tags on their respective sites!"); + res.Call(Localizer.Stub("Warning: NSFW may slip through, images are only based on tags on their respective sites!")); } } \ No newline at end of file diff --git a/src/commands/CommandRole.java b/src/commands/CommandRole.java index 196ddda..8497e27 100644 --- a/src/commands/CommandRole.java +++ b/src/commands/CommandRole.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.*; public class CommandRole extends Command @@ -8,20 +9,20 @@ public class CommandRole extends Command public CommandRole (KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "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 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."); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { if(input.args.isEmpty()) { - res.Call("Your role is " + user.GetRole().name() + "!"); + res.Call(Localizer.Stub("Your role is") + " " + user.GetRole().name() + "!"); return; } if(user.GetRole().getValue() < KittyRole.Admin.getValue()) { - res.Call("You aren't allowed to do that! You must have the KittyRole '" + KittyRole.Admin.toString() + "' or higher!"); + res.Call(String.format(Localizer.Stub("You aren't allowed to do that! You must have the KittyRole '%' or higher!"), KittyRole.Admin.toString())); return; } @@ -45,7 +46,7 @@ public class CommandRole extends Command break; default: - res.Call("Please enter `general`, `mod`, or `admin`!"); + res.Call(Localizer.Stub("Please enter `general`, `mod`, or `admin`!")); return; } String users = ""; @@ -55,6 +56,6 @@ public class CommandRole extends Command users += input.mentions[i].name + " "; } - res.Call("Changed " + users + " to role `" + newRole.name() + "`!"); + res.Call(String.format(Localizer.Stub("Changed %s to role `%s`!"), users, newRole.name())); } } From 1bdbfbac177888313ee6f503a827882443c450b1 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 6 Apr 2019 23:45:41 -0700 Subject: [PATCH 05/25] + Added roll, RPEnd, RPG, RPStart, Shutdown --- localization.config | 148 +++++++++++++++++------------- src/commands/CommandRPEnd.java | 17 +++- src/commands/CommandRPG.java | 5 +- src/commands/CommandRPStart.java | 3 +- src/commands/CommandRoll.java | 4 +- src/commands/CommandShutdown.java | 7 +- 6 files changed, 109 insertions(+), 75 deletions(-) diff --git a/localization.config b/localization.config index c2f20c3..a6b2dea 100644 --- a/localization.config +++ b/localization.config @@ -1,25 +1,25 @@ [CommandEightBall] -It is certain. = Ask again later. = My sources say no. = You may rely on it. = -Concentrate and ask again. = 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. = Without a doubt. = -It is decidedly so. = My reply is no. = +Signs point to yes. = +Reply hazy, try again. = +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. = +Yes. = +Yes - definitely. = +It is certain. = +Concentrate and ask again. = +It is decidedly so. = As I see it, yes. = Outlook good. = Outlook not so good. = Cannot predict now. = -Signs point to yes. = Most likely. = -Reply hazy, try again. = Very doubtful. = -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. = Don't count on it. = -Yes. = -Yes - definitely. = Better not tell you now. = [CommandColiru] @@ -32,100 +32,124 @@ Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you menti Displays how many beans you have = You have %s beans! = +[CommandPollResults] +%s people voted for %s `%s` with `%s%` !\n = +Will show current results of a poll and percentages of votes per choice = +%s people voted for %s `%s` with `%s%` !\n = + +[CommandShutdown] +Forced immediate shutdown, threads abandoned without sync. = +Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown. = +Forced shutdown, database synced before abandoning threads. = + [CommandBetBeans] -Please bet with at least 50 beans! = That's not a valid bet! = +You don't have enough beans! = +Please bet with at least 50 beans! = You won %s beans! = Sorry, you didn't win, try again! = 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 = -You don't have enough beans! = [CommandRole] -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. = -Changed %s to role `%s`! = You aren't allowed to do that! You must have the KittyRole '%' or higher! = Please enter `general`, `mod`, or `admin`! = Your role is = - -[CommandPollShow] -There is no poll running! = -And the choices are:\n = -Will show the current poll running = -The current poll is `%s`\n = - -[CommandPing] -Pong! = -Will respond with Pong! = +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. = +Changed %s to role `%s`! = [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` = -[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 = - -[CommandHelpBuilder] -commands = -Emit help for all commands as formatted HTML = +[CommandMap] +Invalid arguments provided! = +Using mapgen v0.1 = +Width = +Seed = +Height = [CommandPollVote] -You successfully voted for = You already voted = That's not a vaild number! = %s That's not a vaild vote! = 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! = - -[CommandRating] -Kittybot content set to = -Warning: NSFW may slip through, images are only based on tags on their respective sites! = -Invalid content rating = - -[CommandInfo] -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/ = -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/ = -Provides author info and a link to Kitty's website = - -[CommandJDoodle] -Will compile any java code you put in! Supports Java 1.8 = - -[CommandMap] -Invalid arguments provided! = -Seed = -Using mapgen v0.1 = -Height = -Width = +You successfully voted for = [CommandDoWork] I finished with my work! = D = I finished with my work! :D = Occupies a core for a few seconds = -[CommandPollResults] -Will show current results of a poll and percentages of votes per choice = -%s people voted for %s `%s` with `%s%` !\n = - -[CommandBoop] -%s booped %s! = -Woah! %s booped me! That's %s total! = -Kitty will react with a counter = -%s booped several others - %s! = - [CommandHelp] You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` = You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` = Lets you look up specific commands, or get a link to a list of all commands. = -[CommandInvite] -Provies a direct invite link for KittyBot = +[CommandPing] +Will respond with Pong! = +Pong! = + +[CommandBoop] +Woah! %s booped me! That's %s total! = +%s booped several others - %s! = +%s booped %s! = +Kitty will react with a counter = + +[CommandInfo] +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/ = +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/ = +Provides author info and a link to Kitty's website = [CommandBlurry] Blurs your icon or the icon of a friend you mentioned = +[CommandHelpBuilder] +Emit help for all commands as formatted HTML = +commands = + +[CommandRating] +Warning = NSFW may slip through, images are only based on tags on their respective sites! = +Kittybot content set to = +Warning: NSFW may slip through, images are only based on tags on their respective sites! = +Invalid content rating = + +[CommandRPEnd] +Here's your file! = +You can't end this RP! = +Ends RP in channel = + +[CommandPollShow] +Will show the current poll running = +The current poll is `%s`\n = +And the choices are = \n = +There is no poll running! = +And the choices are:\n = + [CommandGiveBeans] That's not a valid number! = -Gave %s %s beans! = Gives beans to the mentioned users! = You didn't mention anyone! = +Gave %s %s beans! = + +[CommandRPG] +Admin+ command only right now - experimental text RPG! Format is !rpg = +Invalid RPG Command! = + +[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 = + +[CommandRPStart] +Starts an rp, add people to it by mentioning them! = + +[CommandJDoodle] +Will compile any java code you put in! Supports Java 1.8 = + +[CommandRoll] +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 = +Didn't work ;3; = + +[CommandInvite] +Provies a direct invite link for KittyBot = [CommandChoose] With an input of x,y,z where x y and z are all choices, kitty will choose one = diff --git a/src/commands/CommandRPEnd.java b/src/commands/CommandRPEnd.java index 1f97c5f..5fa72b3 100644 --- a/src/commands/CommandRPEnd.java +++ b/src/commands/CommandRPEnd.java @@ -5,6 +5,7 @@ import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import core.Command; +import core.Localizer; import core.RPManager; import dataStructures.*; @@ -13,24 +14,30 @@ public class CommandRPEnd extends Command public CommandRPEnd (KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Ends RP in channel"; } + public String HelpText() { return Localizer.Stub("Ends RP in channel"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { File sending = null; - try { + + try + { sending = RPManager.instance.endRP(channel, user); - } catch (FileNotFoundException | UnsupportedEncodingException e) + } + catch (FileNotFoundException | UnsupportedEncodingException e) { System.out.println("I don't know how you got here"); } + if(sending != null) { res.CallFile(sending, "txt"); - res.Call("Here's your file!"); + res.Call(Localizer.Stub("Here's your file!")); } else - res.Call("You can't end this RP!"); + { + res.Call(Localizer.Stub("You can't end this RP!")); + } } } diff --git a/src/commands/CommandRPG.java b/src/commands/CommandRPG.java index dd2273c..255d460 100644 --- a/src/commands/CommandRPG.java +++ b/src/commands/CommandRPG.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import core.rpg.RPGFramework; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -22,7 +23,7 @@ public class CommandRPG extends Command } @Override - public String HelpText() { return "Admin+ command only right now - experimental text RPG! Format is !rpg "; }; + public String HelpText() { return Localizer.Stub("Admin+ command only right now - experimental text RPG! Format is !rpg "); }; @Override @@ -42,7 +43,7 @@ public class CommandRPG extends Command if(result == null) { - res.Call("Invalid RPG Command!"); + res.Call(Localizer.Stub("Invalid RPG Command!")); return; } diff --git a/src/commands/CommandRPStart.java b/src/commands/CommandRPStart.java index dce9b3b..4045a4f 100644 --- a/src/commands/CommandRPStart.java +++ b/src/commands/CommandRPStart.java @@ -3,6 +3,7 @@ package commands; import java.util.ArrayList; import core.Command; +import core.Localizer; import core.RPManager; import dataStructures.*; @@ -11,7 +12,7 @@ public class CommandRPStart extends Command public CommandRPStart (KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Starts an rp, add people to it by mentioning them!"; } + public String HelpText() { return Localizer.Stub("Starts an rp, add people to it by mentioning them!"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) diff --git a/src/commands/CommandRoll.java b/src/commands/CommandRoll.java index d2f11b2..fd7e7f6 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 "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 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"); } @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("Didn't work ;3;"); + res.Call(Localizer.Stub("Didn't work ;3;")); } } diff --git a/src/commands/CommandShutdown.java b/src/commands/CommandShutdown.java index 7339c51..0963d7a 100644 --- a/src/commands/CommandShutdown.java +++ b/src/commands/CommandShutdown.java @@ -2,6 +2,7 @@ package commands; import core.Command; import core.DatabaseManager; +import core.Localizer; import core.Stats; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -17,7 +18,7 @@ public class CommandShutdown extends Command public CommandShutdown(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown."; } + public String HelpText() { return Localizer.Stub("Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown."); } // Called when the command is run! @Override @@ -41,12 +42,12 @@ public class CommandShutdown extends Command if(isSafe) { DatabaseManager.instance.Upkeep(); // Force upkeep, this works so long as on main thread. - res.CallImmediate("Forced shutdown, database synced before abandoning threads."); + res.CallImmediate(Localizer.Stub("Forced shutdown, database synced before abandoning threads.")); System.exit(0); } else { - res.CallImmediate("Forced immediate shutdown, threads abandoned without sync."); + res.CallImmediate(Localizer.Stub("Forced immediate shutdown, threads abandoned without sync.")); System.exit(0); } } From aa415e8e76735218d426bdaf7dcb6cb63358a60b Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 6 Apr 2019 23:49:08 -0700 Subject: [PATCH 06/25] + Added Stark, Stats, Tweet (stubbed only), Wolfram, Yeet --- localization.config | 17 +++++++++++++++++ src/commands/CommandStark.java | 3 ++- src/commands/CommandStats.java | 3 ++- src/commands/CommandTweet.java | 5 +++-- src/commands/CommandWolfram.java | 7 ++++--- src/commands/CommandYeet.java | 3 ++- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/localization.config b/localization.config index a6b2dea..b52e3e6 100644 --- a/localization.config +++ b/localization.config @@ -61,6 +61,12 @@ Changed %s to role `%s`! = 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` = +[CommandTweet] +FUCKED UP HARD = + +[CommandStats] +Displays the actively running KittyBot application information = + [CommandMap] Invalid arguments provided! = Using mapgen v0.1 = @@ -131,16 +137,27 @@ Gives beans to the mentioned users! = You didn't mention anyone! = Gave %s %s beans! = +[CommandWolfram] +Will query wolframalpha with your question and give a full image output of the answer = +Something went wrong! = +You need to provide some arguments! = + [CommandRPG] Admin+ command only right now - experimental text RPG! Format is !rpg = Invalid RPG Command! = +[CommandYeet] +Yeet yourself or yeet a friend with @! = + [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 = [CommandRPStart] Starts an rp, add people to it by mentioning them! = +[CommandStark] +Snaps your icon or the icon of a friend you mentioned = + [CommandJDoodle] Will compile any java code you put in! Supports Java 1.8 = diff --git a/src/commands/CommandStark.java b/src/commands/CommandStark.java index d27fa04..3507c3d 100644 --- a/src/commands/CommandStark.java +++ b/src/commands/CommandStark.java @@ -8,6 +8,7 @@ import java.io.IOException; import javax.imageio.ImageIO; import core.Command; +import core.Localizer; import dataStructures.*; import utils.ImageUtils; @@ -16,7 +17,7 @@ public class CommandStark extends Command public CommandStark(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Snaps your icon or the icon of a friend you mentioned"; }; + public String HelpText() { return Localizer.Stub("Snaps your icon or the icon of a friend you mentioned"); }; private static Long num = 0l; diff --git a/src/commands/CommandStats.java b/src/commands/CommandStats.java index fe865a3..fad2086 100644 --- a/src/commands/CommandStats.java +++ b/src/commands/CommandStats.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import core.CommandManager.ThreadData; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -16,7 +17,7 @@ public class CommandStats extends Command public CommandStats(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "Displays the actively running KittyBot application information"; } + public String HelpText() { return Localizer.Stub("Displays the actively running KittyBot application information"); } // Called when the command is run! @Override diff --git a/src/commands/CommandTweet.java b/src/commands/CommandTweet.java index 947a26d..7538bec 100644 --- a/src/commands/CommandTweet.java +++ b/src/commands/CommandTweet.java @@ -1,6 +1,7 @@ package commands; import core.Command; +import core.Localizer; import dataStructures.*; import network.NetworkTwitter; @@ -10,7 +11,7 @@ public class CommandTweet extends Command public CommandTweet(KittyRole level, KittyRating rating) { super(level, rating); } @Override - public String HelpText() { return "With an input of x,y,z where x y and z are all choices, kitty will choose one"; } + 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"); } @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) @@ -18,7 +19,7 @@ public class CommandTweet extends Command try { res.Call(tweet.tweet(input.args)); } catch (Exception e) { - res.Call("FUCKED UP HARD"); + res.Call(Localizer.Stub("FUCKED UP HARD")); } } } diff --git a/src/commands/CommandWolfram.java b/src/commands/CommandWolfram.java index 8f48c2e..80d6163 100644 --- a/src/commands/CommandWolfram.java +++ b/src/commands/CommandWolfram.java @@ -3,6 +3,7 @@ package commands; import java.io.File; import java.io.IOException; import core.Command; +import core.Localizer; import dataStructures.*; import network.*; import utils.ImageUtils; @@ -14,13 +15,13 @@ public class CommandWolfram extends Command public CommandWolfram(KittyRole level, KittyRating rating) { super(level, rating);} @Override - public String HelpText() { return "Will query wolframalpha with your question and give a full image output of the answer"; } + public String HelpText() { return Localizer.Stub("Will query wolframalpha with your question and give a full image output of the answer"); } @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("You need to provide some arguments!"); + res.Call(Localizer.Stub("You need to provide some arguments!")); try { @@ -30,7 +31,7 @@ public class CommandWolfram extends Command } catch (IOException e) { - res.Call("Something went wrong!"); + res.Call(Localizer.Stub("Something went wrong!")); } } } \ No newline at end of file diff --git a/src/commands/CommandYeet.java b/src/commands/CommandYeet.java index 646771e..7b29add 100644 --- a/src/commands/CommandYeet.java +++ b/src/commands/CommandYeet.java @@ -20,6 +20,7 @@ import javax.imageio.stream.FileImageOutputStream; import javax.imageio.stream.ImageOutputStream; import core.Command; +import core.Localizer; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -38,7 +39,7 @@ public class CommandYeet extends Command private static Long num = 0l; @Override - public String HelpText() { return "Yeet yourself or yeet a friend with @!"; } + public String HelpText() { return Localizer.Stub("Yeet yourself or yeet a friend with @!"); } // Called when the command is run! @Override From 703dcb8d3bf8a6d1c7c9dbe9e5f766e2af5b6654 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Wed, 10 Apr 2019 23:20:08 -0700 Subject: [PATCH 07/25] = Updated readme to include more bot info --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bc4f1cc..6c0e87f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # KittyBot -Fun and useful Discord bot +Fun and useful Discord bot designed to be able searching websites, playing games, compiling code, and much more! + +This repo is an eclipse project, and can be opened in the IDE directly. Authentication keys will need to be placed in a file called `Ref.java` at `src/offline/`. This folder isn't present in this repository by default. + +If you're looking to contribute, feel free to submit a pull request! Take a look at the styleguide to get some pointers on formatting for this repo! \ No newline at end of file From 2c3e6cd1593adfa6a8b739d3eaa854bc5e2fc589 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Wed, 10 Apr 2019 23:36:05 -0700 Subject: [PATCH 08/25] + Added start of a styleguilde --- STYLEGUIDE.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 STYLEGUIDE.md diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md new file mode 100644 index 0000000..12fc856 --- /dev/null +++ b/STYLEGUIDE.md @@ -0,0 +1,46 @@ +KittyBot Style Guide +--- + +#### Indenting +Tabs are used so that individual developers can configure their own width settings, and they won't be enforced on others working on the project. + +` +// No indent! + // One indent! + // Two indents! +` + +#### Braces +When braces are present, Allman style is used which means that braces are on the next line. Braces should be used to prevent scope confusion. Omitting braces on single-line statements is fine so long as the statement is clear. + +` +if(something) +{ + System.out.println("This"); + System.out.println("has"); + System.out.println("braces!"); +} + +if(something) + System.out.println("No braces!"); +` + +#### Naming +Class names and function names are in PascalCase! Variable names are in camelCase! + +` +public class MyClass +{ + private String myString; + + public function MyFuction() + { + // ... + } +} +` + +#### Ternary Operator +Don't. + +#### \ No newline at end of file From c21880fe3a8e863d3d2f2096d5da77de4b73c018 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Wed, 10 Apr 2019 23:40:38 -0700 Subject: [PATCH 09/25] = Updated formatting and language. --- STYLEGUIDE.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 12fc856..7da2050 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -2,43 +2,44 @@ KittyBot Style Guide --- #### Indenting -Tabs are used so that individual developers can configure their own width settings, and they won't be enforced on others working on the project. +Tabs are used so that individual developers can configure their own indent width settings that won't be enforced on others working on the project. -` -// No indent! - // One indent! - // Two indents! -` +```java +// I'm not indented! +{ + // I'm indented with one tab! +} +``` #### Braces -When braces are present, Allman style is used which means that braces are on the next line. Braces should be used to prevent scope confusion. Omitting braces on single-line statements is fine so long as the statement is clear. +When braces are present, Allman style is used meaning that braces start on the next line. Braces are used to prevent scope confusion. Omitting braces on single-line statements is fine if the situation is clear. -` -if(something) +```java +if(foo) { System.out.println("This"); System.out.println("has"); System.out.println("braces!"); } -if(something) +if(bar) System.out.println("No braces!"); -` +``` #### Naming -Class names and function names are in PascalCase! Variable names are in camelCase! +Class names and function names are `PascalCase`. Variable names are `camelCase`. -` +```java public class MyClass { - private String myString; + private Foo myVariable; public function MyFuction() { // ... } } -` +``` #### Ternary Operator Don't. From 5440e3b1ee206df3ff69df69488e4744753df166 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Wed, 10 Apr 2019 23:41:47 -0700 Subject: [PATCH 10/25] = Clarified --- STYLEGUIDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 7da2050..8fd0183 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -41,7 +41,7 @@ public class MyClass } ``` -#### Ternary Operator +#### Ternary Operator (the ?:) Don't. #### \ No newline at end of file From ba7d4324e326a4548a5666ec06b6a665fe6a62d5 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Wed, 10 Apr 2019 23:42:18 -0700 Subject: [PATCH 11/25] = Clarified --- STYLEGUIDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 8fd0183..a244fb1 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -41,7 +41,7 @@ public class MyClass } ``` -#### Ternary Operator (the ?:) +#### Ternary Operator (`?:`) Don't. #### \ No newline at end of file From 047bc97238eed38d431d6f8bde463b4674c2c203 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 00:48:54 -0700 Subject: [PATCH 12/25] + Added custom data type for ini inspired config file --- src/dataStructures/SectionedKeyValue.java | 131 ++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/dataStructures/SectionedKeyValue.java diff --git a/src/dataStructures/SectionedKeyValue.java b/src/dataStructures/SectionedKeyValue.java new file mode 100644 index 0000000..02d4420 --- /dev/null +++ b/src/dataStructures/SectionedKeyValue.java @@ -0,0 +1,131 @@ +package dataStructures; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +// This is a class designed to parse ini inspired key-value pairs that are sectioned off. +// The difference here is that this is more permissive than an ini file, and only accepts +// a single split character, not the traditional set an ini does. All of the following are valid: +// +// [ExampleSection] +// Key=Value +// Valid Ridiculous Key&\n\t_.:;foo =Some Value +// Key= +// +public class SectionedKeyValue +{ + // Variables + public final char SectionStart = '['; + public final char SectionEnd = ']'; + public final char KeyValueLineSeparator = '\n'; + public final String KeyValueSplit = "="; + private HashMap> sectionKeyValue; + + // String constructor that parses the input string into the object + public SectionedKeyValue(String input) + { + sectionKeyValue = new HashMap>(); + + Parse(input); + } + + // Adds a KeyValue pair to the specified section if it's not already there. + // Also creates the section if it's not already present. + public void AddKeyValue(String sectionName, String key, String value) + { + AddSection(sectionName); + sectionKeyValue.get(sectionName).putIfAbsent(key, value); + } + + // Returns a HashMap of Keys to Values for a given section + public HashMap GetSection(String sectionName) + { + return sectionKeyValue.get(sectionName); + } + + // Stores the internal hashmap as a string then reutrns it. + // Places 1 newline between the sections. + @SuppressWarnings({"rawtypes", "unchecked"}) + public String ToString() + { + String out = ""; + + Iterator it = sectionKeyValue.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry pair = (Map.Entry)it.next(); + out += ("" + SectionStart + pair.getKey() + SectionEnd); + + Iterator internal = ((HashMap)pair.getValue()).entrySet().iterator(); + + while(internal.hasNext()) + { + Map.Entry internalPair = (Map.Entry)internal.next(); + out += (internalPair.getKey() + KeyValueSplit + internalPair.getValue()) + KeyValueLineSeparator; + } + + out += "\n"; + } + + return out; + } + + // Adds a given section to the hashmap if it's not already present + private void AddSection(String sectionName) + { + sectionKeyValue.putIfAbsent(sectionName, new HashMap()); + } + + // Parses out the string passed in into the sectionkeyValue HashMap. + // Any character used in a split call is escaped just in case on + // account of some characters having specific regex meanings. + private void Parse(String input) + { + String[] sections = input.split("\\" + SectionStart); + + for(int sec = 0; sec < sections.length; ++sec) + { + // Gather information about the contents of the section, and the header. + String section = sections[sec]; + if(section.length() < 2) + continue; + + int pos = section.indexOf(SectionEnd); + if(pos == -1) + continue; + + // Parse section name. If it already exists, don't bother making it. + String sectionName = section.substring(0, pos); + AddSection(sectionName); + + // Parse out the pairs within the section, split them all out. + String unparsedPairs = section.substring(pos + 1); + String[] pairs = unparsedPairs.split("\\" + KeyValueLineSeparator); + + // 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); + if(splitPos < 0) + continue; + + String key = line.substring(0, splitPos); + String value = line.substring(splitPos + KeyValueSplit.length()); + sectionKeyValue.get(sectionName).putIfAbsent(key, value); + } + } + } + + // Dumps out a string array + @SuppressWarnings("unused") + private void Dump(String[] toPrint) + { + System.out.println("Length: " + toPrint.length); + + for(int i = 0; i < toPrint.length; ++i) + System.out.println(toPrint[i]); + } +} From 41326e1f31339aed045498dfac0a411e60f711e2 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 21:15:10 -0700 Subject: [PATCH 13/25] + Added Pair structure and edited SectionedKeyvalue --- src/dataStructures/Pair.java | 14 ++++++++++++++ ...edKeyValue.java => SectionedKeyValueStore.java} | 0 2 files changed, 14 insertions(+) create mode 100644 src/dataStructures/Pair.java rename src/dataStructures/{SectionedKeyValue.java => SectionedKeyValueStore.java} (100%) diff --git a/src/dataStructures/Pair.java b/src/dataStructures/Pair.java new file mode 100644 index 0000000..e4771db --- /dev/null +++ b/src/dataStructures/Pair.java @@ -0,0 +1,14 @@ +package dataStructures; + +// A generic class designed to hold two types, as a first and second variable. +public class Pair +{ + public T1 First; + public T2 Second; + + public Pair(T1 first, T2 second) + { + this.First = first; + this.Second = second; + } +} diff --git a/src/dataStructures/SectionedKeyValue.java b/src/dataStructures/SectionedKeyValueStore.java similarity index 100% rename from src/dataStructures/SectionedKeyValue.java rename to src/dataStructures/SectionedKeyValueStore.java From 20e4376891b0d6af079b56805723d9390d588c34 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 21:15:29 -0700 Subject: [PATCH 14/25] = Updated localizer code --- localization.config | 324 +++++++++--------- src/core/Localizer.java | 84 ++--- .../SectionedKeyValueStore.java | 63 +++- src/main/Main.java | 9 +- 4 files changed, 259 insertions(+), 221 deletions(-) diff --git a/localization.config b/localization.config index b52e3e6..2adcf25 100644 --- a/localization.config +++ b/localization.config @@ -1,174 +1,170 @@ -[CommandEightBall] -Ask again later. = -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. = -Without a doubt. = -My reply is no. = -Signs point to yes. = -Reply hazy, try again. = -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. = -Yes. = -Yes - definitely. = -It is certain. = -Concentrate and ask again. = -It is decidedly so. = -As I see it, yes. = -Outlook good. = -Outlook not so good. = -Cannot predict now. = -Most likely. = -Very doubtful. = -Don't count on it. = -Better not tell you now. = - -[CommandColiru] -Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++. = - -[CommandPerish] -Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned = +[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='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] -Displays how many beans you have = -You have %s beans! = - -[CommandPollResults] -%s people voted for %s `%s` with `%s%` !\n = -Will show current results of a poll and percentages of votes per choice = -%s people voted for %s `%s` with `%s%` !\n = - -[CommandShutdown] -Forced immediate shutdown, threads abandoned without sync. = -Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown. = -Forced shutdown, database synced before abandoning threads. = - -[CommandBetBeans] -That's not a valid bet! = -You don't have enough beans! = -Please bet with at least 50 beans! = -You won %s beans! = -Sorry, you didn't win, try again! = -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 = - -[CommandRole] -You aren't allowed to do that! You must have the KittyRole '%' or higher! = -Please enter `general`, `mod`, or `admin`! = -Your role is = -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. = -Changed %s to role `%s`! = - -[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` = - -[CommandTweet] -FUCKED UP HARD = - -[CommandStats] -Displays the actively running KittyBot application information = - -[CommandMap] -Invalid arguments provided! = -Using mapgen v0.1 = -Width = -Seed = -Height = - -[CommandPollVote] -You already voted = -That's not a vaild number! = -%s That's not a vaild vote! = -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 successfully voted for = - -[CommandDoWork] -I finished with my work! = D = -I finished with my work! :D = -Occupies a core for a few seconds = +You have %s beans!=You have %s beans! +Displays how many beans you have=Displays how many beans you have [CommandHelp] -You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` = -You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` = -Lets you look up specific commands, or get a link to a list of all commands. = - -[CommandPing] -Will respond with Pong! = -Pong! = - -[CommandBoop] -Woah! %s booped me! That's %s total! = -%s booped several others - %s! = -%s booped %s! = -Kitty will react with a counter = - -[CommandInfo] -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/ = -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/ = -Provides author info and a link to Kitty's website = - -[CommandBlurry] -Blurs your icon or the icon of a friend you mentioned = - -[CommandHelpBuilder] -Emit help for all commands as formatted HTML = -commands = - -[CommandRating] -Warning = NSFW may slip through, images are only based on tags on their respective sites! = -Kittybot content set to = -Warning: NSFW may slip through, images are only based on tags on their respective sites! = -Invalid content rating = - -[CommandRPEnd] -Here's your file! = -You can't end this RP! = -Ends RP in channel = - -[CommandPollShow] -Will show the current poll running = -The current poll is `%s`\n = -And the choices are = \n = -There is no poll running! = -And the choices are:\n = - -[CommandGiveBeans] -That's not a valid number! = -Gives beans to the mentioned users! = -You didn't mention anyone! = -Gave %s %s beans! = - -[CommandWolfram] -Will query wolframalpha with your question and give a full image output of the answer = -Something went wrong! = -You need to provide some arguments! = - -[CommandRPG] -Admin+ command only right now - experimental text RPG! Format is !rpg = -Invalid RPG Command! = - -[CommandYeet] -Yeet yourself or yeet a friend with @! = - -[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 = - -[CommandRPStart] -Starts an rp, add people to it by mentioning them! = - -[CommandStark] -Snaps your icon or the icon of a friend you mentioned = - -[CommandJDoodle] -Will compile any java code you put in! Supports Java 1.8 = +You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`=You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` +Lets you look up specific commands, or get a link to a list of all commands.=Lets you look up specific commands, or get a link to a list of all commands. [CommandRoll] -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 = -Didn't work ;3; = +Didn't work ;3;=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=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 -[CommandInvite] -Provies a direct invite link for KittyBot = +[CommandStats] +Displays the actively running KittyBot application information=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=With an input of x,y,z where x y and z are all choices, kitty will choose one +FUCKED UP HARD=FUCKED UP HARD + +[CommandRole] +Please enter `general`, `mod`, or `admin`!=Please enter `general`, `mod`, or `admin`! +You aren't allowed to do that! You must have the KittyRole '%' or higher!=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.=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=Your role is +Changed %s to role `%s`!=Changed %s to role `%s`! + +[CommandColiru] +Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++.=Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++. + +[CommandJDoodle] +Will compile any java code you put in! Supports Java 1.8=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!=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`=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=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=Snaps your icon or the icon of a friend you mentioned + +[CommandYeet] +Yeet yourself or yeet a friend with @!=Yeet yourself or yeet a friend with @! + +[CommandPollVote] +There is no poll running!=There is no poll running! +You already voted=You already voted +%s That's not a vaild vote!=%s That's not a vaild vote! +That's not a vaild number!=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!=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 successfully voted for=You successfully voted for + +[CommandShutdown] +Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown.=Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown. +Forced shutdown, database synced before abandoning threads.=Forced shutdown, database synced before abandoning threads. +Forced immediate shutdown, threads abandoned without sync.=Forced immediate shutdown, threads abandoned without sync. + +[CommandBetBeans] +That's not a valid bet!=That's not a valid bet! +Please bet with at least 50 beans!=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=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!=Sorry, you didn't win, try again! +You don't have enough beans!=You don't have enough beans! +You won %s beans!=You won %s beans! + +[CommandDoWork] +I finished with my work! :D=I finished with my work! :D +Occupies a core for a few seconds=Occupies a core for a few seconds + +[CommandRPStart] +Starts an rp, add people to it by mentioning them!=Starts an rp, add people to it by mentioning them! + +[CommandBlurry] +Blurs your icon or the icon of a friend you mentioned=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=Will show current results of a poll and percentages of votes per choice +%s people voted for %s `%s` with `%s%` !\n =%s people voted for %s `%s` with `%s%` !\n + +[CommandRating] +Kittybot content set to=Kittybot content set to +Warning: NSFW may slip through, images are only based on tags on their respective sites!=Warning: NSFW may slip through, images are only based on tags on their respective sites! +Invalid content rating=Invalid content rating + +[CommandGiveBeans] +That's not a valid number!=That's not a valid number! +Gave %s %s beans!=Gave %s %s beans! +Gives beans to the mentioned users!=Gives beans to the mentioned users! +You didn't mention anyone!=You didn't mention anyone! + +[CommandPollShow] +There is no poll running!=There is no poll running! +And the choices are:\n=And the choices are:\n +Will show the current poll running=Will show the current poll running +The current poll is `%s`\n=The current poll is `%s`\n + +[CommandHelpBuilder] +Emit help for all commands as formatted HTML=Emit help for all commands as formatted HTML +commands=commands + +[CommandRPEnd] +Here's your file!=Here's your file! +You can't end this RP!=You can't end this RP! +Ends RP in channel=Ends RP in channel + +[CommandRPG] +Invalid RPG Command!=Invalid RPG Command! +Admin+ command only right now - experimental text RPG! Format is !rpg =Admin+ command only right now - experimental text RPG! Format is !rpg + +[CommandBoop] +%s booped %s!=%s booped %s! +Kitty will react with a counter=Kitty will react with a counter +Woah! %s booped me! That's %s total!=Woah! %s booped me! That's %s total! +%s booped several others - %s!=%s booped several others - %s! + +[CommandInfo] +Provides author info and a link to Kitty's website=Provides author info and a link to Kitty's website +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/=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/ + +[CommandPing] +Pong!=Pong! +Will respond with 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! = +With an input of x,y,z where x y and z are all choices, kitty will choose one=With an input of x,y,z where x y and z are all choices, kitty will choose one +I chooooooose %s!=I chooooooose %s! + +[CommandEightBall] +It is certain.=It is certain. +Ask again later.=Ask again later. +Cannot predict now.=Cannot predict now. +My sources say no.=My sources say no. +You may rely on it.=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.=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.=Concentrate and ask again. +Signs point to yes.=Signs point to yes. +Don't count on it.=Don't count on it. +Yes.=Yes. +My reply is no.=My reply is no. +Most likely.=Most likely. +Reply hazy, try again.=Reply hazy, try again. +Without a doubt.=Without a doubt. +Yes - definitely.=Yes - definitely. +Very doubtful.=Very doubtful. +As I see it, yes.=As I see it, yes. +Better not tell you now.=Better not tell you now. +Outlook good.=Outlook good. +Outlook not so good.=Outlook not so good. +It is decidedly so.=It is decidedly so. + +[CommandInvite] +Provies a direct invite link for KittyBot=Provies a direct invite link for KittyBot + +[CommandWolfram] +Something went wrong!=Something went wrong! +Will query wolframalpha with your question and give a full image output of the answer=Will query wolframalpha with your question and give a full image output of the answer +You need to provide some arguments!=You need to provide some arguments! + +[CommandMap] +Seed=Seed +Invalid arguments provided!=Invalid arguments provided! +Height=Height +Using mapgen v0.1=Using mapgen v0.1 +Width=Width + diff --git a/src/core/Localizer.java b/src/core/Localizer.java index 8498f9a..4068454 100644 --- a/src/core/Localizer.java +++ b/src/core/Localizer.java @@ -3,13 +3,17 @@ package core; import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import org.ini4j.InvalidFileFormatException; import org.ini4j.Profile.Section; import org.ini4j.Wini; - +import org.sqlite.SQLiteConfig.Encoding; +import dataStructures.SectionedKeyValueStore; import utils.FileUtils; import utils.GlobalLog; import utils.LogFilter; @@ -23,8 +27,8 @@ public class Localizer public final static String filename = "localization.config"; public final static String functionName = "Localizer.Stub"; - // Local translation - private static HashMap translated = new HashMap(); + // Local translation storage + private static SectionedKeyValueStore stringStore; // Logging private static void Log(String str) { GlobalLog.Log(LogFilter.Strings, str); } @@ -87,37 +91,45 @@ public class Localizer // the string in question if one can be found. public static String Stub(String input) { - if(translated.containsKey(input)) - { - String value = translated.get(input).phrase; - if(value.trim().length() > 0) - return value; - } + if(stringStore == null) + return input; - return input; + return stringStore.GetKey(input); } + // Reads a file to string, adapted from https://stackoverflow.com/a/326440/5383198 + static String ReadFileAsString(String path, Charset encoding) + { + try + { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded, encoding); + } + catch (IOException e) + { + Warn("No file found to read from!"); + } + + return null; + } + // 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() { Log("Attempting to read localization file"); + try { - File file = new File(filename); - file.createNewFile(); - - Wini ini = new Wini(file); - - for(String str : ini.keySet()) + String fileContents = ReadFileAsString(filename, Charset.defaultCharset()); + if(fileContents == null) { - // Store everything in all .ini sections - Section sec = ini.get(str); - for(String s : sec.keySet()) - { - if(!translated.containsKey(s)) - translated.put(s, new LocInfo(sec.getName(), sec.get(s, String.class))); - } + File file = new File(filename); + file.createNewFile(); + } + else + { + stringStore = new SectionedKeyValueStore(fileContents); } } catch(InvalidFileFormatException e) @@ -138,24 +150,8 @@ public class Localizer try { PrintWriter pw = new PrintWriter(filename); + pw.println(stringStore.toString()); pw.close(); - - File file = new File(filename); - file.createNewFile(); - - Wini ini = new Wini(file); - - for(String s : translated.keySet()) - { - LocInfo toWrite = translated.get(s); - ini.put(toWrite.file, s, toWrite.phrase); - } - - ini.store(); - } - catch(InvalidFileFormatException e) - { - Error("File issue with format during localization file write"); } catch(IOException e) { @@ -171,12 +167,6 @@ public class Localizer FileUtils.AcquireAllFiles(".\\src").forEach((path) -> StripForContents(path, localizeList)); for(LocInfo toStub : localizeList) - { - if(!translated.containsKey(toStub.phrase)) - { - translated.put(toStub.phrase, new LocInfo(toStub.file, "")); - Log("Found new stubbed phrase '" + toStub.phrase + "' in " + toStub.file); - } - } + stringStore.AddKeyValue(toStub.file, toStub.phrase, toStub.phrase); } } \ No newline at end of file diff --git a/src/dataStructures/SectionedKeyValueStore.java b/src/dataStructures/SectionedKeyValueStore.java index 02d4420..744d546 100644 --- a/src/dataStructures/SectionedKeyValueStore.java +++ b/src/dataStructures/SectionedKeyValueStore.java @@ -3,6 +3,8 @@ package dataStructures; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; // This is a class designed to parse ini inspired key-value pairs that are sectioned off. // The difference here is that this is more permissive than an ini file, and only accepts @@ -13,20 +15,27 @@ import java.util.Map; // Valid Ridiculous Key&\n\t_.:;foo =Some Value // Key= // -public class SectionedKeyValue +// 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. +public class SectionedKeyValueStore { // Variables public final char SectionStart = '['; public final char SectionEnd = ']'; public final char KeyValueLineSeparator = '\n'; public final String KeyValueSplit = "="; + + // [Key: SectionName, [Key: KeyString, Value: ValueString]] private HashMap> sectionKeyValue; + // [Key: KeyString, Value: ValueString]] + private HashMap keyValue; + // String constructor that parses the input string into the object - public SectionedKeyValue(String input) + public SectionedKeyValueStore(String input) { sectionKeyValue = new HashMap>(); - + keyValue = new HashMap(); Parse(input); } @@ -36,18 +45,59 @@ public class SectionedKeyValue { AddSection(sectionName); sectionKeyValue.get(sectionName).putIfAbsent(key, value); + keyValue.putIfAbsent(key, value); } // Returns a HashMap of Keys to Values for a given section + @SuppressWarnings("unchecked") public HashMap GetSection(String sectionName) { - return sectionKeyValue.get(sectionName); + return (HashMap) sectionKeyValue.get(sectionName).clone(); + } + + // Look up a global key + public String GetKey(String key) + { + if(keyValue.containsKey(key)) + return keyValue.get(key); + + return null; + } + + // Calls back on each item in the entire structure. Provides section, then a pair of the keyString and valueString. + @SuppressWarnings({"rawtypes", "unchecked"}) + public void ForEach(BiConsumer> action) + { + Iterator it = sectionKeyValue.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry pair = (Map.Entry)it.next(); + Iterator internal = ((HashMap)pair.getValue()).entrySet().iterator(); + + while(internal.hasNext()) + { + Map.Entry internalPair = (Map.Entry)internal.next(); + action.accept((String)pair.getKey(), new Pair((String)internalPair.getKey(), (String)internalPair.getValue())); + } + } + } + + // Calls back each item in the structure but does not priv + @SuppressWarnings({"rawtypes"}) + public void ForEach(Consumer> action) + { + Iterator it = keyValue.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry pair = (Map.Entry)it.next(); + action.accept(new Pair((String)pair.getKey(), (String)pair.getValue())); + } } // Stores the internal hashmap as a string then reutrns it. // Places 1 newline between the sections. @SuppressWarnings({"rawtypes", "unchecked"}) - public String ToString() + public String toString() { String out = ""; @@ -55,7 +105,7 @@ public class SectionedKeyValue while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); - out += ("" + SectionStart + pair.getKey() + SectionEnd); + out += ("" + SectionStart + pair.getKey() + SectionEnd + "\n"); Iterator internal = ((HashMap)pair.getValue()).entrySet().iterator(); @@ -115,6 +165,7 @@ public class SectionedKeyValue String key = line.substring(0, splitPos); String value = line.substring(splitPos + KeyValueSplit.length()); sectionKeyValue.get(sectionName).putIfAbsent(key, value); + keyValue.putIfAbsent(key, value); } } } diff --git a/src/main/Main.java b/src/main/Main.java index 50ae429..72f4243 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -32,16 +32,17 @@ public class Main extends ListenerAdapter // 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(); + // Facotry startup. databaseManager = ObjectBuilderFactory.ConstructDatabaseManager(); commandManager = ObjectBuilderFactory.ConstructCommandManager(); rpManager = ObjectBuilderFactory.ConstructRPManager(); stats = ObjectBuilderFactory.ConstructStats(commandManager); - // Localizer startup - Potentially integrate with the factory. - Localizer.UpdateLocFromDisk(); - Localizer.ScrapeAll(); - Localizer.SaveLocToDisk(); // Bot startup kitty = new JDABuilder(AccountType.BOT).setToken(Ref.TestToken).buildBlocking(); From 84009a294d9198077a5ecc035e08f09db7758c71 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 21:27:30 -0700 Subject: [PATCH 15/25] = Revised SectionedKeyValuePair parsing and writing behavior, along with localization stub --- localization.config | 202 +++++++++--------- src/core/Localizer.java | 9 +- .../SectionedKeyValueStore.java | 90 ++++---- 3 files changed, 157 insertions(+), 144 deletions(-) diff --git a/localization.config b/localization.config index 2adcf25..8718a94 100644 --- a/localization.config +++ b/localization.config @@ -1,170 +1,170 @@ [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='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 +'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!=You have %s beans! -Displays how many beans you have=Displays how many beans you have +You have %s beans!=This phrase has been localized. Also, you have %s. +Displays how many beans you have= [CommandHelp] -You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`=You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` -Lets you look up specific commands, or get a link to a list of all commands.=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`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`= +Lets you look up specific commands, or get a link to a list of all commands.= [CommandRoll] -Didn't work ;3;=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=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 +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=Displays the actively running KittyBot application information +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=With an input of x,y,z where x y and z are all choices, kitty will choose one -FUCKED UP HARD=FUCKED UP HARD +With an input of x,y,z where x y and z are all choices, kitty will choose one= +FUCKED UP HARD= [CommandRole] -Please enter `general`, `mod`, or `admin`!=Please enter `general`, `mod`, or `admin`! -You aren't allowed to do that! You must have the KittyRole '%' or higher!=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.=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=Your role is -Changed %s to role `%s`!=Changed %s to role `%s`! +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] -Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++.=Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++. +Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++.= [CommandJDoodle] -Will compile any java code you put in! Supports Java 1.8=Will compile any java code you put in! Supports Java 1.8 +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!=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`=Indicator changed to `%s` +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=Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned +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=Snaps your icon or the icon of a friend you mentioned +Snaps your icon or the icon of a friend you mentioned= [CommandYeet] -Yeet yourself or yeet a friend with @!=Yeet yourself or yeet a friend with @! +Yeet yourself or yeet a friend with @!= [CommandPollVote] -There is no poll running!=There is no poll running! -You already voted=You already voted -%s That's not a vaild vote!=%s That's not a vaild vote! -That's not a vaild number!=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!=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 successfully voted for=You successfully voted for +There is no poll running!= +You already voted= +%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 successfully voted for= [CommandShutdown] -Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown.=Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown. -Forced shutdown, database synced before abandoning threads.=Forced shutdown, database synced before abandoning threads. -Forced immediate shutdown, threads abandoned without sync.=Forced immediate shutdown, threads abandoned without sync. +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!=That's not a valid bet! -Please bet with at least 50 beans!=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=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!=Sorry, you didn't win, try again! -You don't have enough beans!=You don't have enough beans! -You won %s beans!=You won %s beans! +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=I finished with my work! :D -Occupies a core for a few seconds=Occupies a core for a few seconds +I finished with my work! :D= +Occupies a core for a few seconds= [CommandRPStart] -Starts an rp, add people to it by mentioning them!=Starts an rp, add people to it by mentioning them! +Starts an rp, add people to it by mentioning them!= [CommandBlurry] -Blurs your icon or the icon of a friend you mentioned=Blurs your icon or the icon of a friend you mentioned +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=Will show current results of a poll and percentages of votes per choice -%s people voted for %s `%s` with `%s%` !\n =%s people voted for %s `%s` with `%s%` !\n +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=Kittybot content set to -Warning: NSFW may slip through, images are only based on tags on their respective sites!=Warning: NSFW may slip through, images are only based on tags on their respective sites! -Invalid content rating=Invalid content rating +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!=That's not a valid number! -Gave %s %s beans!=Gave %s %s beans! -Gives beans to the mentioned users!=Gives beans to the mentioned users! -You didn't mention anyone!=You didn't mention anyone! +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!=There is no poll running! -And the choices are:\n=And the choices are:\n -Will show the current poll running=Will show the current poll running -The current poll is `%s`\n=The current poll is `%s`\n +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=Emit help for all commands as formatted HTML -commands=commands +Emit help for all commands as formatted HTML= +commands= [CommandRPEnd] -Here's your file!=Here's your file! -You can't end this RP!=You can't end this RP! -Ends RP in channel=Ends RP in channel +Here's your file!= +You can't end this RP!= +Ends RP in channel= [CommandRPG] -Invalid RPG Command!=Invalid RPG Command! -Admin+ command only right now - experimental text RPG! Format is !rpg =Admin+ command only right now - experimental text RPG! Format is !rpg +Invalid RPG Command!= +Admin+ command only right now - experimental text RPG! Format is !rpg = [CommandBoop] -%s booped %s!=%s booped %s! -Kitty will react with a counter=Kitty will react with a counter -Woah! %s booped me! That's %s total!=Woah! %s booped me! That's %s total! -%s booped several others - %s!=%s booped several others - %s! +%s booped %s!= +Kitty will react with a counter= +Woah! %s booped me! That's %s total!= +%s booped several others - %s!= [CommandInfo] -Provides author info and a link to Kitty's website=Provides author info and a link to Kitty's website -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/=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/ +Provides author info and a link to Kitty's website= +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/= [CommandPing] -Pong!=Pong! -Will respond with Pong!=Will respond with Pong! +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=With an input of x,y,z where x y and z are all choices, kitty will choose one -I chooooooose %s!=I chooooooose %s! +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.=It is certain. -Ask again later.=Ask again later. -Cannot predict now.=Cannot predict now. -My sources say no.=My sources say no. -You may rely on it.=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.=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.=Concentrate and ask again. -Signs point to yes.=Signs point to yes. -Don't count on it.=Don't count on it. -Yes.=Yes. -My reply is no.=My reply is no. -Most likely.=Most likely. -Reply hazy, try again.=Reply hazy, try again. -Without a doubt.=Without a doubt. -Yes - definitely.=Yes - definitely. -Very doubtful.=Very doubtful. -As I see it, yes.=As I see it, yes. -Better not tell you now.=Better not tell you now. -Outlook good.=Outlook good. -Outlook not so good.=Outlook not so good. -It is decidedly so.=It is decidedly so. +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.= +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=Provies a direct invite link for KittyBot +Provies a direct invite link for KittyBot= [CommandWolfram] -Something went wrong!=Something went wrong! -Will query wolframalpha with your question and give a full image output of the answer=Will query wolframalpha with your question and give a full image output of the answer -You need to provide some arguments!=You need to provide some arguments! +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=Seed -Invalid arguments provided!=Invalid arguments provided! -Height=Height -Using mapgen v0.1=Using mapgen v0.1 -Width=Width +Seed= +Invalid arguments provided!= +Height= +Using mapgen v0.1= +Width= diff --git a/src/core/Localizer.java b/src/core/Localizer.java index 4068454..6f00172 100644 --- a/src/core/Localizer.java +++ b/src/core/Localizer.java @@ -88,13 +88,18 @@ 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. + // 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) { if(stringStore == null) return input; - return stringStore.GetKey(input); + String value = stringStore.GetKey(input); + if(value.length() < 1) + return input; + + return value; } // Reads a file to string, adapted from https://stackoverflow.com/a/326440/5383198 diff --git a/src/dataStructures/SectionedKeyValueStore.java b/src/dataStructures/SectionedKeyValueStore.java index 744d546..0f67458 100644 --- a/src/dataStructures/SectionedKeyValueStore.java +++ b/src/dataStructures/SectionedKeyValueStore.java @@ -12,11 +12,12 @@ import java.util.function.Consumer; // // [ExampleSection] // Key=Value -// Valid Ridiculous Key&\n\t_.:;foo =Some Value -// Key= +// Valid Ridiculous Key&\n\t_.:;foo = \tValid Ridiculous Value*&%$()^.[]{}@ +// EmptyValue= // -// 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. +// 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 { // Variables @@ -39,31 +40,6 @@ public class SectionedKeyValueStore Parse(input); } - // Adds a KeyValue pair to the specified section if it's not already there. - // Also creates the section if it's not already present. - public void AddKeyValue(String sectionName, String key, String value) - { - AddSection(sectionName); - sectionKeyValue.get(sectionName).putIfAbsent(key, value); - keyValue.putIfAbsent(key, value); - } - - // Returns a HashMap of Keys to Values for a given section - @SuppressWarnings("unchecked") - public HashMap GetSection(String sectionName) - { - return (HashMap) sectionKeyValue.get(sectionName).clone(); - } - - // Look up a global key - public String GetKey(String key) - { - if(keyValue.containsKey(key)) - return keyValue.get(key); - - return null; - } - // Calls back on each item in the entire structure. Provides section, then a pair of the keyString and valueString. @SuppressWarnings({"rawtypes", "unchecked"}) public void ForEach(BiConsumer> action) @@ -94,39 +70,40 @@ public class SectionedKeyValueStore } } - // Stores the internal hashmap as a string then reutrns it. - // Places 1 newline between the sections. + // Parses the internal hashmap as a string then reutrns it, featuring sections. + // Iterates over all key/value pairs in the section and print them. Does not print + // the value of a given key if it is the same as the key. @SuppressWarnings({"rawtypes", "unchecked"}) public String toString() { String out = ""; + // Iterates over the sections and Iterator it = sectionKeyValue.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); - out += ("" + SectionStart + pair.getKey() + SectionEnd + "\n"); + out += ("" + SectionStart + pair.getKey() + SectionEnd + KeyValueLineSeparator); Iterator internal = ((HashMap)pair.getValue()).entrySet().iterator(); - while(internal.hasNext()) { Map.Entry internalPair = (Map.Entry)internal.next(); - out += (internalPair.getKey() + KeyValueSplit + internalPair.getValue()) + KeyValueLineSeparator; + String key = (String)internalPair.getKey(); + String value = (String)internalPair.getValue(); + + if(key == value) + out += (key + KeyValueSplit) + KeyValueLineSeparator; + else + out += (key + KeyValueSplit + value) + KeyValueLineSeparator; } - out += "\n"; + out += KeyValueLineSeparator; } return out; } - // Adds a given section to the hashmap if it's not already present - private void AddSection(String sectionName) - { - sectionKeyValue.putIfAbsent(sectionName, new HashMap()); - } - // Parses out the string passed in into the sectionkeyValue HashMap. // Any character used in a split call is escaped just in case on // account of some characters having specific regex meanings. @@ -179,4 +156,35 @@ public class SectionedKeyValueStore for(int i = 0; i < toPrint.length; ++i) System.out.println(toPrint[i]); } + + // Adds a KeyValue pair to the specified section if it's not already there. + // Also creates the section if it's not already present. + public void AddKeyValue(String sectionName, String key, String value) + { + AddSection(sectionName); + sectionKeyValue.get(sectionName).putIfAbsent(key, value); + keyValue.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()); + } + + // Returns a HashMap of Keys to Values for a given section + @SuppressWarnings("unchecked") + public HashMap GetSection(String sectionName) + { + return (HashMap) sectionKeyValue.get(sectionName).clone(); + } + + // Look up a global key + public String GetKey(String key) + { + if(keyValue.containsKey(key)) + return keyValue.get(key); + + return null; + } } From 2c5c5d3c4a796bbb8781079ef2afe1cecd567469 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 21:29:48 -0700 Subject: [PATCH 16/25] = Updated tweet error text --- localization.config | 4 ++-- src/commands/CommandTweet.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/localization.config b/localization.config index 8718a94..8474259 100644 --- a/localization.config +++ b/localization.config @@ -2,7 +2,7 @@ '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!=This phrase has been localized. Also, you have %s. +You have %s beans!= Displays how many beans you have= [CommandHelp] @@ -18,7 +18,7 @@ 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= -FUCKED UP HARD= +Tweet command failed!= [CommandRole] Please enter `general`, `mod`, or `admin`!= diff --git a/src/commands/CommandTweet.java b/src/commands/CommandTweet.java index 7538bec..8a0bb40 100644 --- a/src/commands/CommandTweet.java +++ b/src/commands/CommandTweet.java @@ -19,7 +19,7 @@ public class CommandTweet extends Command try { res.Call(tweet.tweet(input.args)); } catch (Exception e) { - res.Call(Localizer.Stub("FUCKED UP HARD")); + res.Call(Localizer.Stub("Tweet command failed!")); } } } From a2de36789698bbedebe8e72e96529cce407ac483 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 21:38:12 -0700 Subject: [PATCH 17/25] = Cleanup and clarification --- .classpath | 1 - LICENSE => LICENSE.md | 2 +- lib/ini4j-0.5.4.jar | Bin 102220 -> 0 bytes src/core/Localizer.java | 9 --------- 4 files changed, 1 insertion(+), 11 deletions(-) rename LICENSE => LICENSE.md (95%) delete mode 100644 lib/ini4j-0.5.4.jar diff --git a/.classpath b/.classpath index c1a5172..b116255 100644 --- a/.classpath +++ b/.classpath @@ -13,6 +13,5 @@ - diff --git a/LICENSE b/LICENSE.md similarity index 95% rename from LICENSE rename to LICENSE.md index 9a6b930..9626f73 100644 --- a/LICENSE +++ b/LICENSE.md @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2019, AlexStewartCode +Copyright (c) 2019, AlexStewartCode and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/lib/ini4j-0.5.4.jar b/lib/ini4j-0.5.4.jar deleted file mode 100644 index 499f0afc61dd1b80ef4024f28adcdde373326691..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102220 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 Date: Fri, 12 Apr 2019 21:42:18 -0700 Subject: [PATCH 18/25] = Localization and edge-case updating for stub --- localization.config | 2 +- src/commands/CommandHelp.java | 2 +- src/core/Localizer.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/localization.config b/localization.config index 8474259..436b248 100644 --- a/localization.config +++ b/localization.config @@ -6,8 +6,8 @@ You have %s beans!= Displays how many beans you have= [CommandHelp] -You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`= 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;= diff --git a/src/commands/CommandHelp.java b/src/commands/CommandHelp.java index cb3ec42..12fc256 100644 --- a/src/commands/CommandHelp.java +++ b/src/commands/CommandHelp.java @@ -25,7 +25,7 @@ public class CommandHelp extends Command if(help == null) { - help = Localizer.Stub("You can get help with a specific command by typing `!help command`!\nYou can also look at \nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`"); + 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`"); } else { diff --git a/src/core/Localizer.java b/src/core/Localizer.java index b562d3c..39a8526 100644 --- a/src/core/Localizer.java +++ b/src/core/Localizer.java @@ -91,7 +91,7 @@ public class Localizer return input; String value = stringStore.GetKey(input); - if(value.length() < 1) + if(value == null || value.length() < 1) return input; return value; From 043fa14f16d35234888358613e7d5f41a0fafc86 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 21:44:19 -0700 Subject: [PATCH 19/25] - Removed old TODO --- src/commands/CommandHelp.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commands/CommandHelp.java b/src/commands/CommandHelp.java index 12fc256..0621b26 100644 --- a/src/commands/CommandHelp.java +++ b/src/commands/CommandHelp.java @@ -9,8 +9,7 @@ import dataStructures.KittyUser; import dataStructures.Response; import dataStructures.UserInput; -// TODO: Convert this to a per-command help string! This lets us do all sorts of neat stuff, -// mostly tho it lets us construct this on the fly or by hand for a specific command! +// Either allows for specifically looking up commands or gets a list of general commands to try out! public class CommandHelp extends Command { public CommandHelp(KittyRole level, KittyRating rating) { super(level, rating); } From e70bd5d8d2a92fa86a8fc930fc0edf12ef3ffb6e Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 22:22:07 -0700 Subject: [PATCH 20/25] = Updated Styleguide and comments --- STYLEGUIDE.md | 17 ++++++++++++++++- src/core/Command.java | 3 +-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index a244fb1..b9ff9a7 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -1,6 +1,9 @@ KittyBot Style Guide --- + +# Formatting + #### Indenting Tabs are used so that individual developers can configure their own indent width settings that won't be enforced on others working on the project. @@ -44,4 +47,16 @@ public class MyClass #### Ternary Operator (`?:`) Don't. -#### \ No newline at end of file + +# Architecture + +#### Commands + All commands get spawned on their own threads, and should be implemented in a thread-safe way. Commands all derive from the Command.java class, and use the custom types defined in KittyBot. In order to make any later changes easier and decouple the command logic from core and routing, no JDA structures should be directly exposed in commands, and instead everything needed should be added to the kitty structures that add space to the system. Commands should override the `HelpText` and `Run` functions. Commands are registered in the ObjectBuilderFactory, and the command registration structure can be used for sub-commands as needed. See the RPG for an example. + +#### Tracked Values +Does something need to be tracked in a database? Make sure the class with the data you want inherits from DatabaseTrackedObject, and override the appropriate functions. The object, when marked as dirty, will automatically be written to the database when the next database upkeep tick occurs. Refer to CommandBoop to see an example of a tracked global value, and KittyUser for tracked per-user values. + +#### Tokens, Secrets, etc +Things like tokens, private keys, an secrets are kept in the offline package. This file is intentionally excluded from the repo. If it shouldn't be in the repo, put it in the offline package. + + diff --git a/src/core/Command.java b/src/core/Command.java index e252f9c..a8defdb 100644 --- a/src/core/Command.java +++ b/src/core/Command.java @@ -1,7 +1,6 @@ package core; import java.util.ArrayList; - import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyRating; @@ -42,7 +41,7 @@ public abstract class Command return false; } - //TODO(wisp, rin): ADD CHANNEL CHECK HERE + //TODO: ADD CHANNEL CHECK HERE if(user.GetRole().getValue() >= roleLevel.getValue()) { From 17a9c1980ee4558913cfcfae47bfdfd2649a574f Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 22:26:25 -0700 Subject: [PATCH 21/25] = Clarified naming --- STYLEGUIDE.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index b9ff9a7..64ad712 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -44,6 +44,9 @@ public class MyClass } ``` +Favor a broad to narrow naming scheme to promote autocomplete grouping. For example, use a name like `userDescriptionHeader` instead of `headerUserDescription` because there may be other variables related to a user or description, but there's likely only one header section of a description. + + #### Ternary Operator (`?:`) Don't. @@ -51,12 +54,10 @@ Don't. # Architecture #### Commands - All commands get spawned on their own threads, and should be implemented in a thread-safe way. Commands all derive from the Command.java class, and use the custom types defined in KittyBot. In order to make any later changes easier and decouple the command logic from core and routing, no JDA structures should be directly exposed in commands, and instead everything needed should be added to the kitty structures that add space to the system. Commands should override the `HelpText` and `Run` functions. Commands are registered in the ObjectBuilderFactory, and the command registration structure can be used for sub-commands as needed. See the RPG for an example. +All commands get spawned on their own threads, and should be implemented in a thread-safe way. Commands all derive from the Command.java class, and use the custom types defined in KittyBot. In order to make any later changes easier and decouple the command logic from core and routing, no JDA structures should be directly exposed in commands, and instead everything needed should be added to the kitty structures that add space to the system. Commands should override the `HelpText` and `Run` functions. Commands are registered in the ObjectBuilderFactory, and the command registration structure can be used for sub-commands as needed. See the RPG for an example. #### Tracked Values Does something need to be tracked in a database? Make sure the class with the data you want inherits from DatabaseTrackedObject, and override the appropriate functions. The object, when marked as dirty, will automatically be written to the database when the next database upkeep tick occurs. Refer to CommandBoop to see an example of a tracked global value, and KittyUser for tracked per-user values. #### Tokens, Secrets, etc Things like tokens, private keys, an secrets are kept in the offline package. This file is intentionally excluded from the repo. If it shouldn't be in the repo, put it in the offline package. - - From 815f358873609d435aa805d7b0b15c1fa380c354 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 22:30:28 -0700 Subject: [PATCH 22/25] + Added brief --- STYLEGUIDE.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 64ad712..989ea8d 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -1,9 +1,10 @@ -KittyBot Style Guide +# KittyBot Style Guide + +This document represents the reasonable defaults and expectations for this project, and provides some rationale for the style restrictions! There can always be exceptions to the rules, but they may need justifying. + +Code Formatting --- - -# Formatting - #### Indenting Tabs are used so that individual developers can configure their own indent width settings that won't be enforced on others working on the project. @@ -51,7 +52,8 @@ Favor a broad to narrow naming scheme to promote autocomplete grouping. For exam Don't. -# Architecture +Architecture +--- #### Commands All commands get spawned on their own threads, and should be implemented in a thread-safe way. Commands all derive from the Command.java class, and use the custom types defined in KittyBot. In order to make any later changes easier and decouple the command logic from core and routing, no JDA structures should be directly exposed in commands, and instead everything needed should be added to the kitty structures that add space to the system. Commands should override the `HelpText` and `Run` functions. Commands are registered in the ObjectBuilderFactory, and the command registration structure can be used for sub-commands as needed. See the RPG for an example. From 78ae35d36fb68e12068949f0702f00b26abf650a Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 22:34:06 -0700 Subject: [PATCH 23/25] = Minor formatting tweak --- src/core/Localizer.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/Localizer.java b/src/core/Localizer.java index 39a8526..85c8b2b 100644 --- a/src/core/Localizer.java +++ b/src/core/Localizer.java @@ -30,6 +30,7 @@ public class Localizer private static void Warn(String str) { GlobalLog.Warn(LogFilter.Strings, str); } private static void Error(String str) { GlobalLog.Error(LogFilter.Strings, str); } + // 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 @@ -42,8 +43,8 @@ public class Localizer this.file = f; this.phrase = p; } - } - + } + // Do processing on each path in the scraped directory here, assuming it's .java public static void StripForContents(Path path, ArrayList strings) { @@ -122,6 +123,7 @@ public class Localizer try { String fileContents = ReadFileAsString(filename, Charset.defaultCharset()); + if(fileContents == null) { File file = new File(filename); @@ -143,6 +145,7 @@ public class Localizer public static void SaveLocToDisk() { Log("Attempting to write updated localization file"); + try { PrintWriter pw = new PrintWriter(filename); From afc5176f43bc2378ba58b3c560e5ec2fb015167d Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 22:50:51 -0700 Subject: [PATCH 24/25] = Network Update --- src/network/NetworkDerpi.java | 1 - src/network/NetworkE621.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/network/NetworkDerpi.java b/src/network/NetworkDerpi.java index 2719b4d..04f82f5 100644 --- a/src/network/NetworkDerpi.java +++ b/src/network/NetworkDerpi.java @@ -1,7 +1,6 @@ package network; import com.google.gson.Gson; -import core.*; import dataStructures.GenericImage; import offline.*; import utils.*; diff --git a/src/network/NetworkE621.java b/src/network/NetworkE621.java index 5017964..6cadeca 100644 --- a/src/network/NetworkE621.java +++ b/src/network/NetworkE621.java @@ -1,8 +1,8 @@ package network; import com.google.gson.Gson; -import core.*; import dataStructures.GenericImage; +import offline.Ref; import utils.*; /** @@ -25,7 +25,7 @@ public class NetworkE621 private static final Gson jsonParser_ = new Gson(); private static final String API_ROOT = "https://e621.net/post/index.json?"; private static int maxSearchResults_ = 10; - private static String[] blacklist = {"theallseeingeye","scat","diaper","cub"}; + private static String[] blacklist = Ref.e621Blacklist; private class E621ResponseObject { // public varaibles matching the case and the type we want for JSON. From 8f29e64f834dbbb9b2f5dbb483e2e3e4de5004be Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Fri, 12 Apr 2019 22:59:16 -0700 Subject: [PATCH 25/25] = Updated formatting --- src/main/Main.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/Main.java b/src/main/Main.java index 72f4243..ff780a7 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -1,7 +1,6 @@ package main; import javax.security.auth.login.LoginException; - import core.*; import dataStructures.KittyChannel; import dataStructures.KittyGuild; @@ -18,8 +17,10 @@ import core.Localizer; import utils.GlobalLog; import net.dv8tion.jda.core.*; -// NOTE(wisp): http://www.slf4j.org/ - this JDA logging tool has been disabled by specifying NOP implementation. -// NOTE(wisp): Application entry point! +// http://www.slf4j.org/ - this JDA logging tool has been disabled by specifying NOP implementation. +// This is the application entry point, and bot startup location! + +@SuppressWarnings("unused") public class Main extends ListenerAdapter { // Variables and stuff @@ -37,13 +38,12 @@ public class Main extends ListenerAdapter Localizer.ScrapeAll(); Localizer.SaveLocToDisk(); - // Facotry startup. + // Factory startup databaseManager = ObjectBuilderFactory.ConstructDatabaseManager(); commandManager = ObjectBuilderFactory.ConstructCommandManager(); rpManager = ObjectBuilderFactory.ConstructRPManager(); stats = ObjectBuilderFactory.ConstructStats(commandManager); - // Bot startup kitty = new JDABuilder(AccountType.BOT).setToken(Ref.TestToken).buildBlocking(); kitty.getPresence().setGame(Game.playing("with a new build")); @@ -57,8 +57,6 @@ public class Main extends ListenerAdapter if(!PreProcessSetup(event)) return; - GlobalLog.Log("Parseable message recieved!"); - // Factory objects KittyUser user = ObjectBuilderFactory.ExtractUser(event); KittyGuild guild = ObjectBuilderFactory.ExtractGuild(event); @@ -75,7 +73,7 @@ public class Main extends ListenerAdapter // Track beans! user.ChangeBeans(1); - //RP logging system + // RP logging system RPManager.instance.addLine(channel, user, input); // Issue the command @@ -141,6 +139,7 @@ public class Main extends ListenerAdapter { databaseManager.Upkeep(); RPManager.Upkeep(kitty); + return true; } } \ No newline at end of file