diff --git a/assets/config.csv b/assets/config.csv index 437a63e..20f1aa9 100644 --- a/assets/config.csv +++ b/assets/config.csv @@ -17,6 +17,8 @@ "Localized Commands","dbstats","" "Localized Commands","defaultdance","" "Localized Commands","derp","" +"Localized Commands","derpi","" +"Localized Commands","e6","" "Localized Commands","e621","" "Localized Commands","eightball, 8ball","" "Localized Commands","fetch","" @@ -48,6 +50,7 @@ "Localized Commands","stats","" "Localized Commands","teey","" "Localized Commands","tony, stark, dontfeelgood, dontfeelsogood","tony, stark, dontfeelgood, dontfeelsogood, snap" +"Localized Commands","tradebeans","" "Localized Commands","tweet","" "Localized Commands","vote","" "Localized Commands","wolfram","" @@ -110,8 +113,10 @@ "Localized Strings","DBFlushInfo","Takes all objects queued for the database and writes them to the database, then says how many were written." "Localized Strings","DBStatsInfo","Shows current statistics for the database" "Localized Strings","DefaultDanceInfo","y'all know forknife, get ready to dance, or make a friend dance with @!" +"Localized Strings","DerpiError","" "Localized Strings","DoWorkFinished","I finished with my work! :D" "Localized Strings","DoWorkInfo","Occupies a core for a few seconds" +"Localized Strings","E6Blacklisted","I can't show that image ;3; (it may be blacklisted)" "Localized Strings","EightBallError","Hmm? You'll need to ask a question!" "Localized Strings","EightBallInfo","Answers a yes or no question! Warning: Kitty can not actually tell the future, she claims no responsibility for any lion mauling, lack of lottery wins, or felony charges." "Localized Strings","EightBallMaybe1","Reply hazy, try again." @@ -182,7 +187,10 @@ "Localized Strings","MapVersion","Using mapgen v0.1" "Localized Strings","MapWidth","" "Localized Strings","ModInfo","Mod is a super command for admin or mod use only!\n\t`mod ban @user` will ban a user from the server\n\t`mod kick @user` will kick the user from the server" +"Localized Strings","MusicAddTrack","" "Localized Strings","MusicInfo","" +"Localized Strings","MusicVolChanged","Volume set to %s!" +"Localized Strings","MusicVolCurrent","Volume is at %s!" "Localized Strings","PerishInfo","Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned" "Localized Strings","PingInfo","Will respond with Pong!" "Localized Strings","PingResponse","Pong!" @@ -271,6 +279,8 @@ "Command Enabler","dbstats","1" "Command Enabler","defaultdance","1" "Command Enabler","derp","1" +"Command Enabler","derpi","1" +"Command Enabler","e6","1" "Command Enabler","e621","1" "Command Enabler","eightball, 8ball","1" "Command Enabler","fetch","1" @@ -313,6 +323,7 @@ "Command Enabler","stats","1" "Command Enabler","teey","1" "Command Enabler","tony, stark, dontfeelgood, dontfeelsogood","1" +"Command Enabler","tradebeans","1" "Command Enabler","tweet","1" "Command Enabler","vote","1" "Command Enabler","wolfram","1" diff --git a/assets/plugins/derpisource.lua b/assets/plugins/derpisource.lua index 01bf91c..455eaeb 100644 --- a/assets/plugins/derpisource.lua +++ b/assets/plugins/derpisource.lua @@ -1,22 +1,22 @@ -function plugin(message, user) - local index; - local concat; - if(string.find(message, "https://derpicdn.net/img"))then - if(string.find(message, "view/"))then - index = string.find(message, "/[^/]*$"); - return "!derpi ID:" .. string.sub(message, index + 1, string.find(message, ".[^.]*$")-1); - else - if(string.find(message, "download/"))then - index = string.find(message, "_"); - concat = string.sub(message, 0, index-1); - return "!derpi ID:" .. string.sub(concat, string.find(message, "/[^/]*$") + 1); - else - index = string.find(message, "/[^/]*$"); - concat = string.sub(message, 0, index - 1); - index = string.find(concat, "/[^/]*$"); - - return "!derpi ID:" .. string.sub(concat, index + 1); - end - end - end +function plugin(message, user) + local index; + local concat; + if(string.find(message, "https://derpicdn.net/img"))then + if(string.find(message, "view/"))then + index = string.find(message, "/[^/]*$"); + return "!derpi ID:" .. string.sub(message, index + 1, string.find(message, ".[^.]*$")-1); + else + if(string.find(message, "download/"))then + index = string.find(message, "_"); + concat = string.sub(message, 0, index-1); + return "!derpi ID:" .. string.sub(concat, string.find(message, "/[^/]*$") + 1); + else + index = string.find(message, "/[^/]*$"); + concat = string.sub(message, 0, index - 1); + index = string.find(concat, "/[^/]*$"); + + return "!derpi ID:" .. string.sub(concat, index + 1); + end + end + end end \ No newline at end of file diff --git a/assets/plugins/e6source.lua b/assets/plugins/e6source.lua index 00f3aea..e215906 100644 --- a/assets/plugins/e6source.lua +++ b/assets/plugins/e6source.lua @@ -1,8 +1,8 @@ -function plugin(message, user) - if(string.find(message, "https://static1.e621.net/data") or string.find(message, "https://static1.e926.net/data"))then - if(string.find(message, " "))then - message = string.sub(message, 0, string.find(message, " ")); - end - return "!e6 md5:" .. string.sub(message, string.find(message, "/[^/]*$") + 1 ,string.find(message, ".[^.]*$") - 1); - end +function plugin(message, user) + if(string.find(message, "https://static1.e621.net/data") or string.find(message, "https://static1.e926.net/data"))then + if(string.find(message, " "))then + message = string.sub(message, 0, string.find(message, " ")); + end + return "!e6 md5:" .. string.sub(message, string.find(message, "/[^/]*$") + 1 ,string.find(message, ".[^.]*$") - 1); + end end \ No newline at end of file diff --git a/src/commands/general/CommandBetBeans.java b/src/commands/general/CommandBetBeans.java index bcb14b0..29b65ad 100644 --- a/src/commands/general/CommandBetBeans.java +++ b/src/commands/general/CommandBetBeans.java @@ -20,7 +20,7 @@ public class CommandBetBeans extends Command { String call = ""; - int min = 50; + int min = 20; int bet = 0; int win = 0; diff --git a/src/commands/general/CommandDerpi.java b/src/commands/general/CommandDerpi.java index 7a27173..c082ccf 100644 --- a/src/commands/general/CommandDerpi.java +++ b/src/commands/general/CommandDerpi.java @@ -1,72 +1,72 @@ -package commands.general; - -import core.Command; -import core.LocStrings; -import dataStructures.KittyChannel; -import dataStructures.KittyEmbed; -import dataStructures.KittyGuild; -import dataStructures.KittyRating; -import dataStructures.KittyRole; -import dataStructures.KittyUser; -import dataStructures.Response; -import dataStructures.UserInput; -import network.NetworkDerpi; - -public class CommandDerpi extends Command -{ - NetworkDerpi searcher = new NetworkDerpi(); - KittyEmbed response; - - // Required constructor - public CommandDerpi(KittyRole level, KittyRating rating) { super(level, rating); } - - @Override - public String getHelpText() { return "Will search derpibooru for the tags entered, if KittyBot's content filter allows it"; } - - @Override - public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) - { - if(guild.contentRating == KittyRating.Filtered) - { - try - { - response = searcher.getDerpi(input.args.replace(',', ' ') + " safe").output(); - res.send(response); - } - catch(Exception e) - { - res.send(LocStrings.stub("DerpiError")); - } - } - else - { - if(input.args == null || input.args.length() == 0) - res.send("DerpiNoSearchError"); - else - { - response = searcher.getDerpi(input.args).output(); - try - { - res.send(response); - } - catch(Exception e) - { - res.send(LocStrings.stub("DerpiError")); - } - } - } - - if(input.args.startsWith("ID:")) - { - response = searcher.getDerpiByID(input.args.substring(input.args.indexOf(':'))).output(); - try - { - res.send(response); - } - catch(Exception e) - { - res.send(LocStrings.stub("DerpiError")); - } - } - } +package commands.general; + +import core.Command; +import core.LocStrings; +import dataStructures.KittyChannel; +import dataStructures.KittyEmbed; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.Response; +import dataStructures.UserInput; +import network.NetworkDerpi; + +public class CommandDerpi extends Command +{ + NetworkDerpi searcher = new NetworkDerpi(); + KittyEmbed response; + + // Required constructor + public CommandDerpi(KittyRole level, KittyRating rating) { super(level, rating); } + + @Override + public String getHelpText() { return "Will search derpibooru for the tags entered, if KittyBot's content filter allows it"; } + + @Override + public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) + { + if(guild.contentRating == KittyRating.Filtered) + { + try + { + response = searcher.getDerpi(input.args.replace(',', ' ') + " safe").output(); + res.send(response); + } + catch(Exception e) + { + res.send(LocStrings.stub("DerpiError")); + } + } + else + { + if(input.args == null || input.args.length() == 0) + res.send("DerpiNoSearchError"); + else + { + response = searcher.getDerpi(input.args).output(); + try + { + res.send(response); + } + catch(Exception e) + { + res.send(LocStrings.stub("DerpiError")); + } + } + } + + if(input.args.startsWith("ID:")) + { + response = searcher.getDerpiByID(input.args.substring(input.args.indexOf(':'))).output(); + try + { + res.send(response); + } + catch(Exception e) + { + res.send(LocStrings.stub("DerpiError")); + } + } + } } \ No newline at end of file diff --git a/src/commands/general/CommandE6.java b/src/commands/general/CommandE6.java index a5d5bb0..cf31858 100644 --- a/src/commands/general/CommandE6.java +++ b/src/commands/general/CommandE6.java @@ -1,60 +1,76 @@ -package commands.general; - -import core.Command; -import core.LocStrings; -import dataStructures.*; -import network.NetworkE6; - -public class CommandE6 extends Command -{ - NetworkE6 searcher = new NetworkE6(); - KittyEmbed response; - - public CommandE6(KittyRole level, KittyRating rating) { super(level, rating); } - - @Override - public String getHelpText() - { - String toRet = "Will search e6"; - toRet += "21 for the tags entered, if KittyBot's content filter allows it"; - return toRet; - } - - @Override - public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) - { - if(guild.contentRating == KittyRating.Filtered || !guild.channels.get(Long.getLong(channel.uniqueID)).mature) - { - if(!guild.channels.get(Long.getLong(channel.uniqueID)).mature) - { - res.send("This channel is SFW only! Have some (probably) wholesome content ^^~"); - } - response = searcher.getE6(input.args + " rating:safe").output(); - try - { - res.send(response); - } - catch(Exception e) - { - res.send(LocStrings.stub("E6Blacklisted")); - } - } - else - { - if(input.args == null || input.args.length() == 0) - res.send("E6NoSearchError"); - else - { - try - { - response = searcher.getE6(input.args).output(); - res.send(response); - } - catch(Exception e) - { - res.send(LocStrings.stub("E6Blacklisted")); - } - } - } - } +package commands.general; + +import core.Command; +import core.LocStrings; +import dataStructures.*; +import network.NetworkE6; + +public class CommandE6 extends Command +{ + NetworkE6 searcher = new NetworkE6(); + KittyEmbed response; + GenericImage image; + + public CommandE6(KittyRole level, KittyRating rating) { super(level, rating); } + + @Override + public String getHelpText() + { + String toRet = "Will search e6"; + toRet += "21 for the tags entered, if KittyBot's content filter allows it"; + return toRet; + } + + @Override + public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) + { + if(guild.contentRating == KittyRating.Filtered || !guild.channels.get(Long.getLong(channel.uniqueID)).mature) + { + if(!guild.channels.get(Long.getLong(channel.uniqueID)).mature) + { + res.send("This channel is SFW only! Have some (probably) wholesome content ^^~"); + } + + image = searcher.getE6(input.args + " rating:safe"); + try + { + response = image.output(); + } + catch(Exception e) + { + res.send(LocStrings.stub("E6Blacklisted")); + return; + } + try + { + if(response.authorText == null) + { + Exception e = new Exception(); + throw e; + } + res.send(response); + } + catch(Exception e) + { + res.send(LocStrings.stub("E6Blacklisted")); + } + } + else + { + if(input.args == null || input.args.length() == 0) + res.send("E6NoSearchError"); + else + { + try + { + response = searcher.getE6(input.args).output(); + res.send(response); + } + catch(Exception e) + { + res.send(LocStrings.stub("E6Blacklisted")); + } + } + } + } } \ No newline at end of file diff --git a/src/commands/music/CommandMusicMain.java b/src/commands/music/CommandMusicMain.java index 7e71fc6..a3534a8 100644 --- a/src/commands/music/CommandMusicMain.java +++ b/src/commands/music/CommandMusicMain.java @@ -18,6 +18,7 @@ public class CommandMusicMain extends Command framework.addCommand("skip", new SubCommandSkip(KittyRole.General, KittyRating.Safe)); framework.addCommand("stop", new SubCommandStop(KittyRole.General, KittyRating.Safe)); framework.addCommand("playlist", new SubCommandPlaylist(KittyRole.General, KittyRating.Safe)); + framework.addCommand("volume", new SubCommandVolume(KittyRole.General, KittyRating.Safe)); } @Override diff --git a/src/commands/music/SubCommandAddTrack.java b/src/commands/music/SubCommandAddTrack.java index 39febae..3dbe47e 100644 --- a/src/commands/music/SubCommandAddTrack.java +++ b/src/commands/music/SubCommandAddTrack.java @@ -1,5 +1,6 @@ package commands.music; +import core.LocStrings; import core.SubCommand; import core.SubCommandFormattable; import dataStructures.KittyChannel; @@ -27,6 +28,6 @@ public class SubCommandAddTrack extends SubCommand video = YT.getYT(video); } guild.audio.playVideo(video); - return new SubCommandFormattable(video); + return new SubCommandFormattable(String.format(LocStrings.stub("MusicAddTrack"), video)); } } \ No newline at end of file diff --git a/src/commands/music/SubCommandSkip.java b/src/commands/music/SubCommandSkip.java index b57ee52..78d0bf6 100644 --- a/src/commands/music/SubCommandSkip.java +++ b/src/commands/music/SubCommandSkip.java @@ -1,23 +1,23 @@ -package commands.music; - -import core.SubCommand; -import core.SubCommandFormattable; -import dataStructures.KittyChannel; -import dataStructures.KittyGuild; -import dataStructures.KittyRating; -import dataStructures.KittyRole; -import dataStructures.KittyUser; -import dataStructures.UserInput; - -public class SubCommandSkip extends SubCommand -{ - public SubCommandSkip(KittyRole level, KittyRating rating) { super(level, rating); } - { - - } - @Override - public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input) - { - return new SubCommandFormattable(guild.audio.skipVideo(guild.audio.player)); - } -} +package commands.music; + +import core.SubCommand; +import core.SubCommandFormattable; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.UserInput; + +public class SubCommandSkip extends SubCommand +{ + public SubCommandSkip(KittyRole level, KittyRating rating) { super(level, rating); } + { + + } + @Override + public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input) + { + return new SubCommandFormattable(guild.audio.skipVideo(guild.audio.player)); + } +} diff --git a/src/commands/music/SubCommandVolume.java b/src/commands/music/SubCommandVolume.java new file mode 100644 index 0000000..ab45d59 --- /dev/null +++ b/src/commands/music/SubCommandVolume.java @@ -0,0 +1,42 @@ +package commands.music; + +import core.LocStrings; +import core.SubCommand; +import core.SubCommandFormattable; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.UserInput; + +public class SubCommandVolume extends SubCommand +{ + public SubCommandVolume(KittyRole level, KittyRating rating) { super(level, rating); } + { + + } + @Override + public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input) + { + int newVol = guild.audio.getVolume(guild.audio.player); + if(input.args != null) + { + try + { + newVol = Integer.parseInt(input.args); + if(newVol > 100 || newVol <1) + { + return new SubCommandFormattable(String.format(LocStrings.stub("MusicVolOOB"))); + } + guild.audio.changeVolume(guild.audio.player, newVol); + } + catch(Exception e) + { + return new SubCommandFormattable(String.format(LocStrings.stub("MusicVolCurrent"), newVol)); + } + + } + return new SubCommandFormattable(String.format(LocStrings.stub("MusicVolChanged"), newVol)); + } +} \ No newline at end of file diff --git a/src/core/CommandManager.java b/src/core/CommandManager.java index e532e79..d356519 100644 --- a/src/core/CommandManager.java +++ b/src/core/CommandManager.java @@ -1,234 +1,235 @@ -package core; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map.Entry; - -import commands.characters.CommandCharacterMain; -import commands.general.*; -import commands.guildrole.CommandGuildRoleMain; -import commands.mod.CommandModMain; -import commands.music.CommandMusicMain; -import commands.poll.CommandPollMain; -import commands.raffle.CommandRaffleMain; -import dataStructures.*; -import utils.GlobalLog; -import utils.LogFilter; - -public class CommandManager -{ - // Variables - private HashMap commands; - private ArrayList threadAccumulator; - private CommandEnabler commandEnabler; - private long invokeCount; - - // Singleton - public static CommandManager instance; - - // Default Constructor - public CommandManager(CommandEnabler commandEnabler) - { - GlobalLog.log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName()); - - if(instance == null) - { - this.commands = new HashMap(); - this.threadAccumulator = new ArrayList(); - this.invokeCount = 0; - this.commandEnabler = commandEnabler; - - registerAllCommands(); - - instance = this; - } - else - { - GlobalLog.error(LogFilter.Core, "You can't have two of the following: " + this.getClass().getSimpleName()); - } - } - - // Registers all the commands for the instance - public void registerAllCommands() - { - this.commands.clear(); - - // Dev - this.register(LocCommands.stub("work"), new CommandDoWork(KittyRole.Dev, KittyRating.Safe)); - this.register(LocCommands.stub("shutdown"), new CommandShutdown(KittyRole.Dev, KittyRating.Safe)); - this.register(LocCommands.stub("stats"), new CommandStats(KittyRole.Dev, KittyRating.Safe)); - this.register(LocCommands.stub("invite"), new CommandInvite(KittyRole.Dev, KittyRating.Safe)); - this.register(LocCommands.stub("buildHelp"), new CommandHelpBuilder(KittyRole.Dev, KittyRating.Safe)); - this.register(LocCommands.stub("tweet"), new CommandTweet(KittyRole.Dev, KittyRating.Safe)); - this.register(LocCommands.stub("dbflush"), new CommandDBFlush(KittyRole.Dev, KittyRating.Safe)); - this.register(LocCommands.stub("dbstats"), new CommandDBStats(KittyRole.Dev, KittyRating.Safe)); - - // Admin - this.register(LocCommands.stub("rating"), new CommandRating(KittyRole.Admin, KittyRating.Safe)); - this.register(LocCommands.stub("indicator"), new CommandChangeIndicator(KittyRole.Admin, KittyRating.Safe)); - - // Mod - this.register(LocCommands.stub("givebeans"), new CommandGiveBeans(KittyRole.Mod, KittyRating.Safe)); - this.register(LocCommands.stub("mod"), new CommandModMain(KittyRole.Mod, KittyRating.Safe)); - - // General - this.register(LocCommands.stub("fetch"), new CommandFetch(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("teey"), new CommandTeey(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("perish, thenperish"), new CommandPerish(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("yeet"), new CommandYeet(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("ping"), new CommandPing(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("boop"), new CommandBoop(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("roll"), new CommandRoll(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("choose"), new CommandChoose(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("help"), new CommandHelp(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("info, about"), new CommandInfo(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("wolfram"), new CommandWolfram(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("c++, g++, cplus, cpp"), new CommandColiru(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("java, jdoodle"), new CommandJDoodle(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("beans"), new CommandBeansShow(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("kittyrole"), new CommandRole(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("bet"), new CommandBetBeans(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("map"), new CommandMap(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("rpstart"), new CommandRPStart(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("rpend"), new CommandRPEnd(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("tony, stark, dontfeelgood, dontfeelsogood"), new CommandStark(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("blur"), new CommandBlurry(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("eightball, 8ball"), new CommandEightBall(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("catch"), new CommandCatch(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("bethistory"), new CommandBetHistory(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("crouton"), new CommandCrouton(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("benchmark, bench"), new CommandBenchmark(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("leaderboard"), new CommandLeaderboard(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("color, colour"), new CommandColor(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("remind"), new CommandRemind(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("role"), new CommandGuildRoleMain(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("character"), new CommandCharacterMain(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("raffle"), new CommandRaffleMain(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("poll"), new CommandPollMain(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("music"), new CommandMusicMain(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("defaultdance"), new CommandDefaultDance(KittyRole.General, KittyRating.Safe)); - this.register(LocCommands.stub("getsauce"), new CommandGetSauce(KittyRole.General, KittyRating.Safe)); - - this.register(LocCommands.stub("e6"), new CommandE6(KittyRole.General, KittyRating.Filtered)); - this.register(LocCommands.stub("derpi"), new CommandDerpi(KittyRole.General, KittyRating.Filtered)); - } - - // Allows the command manager to keep track of a command. Takes a pair (the un-localized and localzied commands) - // and the command associated with the localized commands. - public void register(Pair pair, Command command) - { - if(pair == null || pair.Second == null) - return; - - String[] keys = pair.Second.split(","); - - for(int i = 0; i < keys.length; ++i) - { - String key = keys[i].trim().toLowerCase(); - - command.registeredNames.add(key); - Command old = commands.put(key, command); - - if(old != null) - { - GlobalLog.warn(LogFilter.Core, "Writing over a command with the key " + key); - return; - } - - GlobalLog.log(LogFilter.Core, "Command registered under key " + key); - } - } - - // Calls the command but on a whole new thread! - public boolean invokeOnNewThread(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) - { - // This is here to prevent spinning up a thread if this wasn't even a command. - if(input == null || !input.isValid()) - return false; - - // At this point, verify that the command is enabled. If we don't have any info - // on if it's enabled or not, we assume it's enabled to prevent broken functionality due - // to formatting or casing issues. - if(input.key != null && !commandEnabler.isEnabled(input.key)) - return false; - - Command command = commands.get(input.key); - if(command != null) - { - // Spin up a thread and begin it. The thread carries the info needed to invoke the command. - CommandThread newThread = new CommandThread(this, input, guild, channel, user, responseContext); - threadAccumulator.add(newThread); - newThread.start(); - return true; - } - else - { - GlobalLog.warn(LogFilter.Command, "User " + user.name + " tried to invoke command that doesn't exist: " + input.key); - return false; - } - } - - // Calls the command specified with the key, providing user information arguments, etc. - void invoke(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) - { - if(input == null || !input.isValid()) - return; - - Command command = commands.get(input.key); - if(command != null) - { - ++invokeCount; - command.invoke(guild, channel, user, input, responseContext); - } - } - - // Looks up command by name. If it exists, dumps help text, otherwise returns null. - public String getCommandHelpText(String key) - { - Command command = commands.get(key); - - if(command != null) - return "`" + key + "`: " + command.getHelpText(); - - return null; - } - - // Returns the number of commands sent so far during this program run - public long getInvokeCount() - { - return invokeCount; - } - - // Returns all commands by name - public ArrayList getAllRegisteredCommands() - { - ArrayList cmds = new ArrayList(); - for(Entry entry : commands.entrySet()) - cmds.add(entry.getValue()); - - return cmds; - } - - // Info about threads running packaged into an object - public class ThreadData - { - public HashMap states = new HashMap(); - } - public ThreadData dumpThreadData() - { - ThreadData data = new ThreadData(); - - for(int i = 0; i < threadAccumulator.size(); ++i) - { - Thread.State state = threadAccumulator.get(i).getState(); - Integer num = data.states.get(state); - - if(num == null) - num = 0; - - data.states.put(state, num + 1); - } - - return data; - } -} +package core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; + +import commands.characters.CommandCharacterMain; +import commands.general.*; +import commands.guildrole.CommandGuildRoleMain; +import commands.mod.CommandModMain; +import commands.music.CommandMusicMain; +import commands.poll.CommandPollMain; +import commands.raffle.CommandRaffleMain; +import dataStructures.*; +import utils.GlobalLog; +import utils.LogFilter; + +public class CommandManager +{ + // Variables + private HashMap commands; + private ArrayList threadAccumulator; + private CommandEnabler commandEnabler; + private long invokeCount; + + // Singleton + public static CommandManager instance; + + // Default Constructor + public CommandManager(CommandEnabler commandEnabler) + { + GlobalLog.log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName()); + + if(instance == null) + { + this.commands = new HashMap(); + this.threadAccumulator = new ArrayList(); + this.invokeCount = 0; + this.commandEnabler = commandEnabler; + + registerAllCommands(); + + instance = this; + } + else + { + GlobalLog.error(LogFilter.Core, "You can't have two of the following: " + this.getClass().getSimpleName()); + } + } + + // Registers all the commands for the instance + public void registerAllCommands() + { + this.commands.clear(); + + // Dev + this.register(LocCommands.stub("work"), new CommandDoWork(KittyRole.Dev, KittyRating.Safe)); + this.register(LocCommands.stub("shutdown"), new CommandShutdown(KittyRole.Dev, KittyRating.Safe)); + this.register(LocCommands.stub("stats"), new CommandStats(KittyRole.Dev, KittyRating.Safe)); + this.register(LocCommands.stub("invite"), new CommandInvite(KittyRole.Dev, KittyRating.Safe)); + this.register(LocCommands.stub("buildHelp"), new CommandHelpBuilder(KittyRole.Dev, KittyRating.Safe)); + this.register(LocCommands.stub("tweet"), new CommandTweet(KittyRole.Dev, KittyRating.Safe)); + this.register(LocCommands.stub("dbflush"), new CommandDBFlush(KittyRole.Dev, KittyRating.Safe)); + this.register(LocCommands.stub("dbstats"), new CommandDBStats(KittyRole.Dev, KittyRating.Safe)); + + // Admin + this.register(LocCommands.stub("rating"), new CommandRating(KittyRole.Admin, KittyRating.Safe)); + this.register(LocCommands.stub("indicator"), new CommandChangeIndicator(KittyRole.Admin, KittyRating.Safe)); + + // Mod + this.register(LocCommands.stub("givebeans"), new CommandGiveBeans(KittyRole.Mod, KittyRating.Safe)); + this.register(LocCommands.stub("mod"), new CommandModMain(KittyRole.Mod, KittyRating.Safe)); + + // General + this.register(LocCommands.stub("fetch"), new CommandFetch(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("teey"), new CommandTeey(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("perish, thenperish"), new CommandPerish(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("yeet"), new CommandYeet(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("ping"), new CommandPing(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("boop"), new CommandBoop(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("roll"), new CommandRoll(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("choose"), new CommandChoose(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("help"), new CommandHelp(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("info, about"), new CommandInfo(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("wolfram"), new CommandWolfram(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("c++, g++, cplus, cpp"), new CommandColiru(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("java, jdoodle"), new CommandJDoodle(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("beans"), new CommandBeansShow(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("kittyrole"), new CommandRole(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("bet"), new CommandBetBeans(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("map"), new CommandMap(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("rpstart"), new CommandRPStart(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("rpend"), new CommandRPEnd(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("tony, stark, dontfeelgood, dontfeelsogood"), new CommandStark(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("blur"), new CommandBlurry(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("eightball, 8ball"), new CommandEightBall(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("catch"), new CommandCatch(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("bethistory"), new CommandBetHistory(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("crouton"), new CommandCrouton(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("benchmark, bench"), new CommandBenchmark(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("leaderboard"), new CommandLeaderboard(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("color, colour"), new CommandColor(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("remind"), new CommandRemind(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("role"), new CommandGuildRoleMain(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("character"), new CommandCharacterMain(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("raffle"), new CommandRaffleMain(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("poll"), new CommandPollMain(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("music"), new CommandMusicMain(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("defaultdance"), new CommandDefaultDance(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("getsauce"), new CommandGetSauce(KittyRole.General, KittyRating.Safe)); + this.register(LocCommands.stub("tradebeans"), new CommandTradeBeans(KittyRole.General, KittyRating.Safe)); + + this.register(LocCommands.stub("e6"), new CommandE6(KittyRole.General, KittyRating.Filtered)); + this.register(LocCommands.stub("derpi"), new CommandDerpi(KittyRole.General, KittyRating.Filtered)); + } + + // Allows the command manager to keep track of a command. Takes a pair (the un-localized and localzied commands) + // and the command associated with the localized commands. + public void register(Pair pair, Command command) + { + if(pair == null || pair.Second == null) + return; + + String[] keys = pair.Second.split(","); + + for(int i = 0; i < keys.length; ++i) + { + String key = keys[i].trim().toLowerCase(); + + command.registeredNames.add(key); + Command old = commands.put(key, command); + + if(old != null) + { + GlobalLog.warn(LogFilter.Core, "Writing over a command with the key " + key); + return; + } + + GlobalLog.log(LogFilter.Core, "Command registered under key " + key); + } + } + + // Calls the command but on a whole new thread! + public boolean invokeOnNewThread(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) + { + // This is here to prevent spinning up a thread if this wasn't even a command. + if(input == null || !input.isValid()) + return false; + + // At this point, verify that the command is enabled. If we don't have any info + // on if it's enabled or not, we assume it's enabled to prevent broken functionality due + // to formatting or casing issues. + if(input.key != null && !commandEnabler.isEnabled(input.key)) + return false; + + Command command = commands.get(input.key); + if(command != null) + { + // Spin up a thread and begin it. The thread carries the info needed to invoke the command. + CommandThread newThread = new CommandThread(this, input, guild, channel, user, responseContext); + threadAccumulator.add(newThread); + newThread.start(); + return true; + } + else + { + GlobalLog.warn(LogFilter.Command, "User " + user.name + " tried to invoke command that doesn't exist: " + input.key); + return false; + } + } + + // Calls the command specified with the key, providing user information arguments, etc. + void invoke(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) + { + if(input == null || !input.isValid()) + return; + + Command command = commands.get(input.key); + if(command != null) + { + ++invokeCount; + command.invoke(guild, channel, user, input, responseContext); + } + } + + // Looks up command by name. If it exists, dumps help text, otherwise returns null. + public String getCommandHelpText(String key) + { + Command command = commands.get(key); + + if(command != null) + return "`" + key + "`: " + command.getHelpText(); + + return null; + } + + // Returns the number of commands sent so far during this program run + public long getInvokeCount() + { + return invokeCount; + } + + // Returns all commands by name + public ArrayList getAllRegisteredCommands() + { + ArrayList cmds = new ArrayList(); + for(Entry entry : commands.entrySet()) + cmds.add(entry.getValue()); + + return cmds; + } + + // Info about threads running packaged into an object + public class ThreadData + { + public HashMap states = new HashMap(); + } + public ThreadData dumpThreadData() + { + ThreadData data = new ThreadData(); + + for(int i = 0; i < threadAccumulator.size(); ++i) + { + Thread.State state = threadAccumulator.get(i).getState(); + Integer num = data.states.get(state); + + if(num == null) + num = 0; + + data.states.put(state, num + 1); + } + + return data; + } +} diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index ccd7b04..f01912d 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -1,479 +1,479 @@ -package core; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.Semaphore; - -import javax.security.auth.login.LoginException; - -import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; -import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; -import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; - -//import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; -//import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; - -import core.lua.PluginManager; -import dataStructures.KittyChannel; -import dataStructures.KittyCore; -import dataStructures.KittyGuild; -import dataStructures.KittyRating; -import dataStructures.KittyRole; -import dataStructures.KittyStartupMode; -import dataStructures.KittyUser; -import main.Main; -import net.dv8tion.jda.core.AccountType; -import net.dv8tion.jda.core.JDA; -import net.dv8tion.jda.core.JDABuilder; -import net.dv8tion.jda.core.entities.Emote; -import net.dv8tion.jda.core.entities.Game; -import net.dv8tion.jda.core.entities.Guild; -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.User; -import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; -import offline.Ref; -import utils.AdminControl; -//import utils.AudioUtils; -import utils.GlobalLog; -import utils.LogFilter; -import utils.audio.AudioUtils; - -// NOTE(wisp): Isolated factory to assist with storage and caching if needed. -// This also minimizes the number of places JDA interacts with our codebase. -// As it stands, if the object name begins with Kitty, it's constructed here. -// TODO: Make all methods ID based instead of event based -public class ObjectBuilderFactory -{ - // Key: guild string id, Value: guild information - private static HashMap guildCache; - - // Key: channel string id, Value: channel information - private static HashMap channelCache; - - // Key: guild string id + user string id, Value: user information - private static HashMap userCache; - - // For tracking and managing object sync - private static DatabaseManager database; - - // Stats tracking and whatnot... for setting stats too internally potentially - private static Stats stats; - - // RPManger for tracking RP system - private static RPManager rpManager; - - // Plugin manager - private static PluginManager pluginManager; - - // Command manager - private static CommandManager commandManager; - - //Audio track manager - private static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); - - // Localization classes - these are singletons, but should be initialized before almost all other - // things so their inclusion in the factory is to ensure they're started at the correct time. - @SuppressWarnings("unused") private static LocStrings locStrings; - @SuppressWarnings("unused") private static LocCommands locCommands; - - // Config - @SuppressWarnings("unused") private static Config config; - - // Lazy initialization multithreaded mutex stuff to prevent explosions. - // TODO: Investigate using 'synchronized' instead potentially - private static boolean hasInitialized; - private static Semaphore initMutex = new Semaphore(1); - private static JDA kitty; - - // This is it, this is how the lazy init starts! - private static void lazyInit() - { - if(hasInitialized) - return; - - try - { - initMutex.acquire(); - try - { - // structure initialization - // Construct necessary data structures. - guildCache = new HashMap(); - userCache = new HashMap(); - channelCache = new HashMap(); - database = null; - stats = null; - - AudioSourceManagers.registerRemoteSources(playerManager); - AudioSourceManagers.registerLocalSource(playerManager); - - // Start by reading from things that are external. Because - // we require these things to be resolved before the rest of the application, - // we place them here. - config = new Config(); - } - finally - { - initMutex.release(); - hasInitialized = true; - } - } - catch(InterruptedException ie) - { - GlobalLog.error(LogFilter.Core, "Issue during object builder lazy initialization." - + " The factory was not initialized, and kitty will not be able to continue functionally."); - } - } - - //////////////////////// - // Extraction Methods // - //////////////////////// - - // Explicitly locks: guildCache - public static KittyGuild extractGuild(GuildMessageReceivedEvent event) - { - lazyInit(); - - // Look up the guild. This process can only happen in a single-threaded way - // because of the nature of the cache. We wait until the last second to - // look up the guild. - String uid = event.getGuild().getId(); - - List emotes = event.getGuild().getEmotes(); - ArrayList emotesString = new ArrayList(); - HashMap channels = new HashMap(); - String emote; - String emoteFix; - channels.put(Long.getLong(uid), extractChannel(event)); - for(int i = 0; i < emotes.size(); i++) - { - emote = emotes.get(i).toString(); - emoteFix = "<:" + emote.substring(2, emote.indexOf("(")); - emoteFix += ":" + emote.substring(emote.indexOf("(")+1, emote.length()-1) + ">"; - emotesString.add(emoteFix); - } - - // once we're lazily initialized, we can synchronize w/ the - // guildCache object now instead of having to use a mutex. - KittyGuild guild = null; - synchronized (guildCache) - { - KittyGuild cachedGuild = guildCache.get(uid); - if(cachedGuild != null) - { - guild = cachedGuild; - } - else - { - // Construct a new guild with defaults - guild = new KittyGuild(uid, new AdminControl(event.getGuild()), emotesString, new AudioUtils(event.getGuild(), playerManager), channels); - DatabaseManager.instance.globalRegister(guild); - guildCache.put(uid, guild); - } - } - - return guild; - } - - // Explicitly locks: guildCache - public static KittyRole extractRole(GuildMessageReceivedEvent event) - { - lazyInit(); - - // Looks up the user role. If none is found we check to see if they own - // the guild if not, they're assumed to be - // allowed to use the bot at a general level. - KittyRole role = KittyRole.General; - - if(event.getAuthor().getId() == event.getGuild().getOwner().getUser().getId()) - { - role = KittyRole.Admin; - } - - String uid = event.getGuild().getId() + event.getAuthor().getId(); - synchronized(userCache) - { - KittyUser cachedUser = userCache.get(uid); - if(cachedUser != null) - role = cachedUser.getRole(); - } - - return role; - } - - // Explicitly locks: guildCache - // Extracts the content rating information it can from the provided event. - public static KittyRating extractContentRating(GuildMessageReceivedEvent event) - { - lazyInit(); - - // Look up content rating of the guild, returns a safe content rating. - KittyRating contentRating = KittyRating.Safe; - String uid = event.getGuild().getId(); - synchronized(guildCache) - { - KittyGuild cachedGuild = guildCache.get(uid); - if(cachedGuild != null) - contentRating = cachedGuild.contentRating; - } - - return contentRating; - } - - // Implicitly locks guild cache by calling ExtractGuild - public static KittyChannel extractChannel(GuildMessageReceivedEvent event) - { - lazyInit(); - String channelID = event.getChannel().getId(); - KittyChannel channel = null; - - synchronized(channelCache) - { - KittyChannel cachedChannel = channelCache.get(channelID); - boolean mature; - - if(cachedChannel != null) - { - channel = cachedChannel; - } - else - { - mature = event.getChannel().isNSFW(); - channel = new KittyChannel(channelID, mature); - channelCache.put(channelID, channel); - } - } - - return channel; - } - - // Implicitly locks guild cache by calling ExtractRole and ExtractGuild - public static KittyUser extractUser(GuildMessageReceivedEvent event) - { - lazyInit(); - - String uid = event.getGuild().getId() + event.getAuthor().getId(); - KittyUser user = null; - synchronized(userCache) - { - KittyUser cachedUser = userCache.get(uid); - if(cachedUser != null) - { - updateUser(cachedUser, event.getMember()); - user = cachedUser; - } - else - { - KittyRole role = extractRole(event); - KittyGuild guild = extractGuild(event); - - String name; - if(event.getMember().getNickname() == null) - name = event.getAuthor().getName(); - else - name = event.getMember().getNickname(); - - String discordID = event.getMember().getUser().getId(); - String avatarID = event.getAuthor().getAvatarUrl(); - user = new KittyUser(name, guild, role, uid, avatarID, discordID); - DatabaseManager.instance.globalRegister(user); - userCache.put(uid, user); - } - } - - if(event.getMessage().getMentionedMembers().isEmpty()) - return user; - - Member mentioned; - for(int i = 0; i < event.getMessage().getMentionedMembers().size(); i++) - { - mentioned = event.getMessage().getMentionedMembers().get(i); - if(mentioned.getNickname() != null) - extractUserByJDAUser(event.getGuild().getId(), mentioned.getNickname(), - mentioned.getUser().getId(), mentioned.getUser().getAvatarUrl(), mentioned.getUser().getId()); - else - extractUserByJDAUser(event.getGuild().getId(), mentioned.getUser().getName(), - mentioned.getUser().getId(), mentioned.getUser().getAvatarUrl(), mentioned.getUser().getId()); - } - - return user; - } - - // TODO: Clean up - public static KittyUser extractUserByJDAUser(String guildID, String name, String userID, String avatarID, String discordID) - { - lazyInit(); - - String uid = guildID + userID; - KittyUser user = null; - synchronized(userCache) - { - KittyUser cachedUser = userCache.get(uid); - if(cachedUser != null) - { - if(name != null) - cachedUser.name = name; - - cachedUser.avatarID = avatarID; - user = cachedUser; - } - else - { - KittyRole role = KittyRole.General; - KittyGuild guild = guildCache.get(guildID); - user = new KittyUser(name, guild, role, uid, avatarID, discordID); - DatabaseManager.instance.globalRegister(user); - userCache.put(uid, user); - } - } - - return user; - } - - // There is some redundant lookup occurring. If the user isn't cached yet, then we construct them and cache them. - // The assumption is made that the user does, in fact, exist. - public static KittyUser getKittyUser(String guildID, String userID) - { - String uid = guildID + userID; - KittyUser user = null; - synchronized(userCache) - { - user = userCache.get(uid); - } - - if(user == null) - { - Guild jdaGuild = kitty.getGuildById(guildID); - if(jdaGuild == null) return null; - - Member jdaMember = jdaGuild.getMemberById(userID); - if(jdaMember == null) return null; - - User jdaUser = jdaMember.getUser(); - if(jdaUser == null) return null; - - user = extractUserByJDAUser(guildID, jdaMember.getNickname(), jdaUser.getId(), jdaUser.getAvatarUrl(), jdaUser.getId()); - updateUser(user, jdaMember); - } - - return user; - } - - // Updates a user's name appropriately based on nickname if available - public static void updateUser(KittyUser user, Member member) - { - if(member.getNickname() == null) - { - user.name = member.getUser().getName(); - } - else - { - user.name = member.getNickname(); - } - - user.avatarID = member.getUser().getAvatarUrl(); - } - - - ////////////////////////// - // Construction Methods // - ////////////////////////// - // Builds the core of the bot - public static KittyCore constructKittyCore() throws LoginException, InterruptedException - { - lazyInit(); - - // Determine token based on config. Default to test token. - String tokenToUse = Ref.TestToken; - if(ConfigGlobals.getStartupMode() == KittyStartupMode.Release) - tokenToUse = Ref.Token; - - // Construct bot based on token - kitty = new JDABuilder(AccountType.BOT) - .setToken(tokenToUse).buildBlocking(); - kitty.getPresence().setGame(Game.playing("with a laser pointer")); - kitty.addEventListener(new Main()); - - return new KittyCore(kitty); - } - - // Default construction of the command manager. In order to remotely resolve command enabling - // and disabling, what we do is construct the commands with a localized pair that is checked against - // the CommandEnabler object passed in. In theory, we could have multiple CommandManagers, tho we can - // only have one CommandEnabler. - public static CommandManager constructCommandManager(CommandEnabler commandEnabler) - { - lazyInit(); - - if(commandManager == null) - commandManager = new CommandManager(commandEnabler); - - return commandManager; - } - - // Default database manager construction. It can be constructed - // in different ways, and so we construct it outside of the constructor for - // the factory since it doesn't have to be present / can be elsewhere. - // Effectively we cache the database here. - public static DatabaseManager constructDatabaseManager() - { - lazyInit(); - - if(database == null) - database = new DatabaseManager(); - - return database; - } - - public static Stats constructStats(CommandManager manager) - { - lazyInit(); - - if(stats == null) - stats = new Stats(manager); - - return stats; - } - - public static RPManager constructRPManager() - { - lazyInit(); - - if(rpManager == null) - rpManager = new RPManager(); - - return rpManager; - } - - public static PluginManager constructPluginManager() - { - lazyInit(); - - if(pluginManager == null) - pluginManager = new PluginManager(Constants.AssetDirectory + "plugins/"); - - return pluginManager; - } - - - ///////////////////// - // Utility Methods // - ///////////////////// - - // Returns number of cached guilds (does not equal total users in the database, only what's in memory) - public static Integer getGuildCount() - { synchronized(guildCache) - { - return guildCache.size(); - } - } - - // Returns number of cached users (does not equal total users in the database, only what's in memory) - public static Integer getUserCount() - { synchronized(userCache) - { - return userCache.size(); - } - } +package core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.Semaphore; + +import javax.security.auth.login.LoginException; + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; + +//import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +//import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; + +import core.lua.PluginManager; +import dataStructures.KittyChannel; +import dataStructures.KittyCore; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyStartupMode; +import dataStructures.KittyUser; +import main.Main; +import net.dv8tion.jda.core.AccountType; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.JDABuilder; +import net.dv8tion.jda.core.entities.Emote; +import net.dv8tion.jda.core.entities.Game; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import offline.Ref; +import utils.AdminControl; +//import utils.AudioUtils; +import utils.GlobalLog; +import utils.LogFilter; +import utils.audio.AudioUtils; + +// NOTE(wisp): Isolated factory to assist with storage and caching if needed. +// This also minimizes the number of places JDA interacts with our codebase. +// As it stands, if the object name begins with Kitty, it's constructed here. +// TODO: Make all methods ID based instead of event based +public class ObjectBuilderFactory +{ + // Key: guild string id, Value: guild information + private static HashMap guildCache; + + // Key: channel string id, Value: channel information + private static HashMap channelCache; + + // Key: guild string id + user string id, Value: user information + private static HashMap userCache; + + // For tracking and managing object sync + private static DatabaseManager database; + + // Stats tracking and whatnot... for setting stats too internally potentially + private static Stats stats; + + // RPManger for tracking RP system + private static RPManager rpManager; + + // Plugin manager + private static PluginManager pluginManager; + + // Command manager + private static CommandManager commandManager; + + //Audio track manager + private static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); + + // Localization classes - these are singletons, but should be initialized before almost all other + // things so their inclusion in the factory is to ensure they're started at the correct time. + @SuppressWarnings("unused") private static LocStrings locStrings; + @SuppressWarnings("unused") private static LocCommands locCommands; + + // Config + @SuppressWarnings("unused") private static Config config; + + // Lazy initialization multithreaded mutex stuff to prevent explosions. + // TODO: Investigate using 'synchronized' instead potentially + private static boolean hasInitialized; + private static Semaphore initMutex = new Semaphore(1); + private static JDA kitty; + + // This is it, this is how the lazy init starts! + private static void lazyInit() + { + if(hasInitialized) + return; + + try + { + initMutex.acquire(); + try + { + // structure initialization + // Construct necessary data structures. + guildCache = new HashMap(); + userCache = new HashMap(); + channelCache = new HashMap(); + database = null; + stats = null; + + AudioSourceManagers.registerRemoteSources(playerManager); + AudioSourceManagers.registerLocalSource(playerManager); + + // Start by reading from things that are external. Because + // we require these things to be resolved before the rest of the application, + // we place them here. + config = new Config(); + } + finally + { + initMutex.release(); + hasInitialized = true; + } + } + catch(InterruptedException ie) + { + GlobalLog.error(LogFilter.Core, "Issue during object builder lazy initialization." + + " The factory was not initialized, and kitty will not be able to continue functionally."); + } + } + + //////////////////////// + // Extraction Methods // + //////////////////////// + + // Explicitly locks: guildCache + public static KittyGuild extractGuild(GuildMessageReceivedEvent event) + { + lazyInit(); + + // Look up the guild. This process can only happen in a single-threaded way + // because of the nature of the cache. We wait until the last second to + // look up the guild. + String uid = event.getGuild().getId(); + + List emotes = event.getGuild().getEmotes(); + ArrayList emotesString = new ArrayList(); + HashMap channels = new HashMap(); + String emote; + String emoteFix; + channels.put(Long.getLong(uid), extractChannel(event)); + for(int i = 0; i < emotes.size(); i++) + { + emote = emotes.get(i).toString(); + emoteFix = "<:" + emote.substring(2, emote.indexOf("(")); + emoteFix += ":" + emote.substring(emote.indexOf("(")+1, emote.length()-1) + ">"; + emotesString.add(emoteFix); + } + + // once we're lazily initialized, we can synchronize w/ the + // guildCache object now instead of having to use a mutex. + KittyGuild guild = null; + synchronized (guildCache) + { + KittyGuild cachedGuild = guildCache.get(uid); + if(cachedGuild != null) + { + guild = cachedGuild; + } + else + { + // Construct a new guild with defaults + guild = new KittyGuild(uid, new AdminControl(event.getGuild()), emotesString, new AudioUtils(event.getGuild(), playerManager), channels); + DatabaseManager.instance.globalRegister(guild); + guildCache.put(uid, guild); + } + } + + return guild; + } + + // Explicitly locks: guildCache + public static KittyRole extractRole(GuildMessageReceivedEvent event) + { + lazyInit(); + + // Looks up the user role. If none is found we check to see if they own + // the guild if not, they're assumed to be + // allowed to use the bot at a general level. + KittyRole role = KittyRole.General; + + if(event.getAuthor().getId() == event.getGuild().getOwner().getUser().getId()) + { + role = KittyRole.Admin; + } + + String uid = event.getGuild().getId() + event.getAuthor().getId(); + synchronized(userCache) + { + KittyUser cachedUser = userCache.get(uid); + if(cachedUser != null) + role = cachedUser.getRole(); + } + + return role; + } + + // Explicitly locks: guildCache + // Extracts the content rating information it can from the provided event. + public static KittyRating extractContentRating(GuildMessageReceivedEvent event) + { + lazyInit(); + + // Look up content rating of the guild, returns a safe content rating. + KittyRating contentRating = KittyRating.Safe; + String uid = event.getGuild().getId(); + synchronized(guildCache) + { + KittyGuild cachedGuild = guildCache.get(uid); + if(cachedGuild != null) + contentRating = cachedGuild.contentRating; + } + + return contentRating; + } + + // Implicitly locks guild cache by calling ExtractGuild + public static KittyChannel extractChannel(GuildMessageReceivedEvent event) + { + lazyInit(); + String channelID = event.getChannel().getId(); + KittyChannel channel = null; + + synchronized(channelCache) + { + KittyChannel cachedChannel = channelCache.get(channelID); + boolean mature; + + if(cachedChannel != null) + { + channel = cachedChannel; + } + else + { + mature = event.getChannel().isNSFW(); + channel = new KittyChannel(channelID, mature); + channelCache.put(channelID, channel); + } + } + + return channel; + } + + // Implicitly locks guild cache by calling ExtractRole and ExtractGuild + public static KittyUser extractUser(GuildMessageReceivedEvent event) + { + lazyInit(); + + String uid = event.getGuild().getId() + event.getAuthor().getId(); + KittyUser user = null; + synchronized(userCache) + { + KittyUser cachedUser = userCache.get(uid); + if(cachedUser != null) + { + updateUser(cachedUser, event.getMember()); + user = cachedUser; + } + else + { + KittyRole role = extractRole(event); + KittyGuild guild = extractGuild(event); + + String name; + if(event.getMember().getNickname() == null) + name = event.getAuthor().getName(); + else + name = event.getMember().getNickname(); + + String discordID = event.getMember().getUser().getId(); + String avatarID = event.getAuthor().getAvatarUrl(); + user = new KittyUser(name, guild, role, uid, avatarID, discordID); + DatabaseManager.instance.globalRegister(user); + userCache.put(uid, user); + } + } + + if(event.getMessage().getMentionedMembers().isEmpty()) + return user; + + Member mentioned; + for(int i = 0; i < event.getMessage().getMentionedMembers().size(); i++) + { + mentioned = event.getMessage().getMentionedMembers().get(i); + if(mentioned.getNickname() != null) + extractUserByJDAUser(event.getGuild().getId(), mentioned.getNickname(), + mentioned.getUser().getId(), mentioned.getUser().getAvatarUrl(), mentioned.getUser().getId()); + else + extractUserByJDAUser(event.getGuild().getId(), mentioned.getUser().getName(), + mentioned.getUser().getId(), mentioned.getUser().getAvatarUrl(), mentioned.getUser().getId()); + } + + return user; + } + + // TODO: Clean up + public static KittyUser extractUserByJDAUser(String guildID, String name, String userID, String avatarID, String discordID) + { + lazyInit(); + + String uid = guildID + userID; + KittyUser user = null; + synchronized(userCache) + { + KittyUser cachedUser = userCache.get(uid); + if(cachedUser != null) + { + if(name != null) + cachedUser.name = name; + + cachedUser.avatarID = avatarID; + user = cachedUser; + } + else + { + KittyRole role = KittyRole.General; + KittyGuild guild = guildCache.get(guildID); + user = new KittyUser(name, guild, role, uid, avatarID, discordID); + DatabaseManager.instance.globalRegister(user); + userCache.put(uid, user); + } + } + + return user; + } + + // There is some redundant lookup occurring. If the user isn't cached yet, then we construct them and cache them. + // The assumption is made that the user does, in fact, exist. + public static KittyUser getKittyUser(String guildID, String userID) + { + String uid = guildID + userID; + KittyUser user = null; + synchronized(userCache) + { + user = userCache.get(uid); + } + + if(user == null) + { + Guild jdaGuild = kitty.getGuildById(guildID); + if(jdaGuild == null) return null; + + Member jdaMember = jdaGuild.getMemberById(userID); + if(jdaMember == null) return null; + + User jdaUser = jdaMember.getUser(); + if(jdaUser == null) return null; + + user = extractUserByJDAUser(guildID, jdaMember.getNickname(), jdaUser.getId(), jdaUser.getAvatarUrl(), jdaUser.getId()); + updateUser(user, jdaMember); + } + + return user; + } + + // Updates a user's name appropriately based on nickname if available + public static void updateUser(KittyUser user, Member member) + { + if(member.getNickname() == null) + { + user.name = member.getUser().getName(); + } + else + { + user.name = member.getNickname(); + } + + user.avatarID = member.getUser().getAvatarUrl(); + } + + + ////////////////////////// + // Construction Methods // + ////////////////////////// + // Builds the core of the bot + public static KittyCore constructKittyCore() throws LoginException, InterruptedException + { + lazyInit(); + + // Determine token based on config. Default to test token. + String tokenToUse = Ref.TestToken; + if(ConfigGlobals.getStartupMode() == KittyStartupMode.Release) + tokenToUse = Ref.PoguToken; + + // Construct bot based on token + kitty = new JDABuilder(AccountType.BOT) + .setToken(tokenToUse).buildBlocking(); + kitty.getPresence().setGame(Game.playing("with a laser pointer")); + kitty.addEventListener(new Main()); + + return new KittyCore(kitty); + } + + // Default construction of the command manager. In order to remotely resolve command enabling + // and disabling, what we do is construct the commands with a localized pair that is checked against + // the CommandEnabler object passed in. In theory, we could have multiple CommandManagers, tho we can + // only have one CommandEnabler. + public static CommandManager constructCommandManager(CommandEnabler commandEnabler) + { + lazyInit(); + + if(commandManager == null) + commandManager = new CommandManager(commandEnabler); + + return commandManager; + } + + // Default database manager construction. It can be constructed + // in different ways, and so we construct it outside of the constructor for + // the factory since it doesn't have to be present / can be elsewhere. + // Effectively we cache the database here. + public static DatabaseManager constructDatabaseManager() + { + lazyInit(); + + if(database == null) + database = new DatabaseManager(); + + return database; + } + + public static Stats constructStats(CommandManager manager) + { + lazyInit(); + + if(stats == null) + stats = new Stats(manager); + + return stats; + } + + public static RPManager constructRPManager() + { + lazyInit(); + + if(rpManager == null) + rpManager = new RPManager(); + + return rpManager; + } + + public static PluginManager constructPluginManager() + { + lazyInit(); + + if(pluginManager == null) + pluginManager = new PluginManager(Constants.AssetDirectory + "plugins/"); + + return pluginManager; + } + + + ///////////////////// + // Utility Methods // + ///////////////////// + + // Returns number of cached guilds (does not equal total users in the database, only what's in memory) + public static Integer getGuildCount() + { synchronized(guildCache) + { + return guildCache.size(); + } + } + + // Returns number of cached users (does not equal total users in the database, only what's in memory) + public static Integer getUserCount() + { synchronized(userCache) + { + return userCache.size(); + } + } } \ No newline at end of file diff --git a/src/dataStructures/KittyChannel.java b/src/dataStructures/KittyChannel.java index 770bc49..71fc794 100644 --- a/src/dataStructures/KittyChannel.java +++ b/src/dataStructures/KittyChannel.java @@ -1,15 +1,15 @@ -package dataStructures; - - -public class KittyChannel -{ - public String uniqueID; - public boolean mature; - - public KittyChannel(String uniqueID, boolean mature) - { - //super(uniqueID); - this.uniqueID = uniqueID; - this.mature = false; - } +package dataStructures; + + +public class KittyChannel +{ + public String uniqueID; + public boolean mature; + + public KittyChannel(String uniqueID, boolean mature) + { + //super(uniqueID); + this.uniqueID = uniqueID; + this.mature = false; + } } \ No newline at end of file diff --git a/src/dataStructures/KittyGuild.java b/src/dataStructures/KittyGuild.java index 71445b9..6e18606 100644 --- a/src/dataStructures/KittyGuild.java +++ b/src/dataStructures/KittyGuild.java @@ -1,180 +1,180 @@ -package dataStructures; - -import java.util.ArrayList; -import java.util.HashMap; - -import core.DatabaseManager; -import core.DatabaseTrackedObject; -import utils.AdminControl; -import utils.audio.AudioUtils; - -// Context for a given guild for kittybot. Primarily designed to hold guild-specific settings. -public class KittyGuild extends DatabaseTrackedObject -{ - // Variables - public final String uniqueID; - public KittyRating contentRating; - public KittyUser guildOwner; - public boolean polling; - public String poll; - public boolean raffling; - public int raffleCost; - public ArrayList hasVoted = new ArrayList(); - public ArrayList emoji = new ArrayList(); - public ArrayList choices = new ArrayList(); - public HashMap channels; - public AdminControl control; - public AudioUtils audio; - public ArrayList raffleUsersUnchosen = new ArrayList(); - public ArrayList raffleUsersChosen = new ArrayList(); - - // Database synced info - private final String roleListName = "guildRoles"; - public final KittyTrackedVector roleList; - - private final String beansName = "guildBeans"; - public final KittyTrackedLong beans; - - private String commandIndicator; - - private void registerTrackedObjects() - { - DatabaseManager.instance.globalRegister(roleList); - DatabaseManager.instance.globalRegister(beans); - } - - // Default content for a guild - public KittyGuild(String uniqueID, AdminControl adminControl, ArrayList emoji, AudioUtils audio, HashMap channels) - { - - super(uniqueID); - this.uniqueID = uniqueID; - roleList = new KittyTrackedVector(roleListName, uniqueID); - beans = new KittyTrackedLong(beansName, uniqueID); - registerTrackedObjects(); - - control = adminControl; - this.contentRating = KittyRating.Safe; - this.polling = false; - this.emoji = emoji; - this.audio = audio; - this.channels = channels; - setCommandIndicator("!"); - } - - // Explicit constructor - public KittyGuild(String commandIndicator, KittyRating contentRating, KittyUser guildOwner, String uniqueID, AudioUtils audio, HashMap channels) - { - super(uniqueID); - this.uniqueID = uniqueID; - roleList = new KittyTrackedVector(roleListName, uniqueID); - beans = new KittyTrackedLong(beansName, uniqueID); - registerTrackedObjects(); - - setCommandIndicator(commandIndicator); - this.contentRating = contentRating; - this.polling = false; - this.guildOwner = guildOwner; - this.audio = audio; - this.channels = channels; - } - - public String startPoll(String poll) - { - polling = true; - this.poll = poll; - return "Poll `" + poll + "` started! Don't forget to add choices with `!poll choice`~"; - } - - public String addChoiceToPoll(String choice) - { - choices.add(new KittyPoll(choice)); - return "Added `" + choice + "` to poll!"; - } - - public String endPoll() - { - choices.clear(); - hasVoted.clear(); - this.polling = false; - poll = null; - return "Poll ended!"; - } - - //Raffle methods - public boolean startRaffle(int beanCost) - { - if(raffling) - { - return false; - } - raffleCost = beanCost; - raffling = true; - return true; - } - - public boolean endRaffle() - { - if(raffling) - { - raffleCost = 0; - raffling = false; - raffleUsersChosen.removeAll(raffleUsersChosen); - raffleUsersUnchosen.removeAll(raffleUsersUnchosen); - return true; - } - return false; - } - - public boolean joinRaffle(KittyUser user) - { - if(!raffleUsersChosen.contains(user) && !raffleUsersUnchosen.contains(user) && user.getBeans() > raffleCost && raffling) - { - user.changeBeans(raffleCost); - raffleUsersUnchosen.add(user); - return true; - } - return false; - } - - public KittyUser chooseRaffleWinner() - { - if(!raffleUsersUnchosen.isEmpty()) - { - KittyUser chosen = raffleUsersUnchosen.get((int) (Math.random() * raffleUsersUnchosen.size())); - raffleUsersUnchosen.remove(chosen); - raffleUsersChosen.add(chosen); - return chosen; - } - return null; - } - - @Override - public String serialize() - { - return commandIndicator; - } - - @Override - public void deSerialzie(String string) - { - if(string == null || string.length() == 0) - setCommandIndicator("!"); - else - setCommandIndicator(string); - } - - public String getCommandIndicator() - { - return commandIndicator; - } - - public void setCommandIndicator(String newIndicator) - { - if(newIndicator != commandIndicator) - { - commandIndicator = newIndicator; - markDirty(); - } - } -} +package dataStructures; + +import java.util.ArrayList; +import java.util.HashMap; + +import core.DatabaseManager; +import core.DatabaseTrackedObject; +import utils.AdminControl; +import utils.audio.AudioUtils; + +// Context for a given guild for kittybot. Primarily designed to hold guild-specific settings. +public class KittyGuild extends DatabaseTrackedObject +{ + // Variables + public final String uniqueID; + public KittyRating contentRating; + public KittyUser guildOwner; + public boolean polling; + public String poll; + public boolean raffling; + public int raffleCost; + public ArrayList hasVoted = new ArrayList(); + public ArrayList emoji = new ArrayList(); + public ArrayList choices = new ArrayList(); + public HashMap channels; + public AdminControl control; + public AudioUtils audio; + public ArrayList raffleUsersUnchosen = new ArrayList(); + public ArrayList raffleUsersChosen = new ArrayList(); + + // Database synced info + private final String roleListName = "guildRoles"; + public final KittyTrackedVector roleList; + + private final String beansName = "guildBeans"; + public final KittyTrackedLong beans; + + private String commandIndicator; + + private void registerTrackedObjects() + { + DatabaseManager.instance.globalRegister(roleList); + DatabaseManager.instance.globalRegister(beans); + } + + // Default content for a guild + public KittyGuild(String uniqueID, AdminControl adminControl, ArrayList emoji, AudioUtils audio, HashMap channels) + { + + super(uniqueID); + this.uniqueID = uniqueID; + roleList = new KittyTrackedVector(roleListName, uniqueID); + beans = new KittyTrackedLong(beansName, uniqueID); + registerTrackedObjects(); + + control = adminControl; + this.contentRating = KittyRating.Safe; + this.polling = false; + this.emoji = emoji; + this.audio = audio; + this.channels = channels; + setCommandIndicator("!"); + } + + // Explicit constructor + public KittyGuild(String commandIndicator, KittyRating contentRating, KittyUser guildOwner, String uniqueID, AudioUtils audio, HashMap channels) + { + super(uniqueID); + this.uniqueID = uniqueID; + roleList = new KittyTrackedVector(roleListName, uniqueID); + beans = new KittyTrackedLong(beansName, uniqueID); + registerTrackedObjects(); + + setCommandIndicator(commandIndicator); + this.contentRating = contentRating; + this.polling = false; + this.guildOwner = guildOwner; + this.audio = audio; + this.channels = channels; + } + + public String startPoll(String poll) + { + polling = true; + this.poll = poll; + return "Poll `" + poll + "` started! Don't forget to add choices with `!poll choice`~"; + } + + public String addChoiceToPoll(String choice) + { + choices.add(new KittyPoll(choice)); + return "Added `" + choice + "` to poll!"; + } + + public String endPoll() + { + choices.clear(); + hasVoted.clear(); + this.polling = false; + poll = null; + return "Poll ended!"; + } + + //Raffle methods + public boolean startRaffle(int beanCost) + { + if(raffling) + { + return false; + } + raffleCost = beanCost; + raffling = true; + return true; + } + + public boolean endRaffle() + { + if(raffling) + { + raffleCost = 0; + raffling = false; + raffleUsersChosen.removeAll(raffleUsersChosen); + raffleUsersUnchosen.removeAll(raffleUsersUnchosen); + return true; + } + return false; + } + + public boolean joinRaffle(KittyUser user) + { + if(!raffleUsersChosen.contains(user) && !raffleUsersUnchosen.contains(user) && user.getBeans() > raffleCost && raffling) + { + user.changeBeans(-raffleCost); + raffleUsersUnchosen.add(user); + return true; + } + return false; + } + + public KittyUser chooseRaffleWinner() + { + if(!raffleUsersUnchosen.isEmpty()) + { + KittyUser chosen = raffleUsersUnchosen.get((int) (Math.random() * raffleUsersUnchosen.size())); + raffleUsersUnchosen.remove(chosen); + raffleUsersChosen.add(chosen); + return chosen; + } + return null; + } + + @Override + public String serialize() + { + return commandIndicator; + } + + @Override + public void deSerialzie(String string) + { + if(string == null || string.length() == 0) + setCommandIndicator("!"); + else + setCommandIndicator(string); + } + + public String getCommandIndicator() + { + return commandIndicator; + } + + public void setCommandIndicator(String newIndicator) + { + if(newIndicator != commandIndicator) + { + commandIndicator = newIndicator; + markDirty(); + } + } +} diff --git a/src/main/Main.java b/src/main/Main.java index 23e3b7d..3c937b8 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -1,135 +1,135 @@ -package main; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.security.auth.login.LoginException; - -import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; -import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; -import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; -import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; -import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; -import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; -import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; -import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame; - -import core.CharacterManager; -import core.CommandEnabler; -import core.CommandManager; -import core.DatabaseManager; -import core.ObjectBuilderFactory; -import core.RPManager; -import core.Stats; -import core.lua.PluginManager; -import dataStructures.KittyChannel; -import dataStructures.KittyCore; -import dataStructures.KittyGuild; -import dataStructures.KittyUser; -import dataStructures.Response; -import dataStructures.UserInput; -import net.dv8tion.jda.core.AccountType; -import net.dv8tion.jda.core.JDA; -import net.dv8tion.jda.core.JDABuilder; -import net.dv8tion.jda.core.audio.AudioSendHandler; -import net.dv8tion.jda.core.entities.Guild; -import net.dv8tion.jda.core.entities.TextChannel; -import net.dv8tion.jda.core.entities.VoiceChannel; -import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; -import net.dv8tion.jda.core.hooks.ListenerAdapter; -import net.dv8tion.jda.core.managers.AudioManager; -import offline.Ref; -import utils.GlobalLog; - -// 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 bot specific objects - private static KittyCore kittyCore; - private static DatabaseManager databaseManager; - private static CommandManager commandManager; - private static Stats stats; - private static RPManager rpManager; - private static PluginManager pluginManager; - private static CharacterManager charManager; - - - // Initialization and setup - public static void main(String[] args) throws InterruptedException, LoginException, Exception - { - // Factory startup. The ordering is intentional. - GlobalLog.initialize(); - databaseManager = ObjectBuilderFactory.constructDatabaseManager(); - commandManager = ObjectBuilderFactory.constructCommandManager(CommandEnabler.instance); // TODO: Untangle this singleton - stats = ObjectBuilderFactory.constructStats(commandManager); - charManager = new CharacterManager(); - rpManager = ObjectBuilderFactory.constructRPManager(); - pluginManager = ObjectBuilderFactory.constructPluginManager(); - - // Bot startup - kittyCore = ObjectBuilderFactory.constructKittyCore(); - } - - // When a message is sent in a server that kitty is in, this is what's called. - @Override - public void onGuildMessageReceived(GuildMessageReceivedEvent event) - { - // Tweak the event as necessary - if(!Superintendent.preProcessSetup(event, stats)) - return; - - // Factory objects - KittyUser user = ObjectBuilderFactory.extractUser(event); - KittyGuild guild = ObjectBuilderFactory.extractGuild(event); - KittyChannel channel = ObjectBuilderFactory.extractChannel(event); - - // Specialized uncached objects - Response response = new Response(event, kittyCore); - UserInput input = new UserInput(event, guild); - - // Tweak object construction as necessary - if(!Superintendent.postProcessSetup(event, user, guild, channel, response, input)) - return; - - // Track beans! - user.changeBeans(1); - - // RP logging system - RPManager.instance.addLine(channel, user, input); - - // Run any pre-emptive upkeep we need to - if(!Superintendent.perCommandUpkeepPre(pluginManager)) - return; - - // Attempt to spin up a command. If the command doesn't exist. - // Run plugins right before invoking the commands but after all other setup. - if(commandManager.invokeOnNewThread(guild, channel, user, input, response) == false) - { - List pluginOutput = pluginManager.runAll(input.message, user); - - if(pluginOutput != null && pluginOutput.size() > 0) - { - for(int i = 0; i < pluginOutput.size(); ++i) - { - if(pluginOutput.get(i).startsWith("!")) - { - commandManager.invokeOnNewThread(guild, channel, user, new UserInput(pluginOutput.get(i).substring(1), guild), response); - } - else - { - response.send(pluginOutput.get(i)); - } - } - } - } - - // Run any upkeep in post we need to - if(!Superintendent.perCommandUpkeepPost(kittyCore, databaseManager)) - return; - } +package main; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.security.auth.login.LoginException; + +import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame; + +import core.CharacterManager; +import core.CommandEnabler; +import core.CommandManager; +import core.DatabaseManager; +import core.ObjectBuilderFactory; +import core.RPManager; +import core.Stats; +import core.lua.PluginManager; +import dataStructures.KittyChannel; +import dataStructures.KittyCore; +import dataStructures.KittyGuild; +import dataStructures.KittyUser; +import dataStructures.Response; +import dataStructures.UserInput; +import net.dv8tion.jda.core.AccountType; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.JDABuilder; +import net.dv8tion.jda.core.audio.AudioSendHandler; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.entities.VoiceChannel; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.core.hooks.ListenerAdapter; +import net.dv8tion.jda.core.managers.AudioManager; +import offline.Ref; +import utils.GlobalLog; + +// 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 bot specific objects + private static KittyCore kittyCore; + private static DatabaseManager databaseManager; + private static CommandManager commandManager; + private static Stats stats; + private static RPManager rpManager; + private static PluginManager pluginManager; + private static CharacterManager charManager; + + + // Initialization and setup + public static void main(String[] args) throws InterruptedException, LoginException, Exception + { + // Factory startup. The ordering is intentional. + GlobalLog.initialize(); + databaseManager = ObjectBuilderFactory.constructDatabaseManager(); + commandManager = ObjectBuilderFactory.constructCommandManager(CommandEnabler.instance); // TODO: Untangle this singleton + stats = ObjectBuilderFactory.constructStats(commandManager); + charManager = new CharacterManager(); + rpManager = ObjectBuilderFactory.constructRPManager(); + pluginManager = ObjectBuilderFactory.constructPluginManager(); + + // Bot startup + kittyCore = ObjectBuilderFactory.constructKittyCore(); + } + + // When a message is sent in a server that kitty is in, this is what's called. + @Override + public void onGuildMessageReceived(GuildMessageReceivedEvent event) + { + // Tweak the event as necessary + if(!Superintendent.preProcessSetup(event, stats)) + return; + + // Factory objects + KittyUser user = ObjectBuilderFactory.extractUser(event); + KittyGuild guild = ObjectBuilderFactory.extractGuild(event); + KittyChannel channel = ObjectBuilderFactory.extractChannel(event); + + // Specialized uncached objects + Response response = new Response(event, kittyCore); + UserInput input = new UserInput(event, guild); + + // Tweak object construction as necessary + if(!Superintendent.postProcessSetup(event, user, guild, channel, response, input)) + return; + + // Track beans! + user.changeBeans(1); + + // RP logging system + RPManager.instance.addLine(channel, user, input); + + // Run any pre-emptive upkeep we need to + if(!Superintendent.perCommandUpkeepPre(pluginManager)) + return; + + // Attempt to spin up a command. If the command doesn't exist. + // Run plugins right before invoking the commands but after all other setup. + if(commandManager.invokeOnNewThread(guild, channel, user, input, response) == false) + { + List pluginOutput = pluginManager.runAll(input.message, user); + + if(pluginOutput != null && pluginOutput.size() > 0) + { + for(int i = 0; i < pluginOutput.size(); ++i) + { + if(pluginOutput.get(i).startsWith("!")) + { + commandManager.invokeOnNewThread(guild, channel, user, new UserInput(pluginOutput.get(i).substring(1), guild), response); + } + else + { + response.send(pluginOutput.get(i)); + } + } + } + } + + // Run any upkeep in post we need to + if(!Superintendent.perCommandUpkeepPost(kittyCore, databaseManager)) + return; + } } \ No newline at end of file diff --git a/src/network/NetworkSauceNAO.java b/src/network/NetworkSauceNAO.java index 080c25d..11504cc 100644 --- a/src/network/NetworkSauceNAO.java +++ b/src/network/NetworkSauceNAO.java @@ -1,48 +1,48 @@ -package network; - -import java.util.List; - -import com.google.gson.Gson; - -import offline.Ref; -import utils.HTTPUtils; - -public class NetworkSauceNAO -{ - private static final Gson jsonParser_ = new Gson(); - private static final String API_ROOT = "https://saucenao.com/search.php?db=999&output_type=2&numres=10&api_key=" + Ref.SauceNAOKey +"&url="; - NetworkE6 e6Sauce = new NetworkE6(); - private class SauceNAOResponseObject - { - List results; - } - - private class SauceNAOResult - { - SauceNAOData data; - } - - private class SauceNAOData - { - String [] ext_urls; - } - - public String getSauce(String input) - { - input = input.trim(); - input = input.replace("+", "%2B"); - input = input.replace(" ", "%20"); - - String res = HTTPUtils.sendGETRequest(API_ROOT + input); - - SauceNAOResponseObject sauce = jsonParser_.fromJson(res, SauceNAOResponseObject.class); - String sauceUrl = sauce.results.get(0).data.ext_urls[0]; - if(sauceUrl.startsWith("https://e621.net/post/show/")) - { - System.out.println("id:" + sauceUrl.substring(26)); - return e6Sauce.getE6("id:" + sauceUrl.substring(27)).toString(); - } - return sauce.results.get(0).data.ext_urls[0]; - } - -} +package network; + +import java.util.List; + +import com.google.gson.Gson; + +import offline.Ref; +import utils.HTTPUtils; + +public class NetworkSauceNAO +{ + private static final Gson jsonParser_ = new Gson(); + private static final String API_ROOT = "https://saucenao.com/search.php?db=999&output_type=2&numres=10&api_key=" + Ref.SauceNAOKey +"&url="; + NetworkE6 e6Sauce = new NetworkE6(); + private class SauceNAOResponseObject + { + List results; + } + + private class SauceNAOResult + { + SauceNAOData data; + } + + private class SauceNAOData + { + String [] ext_urls; + } + + public String getSauce(String input) + { + input = input.trim(); + input = input.replace("+", "%2B"); + input = input.replace(" ", "%20"); + + String res = HTTPUtils.sendGETRequest(API_ROOT + input); + + SauceNAOResponseObject sauce = jsonParser_.fromJson(res, SauceNAOResponseObject.class); + String sauceUrl = sauce.results.get(0).data.ext_urls[0]; + if(sauceUrl.startsWith("https://e621.net/post/show/")) + { + System.out.println("id:" + sauceUrl.substring(26)); + return e6Sauce.getE6("id:" + sauceUrl.substring(27)).toString(); + } + return sauce.results.get(0).data.ext_urls[0]; + } + +} diff --git a/src/utils/audio/AudioUtils.java b/src/utils/audio/AudioUtils.java index 7430926..18586f0 100644 --- a/src/utils/audio/AudioUtils.java +++ b/src/utils/audio/AudioUtils.java @@ -119,6 +119,16 @@ public class AudioUtils return null; } + public int getVolume(AudioPlayer player) + { + return player.getVolume(); + } + + public void changeVolume(AudioPlayer player, int newVol) + { + player.setVolume(newVol); + } + public String skipVideo(AudioPlayer player) { player.stopTrack(); @@ -152,6 +162,9 @@ class MusicController extends Thread @Override public void run() { + try { + Thread.sleep(5000); + } catch (InterruptedException e) {} AudioTrack nowPlaying = null; do {