diff --git a/.gitignore b/.gitignore index 7deac38d..76174e5b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,7 @@ hs_err_pid* # Custom files build/ +core/build/ +bukkit/build/ .idea/ .gradle/ \ No newline at end of file diff --git a/bukkit/build.gradle b/bukkit/build.gradle index 5436852a..12bcf641 100644 --- a/bukkit/build.gradle +++ b/bukkit/build.gradle @@ -56,6 +56,7 @@ dependencies { compileOnly urlFile("https://github.com/Zrips/CMI-API/releases/download/8.7.8.2/CMIAPI8.7.8.2.jar", "CMI-API") compileOnly 'net.lapismc:AFKPlus:3.3.15' implementation project(":core") + implementation('org.slf4j:slf4j-api:2.0.1') compileOnly('com.discordsrv:discordsrv:1.26.0') implementation 'org.jooq:jooq:3.14.16' compileOnly 'net.essentialsx:EssentialsX:2.19.0' diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitDebugger.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitDebugger.java index b827a43e..1f3314fa 100644 --- a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitDebugger.java +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitDebugger.java @@ -157,8 +157,7 @@ private List> getDSUFiles() throws Exception { files.add(fileMap("leveling.yml", Utils.readFile(core.getPlatform().getDataFolder() + core.fileseparator + "leveling.yml"))); files.add(fileMap("status.yml", Utils.readFile(core.getPlatform().getDataFolder() + core.fileseparator + "status.yml"))); files.add(fileMap("suggestions.yml", Utils.readFile(core.getPlatform().getDataFolder() + core.fileseparator + "suggestions.yml"))); - files.add(fileMap("leveling-roles.json", Utils.readFile(core.getPlatform().getDataFolder() + core.fileseparator + "leveling-roles.json"))); - files.add(fileMap("leveling-roles.json", Utils.readFile(core.getPlatform().getDataFolder() + core.fileseparator + "leveling-roles.json"))); + files.add(fileMap("leveling-rewards.json", Utils.readFile(core.getPlatform().getDataFolder() + core.fileseparator + "leveling-rewards.json"))); return files; } diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitPlatformServer.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitPlatformServer.java index 017841c4..1e790345 100644 --- a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitPlatformServer.java +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitPlatformServer.java @@ -43,10 +43,12 @@ public class BukkitPlatformServer extends PlatformServer { private final DiscordSRVUtils core; @Getter private final Debugger debugger; + private final DiscordSRVUtilsBukkit bcore; - public BukkitPlatformServer(DiscordSRVUtils core) { + public BukkitPlatformServer(DiscordSRVUtils core, DiscordSRVUtilsBukkit bcore) { this.core = core; debugger = new BukkitDebugger(core); + this.bcore = bcore; } @Override @@ -96,5 +98,23 @@ public PlatformPlayer getOfflinePlayer(UUID uuid) { return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(uuid), core); } + @Override + public PlatformPlayer getPlayer(UUID uuid) { + Player player = Bukkit.getPlayer(uuid); + if (player == null) return null; + return new BukkitPlayer(core, player); + } + + @Override + public void executeConsoleCommands(String... cmds) { + Runnable runnable = () -> { + for (String cmd : cmds) { + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd); + } + }; + if (Bukkit.isPrimaryThread()) runnable.run(); + else Bukkit.getScheduler().runTask(bcore, runnable); + } + } diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitPlugin.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitPlugin.java index 9786831b..b8b8655a 100644 --- a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitPlugin.java +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/BukkitPlugin.java @@ -92,7 +92,7 @@ public File getDataFolder() { @Override public PlatformServer getServer() { - return new BukkitPlatformServer(core); + return new BukkitPlatformServer(core, main); } @Override diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/DiscordSRVUtilsBukkit.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/DiscordSRVUtilsBukkit.java index c0f2bfe7..be744305 100644 --- a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/DiscordSRVUtilsBukkit.java +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/DiscordSRVUtilsBukkit.java @@ -28,13 +28,31 @@ import org.bstats.charts.AdvancedPie; import org.bstats.charts.SimplePie; import org.bukkit.plugin.java.JavaPlugin; +import org.slf4j.LoggerFactory; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; import tk.bluetree242.discordsrvutils.bukkit.discordsrv.SlashCommandProvider; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class DiscordSRVUtilsBukkit extends JavaPlugin { + + static { + ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(DiscordSRVUtilsBukkit.class.getClassLoader()); + try { + Method method = LoggerFactory.class.getDeclaredMethod("bind"); + method.setAccessible(true); + method.invoke(null); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new RuntimeException(e); + } finally { + Thread.currentThread().setContextClassLoader(oldCl); + } + } + @Getter private DiscordSRVUtils core = null; diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/discordsrv/SlashCommandProvider.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/discordsrv/SlashCommandProvider.java index 4ab80a65..25470d46 100644 --- a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/discordsrv/SlashCommandProvider.java +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/discordsrv/SlashCommandProvider.java @@ -44,10 +44,12 @@ @RequiredArgsConstructor public class SlashCommandProvider implements github.scarsz.discordsrv.api.commands.SlashCommandProvider { private final DiscordSRVUtilsBukkit core; + @Override public Set getSlashCommands() { Set commands = new HashSet<>(); - if (core.getCore() == null || !core.getCore().isEnabled() || !core.getCore().getMainConfig().register_slash()) return commands; + if (core.getCore() == null || !core.getCore().isEnabled() || !core.getCore().getMainConfig().register_slash()) + return commands; CommandManager manager = core.getCore().getCommandManager(); for (Command command : manager.getCommands()) { if (!command.isEnabled()) continue; @@ -68,49 +70,49 @@ private PluginSlashCommand getCmd(String alias, Command cmd) { public void onCommand(SlashCommandEvent e) { DiscordSRVUtils core = this.core.getCore(); if (core.getMainConfig().bungee_mode()) return; - String cmd = e.getName(); - Command executor = core.getCommandManager().getCommandHashMap().get(cmd); - if (executor == null || !executor.isEnabled()) return; - CommandEvent event = new CommandEvent(core, e.getMember(), e.getUser(), e.getChannel(), e.getJDA(), e); - try { - if (executor.getRequiredPermission() != null) { - if (e.getChannel() instanceof TextChannel) { - if (!e.getMember().hasPermission(executor.getRequiredPermission())) { - e.replyEmbeds(Embed.error("You don't have permission to use this command.", "Required: " + executor.getRequiredPermission())).queue(); - return; - } + String cmd = e.getName(); + Command executor = core.getCommandManager().getCommandHashMap().get(cmd); + if (executor == null || !executor.isEnabled()) return; + CommandEvent event = new CommandEvent(core, e.getMember(), e.getUser(), e.getChannel(), e.getJDA(), e); + try { + if (executor.getRequiredPermission() != null) { + if (e.getChannel() instanceof TextChannel) { + if (!e.getMember().hasPermission(executor.getRequiredPermission())) { + e.replyEmbeds(Embed.error("You don't have permission to use this command.", "Required: " + executor.getRequiredPermission())).queue(); + return; } } - if (e.getChannel() instanceof TextChannel) { - if (executor.isOwnerOnly()) { - if (!e.getMember().isOwner()) { - e.replyEmbeds(Embed.error("Only Guild Owner can use this command.")).queue(); - return; - } + } + if (e.getChannel() instanceof TextChannel) { + if (executor.isOwnerOnly()) { + if (!e.getMember().isOwner()) { + e.replyEmbeds(Embed.error("Only Guild Owner can use this command.")).queue(); + return; } - if (executor.isAdminOnly()) { - if (!core.getJdaManager().isAdmin(e.getUser().getIdLong())) { - e.replyEmbeds(Embed.error("Only Admins can use this command.", "Your id must be in admin list on the config.yml")).queue(); - return; - } + } + if (executor.isAdminOnly()) { + if (!core.getJdaManager().isAdmin(e.getUser().getIdLong())) { + e.replyEmbeds(Embed.error("Only Admins can use this command.", "Your id must be in admin list on the config.yml")).queue(); + return; } } - core.getLogger().info(e.getUser().getAsTag() + " Used " + "/" + cmd + " Command"); - executor.run(event); - } catch (InsufficientPermissionException ex) { - ex.printStackTrace(); - e.replyEmbeds(Embed.error("An error happened while executing this Command. Please report to the devs!", "The bot is missing the following permission: " + ex.getPermission())).queue(); - } catch (Exception exception) { - exception.printStackTrace(); - e.replyEmbeds(Embed.error("An error happened while executing this Command. Please report to the devs!")).queue(); } - if (event.isConnOpen()) { - try { - event.getConnection().configuration().connectionProvider().acquire().close(); - } catch (SQLException throwables) { - core.getErrorHandler().defaultHandle(throwables); - } + core.getLogger().info(e.getUser().getAsTag() + " Used " + "/" + cmd + " Command"); + executor.run(event); + } catch (InsufficientPermissionException ex) { + ex.printStackTrace(); + e.replyEmbeds(Embed.error("An error happened while executing this Command. Please report to the devs!", "The bot is missing the following permission: " + ex.getPermission())).queue(); + } catch (Exception exception) { + exception.printStackTrace(); + e.replyEmbeds(Embed.error("An error happened while executing this Command. Please report to the devs!")).queue(); + } + if (event.isConnOpen()) { + try { + event.getConnection().configuration().connectionProvider().acquire().close(); + } catch (SQLException throwables) { + core.getErrorHandler().defaultHandle(throwables); } + } } } diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/listeners/punishments/libertybans/LibertyBansPunishment.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/listeners/punishments/libertybans/LibertyBansPunishment.java index c9ada79f..2772d99d 100644 --- a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/listeners/punishments/libertybans/LibertyBansPunishment.java +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/listeners/punishments/libertybans/LibertyBansPunishment.java @@ -23,21 +23,22 @@ package tk.bluetree242.discordsrvutils.bukkit.listeners.punishments.libertybans; import lombok.RequiredArgsConstructor; -import org.bukkit.Bukkit; -import space.arim.libertybans.api.Operator; -import space.arim.libertybans.api.PlayerOperator; -import space.arim.libertybans.api.PlayerVictim; -import space.arim.libertybans.api.Victim; +import space.arim.libertybans.api.*; import tk.bluetree242.discordsrvutils.interfaces.Punishment; import tk.bluetree242.discordsrvutils.utils.Utils; import java.util.UUID; +import java.util.concurrent.ExecutionException; @RequiredArgsConstructor public class LibertyBansPunishment implements Punishment { private final space.arim.libertybans.api.punish.Punishment punishment; private final Operator operator; private final boolean revoke; + private final LibertyBans plugin; + + private String operatorName = null; + private String targetName = null; @Override public String getDuration() { @@ -50,8 +51,7 @@ public String getOperator() { if (operator.getType() == Operator.OperatorType.CONSOLE) { return "CONSOLE"; } else { - PlayerOperator operatorplayer = (PlayerOperator) operator; - String name = Bukkit.getOfflinePlayer(operatorplayer.getUUID()).getName(); + String name = retrieveName(true); return name == null ? "Unknown" : name; } } @@ -61,8 +61,7 @@ public String getName() { if (punishment.getVictim().getType() == Victim.VictimType.ADDRESS) { return "Unknown"; } else { - PlayerVictim victim = (PlayerVictim) punishment.getVictim(); - String name = Bukkit.getOfflinePlayer(victim.getUUID()).getName(); + String name = retrieveName(false); return name == null ? "Unknown" : name; } } @@ -112,4 +111,28 @@ public UUID getTargetUUID() { return victim.getUUID(); } } + + private String retrieveName(boolean operator) { + String saved = operator ? operatorName : targetName; + if (saved != null) return saved.equals("NONE@*") ? null : saved; + String result = null; + try { + result = plugin.getUserResolver().lookupName(operator ? getOperatorUUID() : getTargetUUID()).get().orElse(null); + } catch (InterruptedException | ExecutionException e) { + //nothing + } + if (result != null) { + if (operator) operatorName = result; + else targetName = result; + } else { + if (operator) operatorName = "NONE@*"; + else targetName = "NONE@*"; + } + return result; + } + + private UUID getOperatorUUID() { + if (operator.getType() != Operator.OperatorType.PLAYER) return null; + return ((PlayerOperator) operator).getUUID(); + } } diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/listeners/punishments/libertybans/LibertybansListener.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/listeners/punishments/libertybans/LibertybansListener.java index 16f47db5..51456b54 100644 --- a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/listeners/punishments/libertybans/LibertybansListener.java +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/listeners/punishments/libertybans/LibertybansListener.java @@ -61,7 +61,7 @@ public class PunishmentListener implements EventConsumer { @Override public void accept(PostPunishEvent e) { core.getAsyncManager().executeAsync(() -> { - LibertyBansPunishment punishment = new LibertyBansPunishment(e.getPunishment(), e.getPunishment().getOperator(), false); + LibertyBansPunishment punishment = new LibertyBansPunishment(e.getPunishment(), e.getPunishment().getOperator(), false, plugin); tk.bluetree242.discordsrvutils.interfaces.Punishment.handlePunishment(punishment, core); }); } @@ -72,7 +72,7 @@ public class PardonListener implements EventConsumer { @Override public void accept(PostPardonEvent e) { core.getAsyncManager().executeAsync(() -> { - LibertyBansPunishment punishment = new LibertyBansPunishment(e.getPunishment(), e.getPunishment().getOperator(), true); + LibertyBansPunishment punishment = new LibertyBansPunishment(e.getPunishment(), e.getPunishment().getOperator(), true, plugin); tk.bluetree242.discordsrvutils.interfaces.Punishment.handlePunishment(punishment, core); }); } diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/BukkitLogger.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/BukkitLogger.java new file mode 100644 index 00000000..f62322b4 --- /dev/null +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/BukkitLogger.java @@ -0,0 +1,107 @@ +/* + * LICENSE + * DiscordSRVUtils + * ------------- + * Copyright (C) 2020 - 2022 BlueTree242 + * ------------- + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * END + */ + +package tk.bluetree242.discordsrvutils.bukkit.logging; + +import lombok.RequiredArgsConstructor; +import org.bukkit.Bukkit; +import org.slf4j.Marker; +import org.slf4j.event.Level; +import org.slf4j.helpers.LegacyAbstractLogger; +import tk.bluetree242.discordsrvutils.bukkit.DiscordSRVUtilsBukkit; + +import java.util.logging.LogRecord; + +@RequiredArgsConstructor +public class BukkitLogger extends LegacyAbstractLogger { + private final String name; + + @Override + public String getName() { + return name; + } + + private DiscordSRVUtilsBukkit getMain() { + return (DiscordSRVUtilsBukkit) Bukkit.getPluginManager().getPlugin("DiscordSRVUtils"); + } + + @Override + protected String getFullyQualifiedCallerName() { + return BukkitLogger.class.getName(); + } + + @Override + protected void handleNormalizedLoggingCall(Level level, Marker marker, String msg, Object[] arguments, Throwable throwable) { + DiscordSRVUtilsBukkit main = getMain(); + if (main == null) return; + if (arguments != null) { + int num = 0; + for (Object argument : arguments) { + num++; + if (num > arguments.length) continue; + msg = msg.replaceFirst("\\{}", argument.toString()); + } + } + LogRecord record = new LogRecord(toJUtilLevel(level), msg); + record.setLoggerName(main.getLogger().getName()); + record.setParameters(arguments); + record.setThrown(throwable); + if (!main.getCore().getMessageFilter().canLog(name, record)) return; + main.getLogger().log(record); + } + + private java.util.logging.Level toJUtilLevel(Level level) { + switch (level) { + case WARN: + return java.util.logging.Level.WARNING; + case ERROR: + return java.util.logging.Level.SEVERE; + default: + return java.util.logging.Level.INFO; + } + } + + @Override + public boolean isTraceEnabled() { + return false; + } + + @Override + public boolean isDebugEnabled() { + return false; + } + + @Override + public boolean isInfoEnabled() { + return true; + } + + @Override + public boolean isWarnEnabled() { + return true; + } + + @Override + public boolean isErrorEnabled() { + return true; + } +} diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/LoggerFactory.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/LoggerFactory.java new file mode 100644 index 00000000..24a665e5 --- /dev/null +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/LoggerFactory.java @@ -0,0 +1,33 @@ +/* + * LICENSE + * DiscordSRVUtils + * ------------- + * Copyright (C) 2020 - 2022 BlueTree242 + * ------------- + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * END + */ + +package tk.bluetree242.discordsrvutils.bukkit.logging; + +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; + +public class LoggerFactory implements ILoggerFactory { + @Override + public Logger getLogger(String s) { + return new BukkitLogger(s); + } +} diff --git a/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/LoggerProvider.java b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/LoggerProvider.java new file mode 100644 index 00000000..d41a1578 --- /dev/null +++ b/bukkit/src/main/java/tk/bluetree242/discordsrvutils/bukkit/logging/LoggerProvider.java @@ -0,0 +1,58 @@ +/* + * LICENSE + * DiscordSRVUtils + * ------------- + * Copyright (C) 2020 - 2022 BlueTree242 + * ------------- + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * END + */ + +package tk.bluetree242.discordsrvutils.bukkit.logging; + +import org.slf4j.ILoggerFactory; +import org.slf4j.IMarkerFactory; +import org.slf4j.spi.MDCAdapter; +import org.slf4j.spi.SLF4JServiceProvider; + + +public class LoggerProvider implements SLF4JServiceProvider { + private final LoggerFactory factory = new LoggerFactory(); + + @Override + public ILoggerFactory getLoggerFactory() { + return factory; + } + + @Override + public IMarkerFactory getMarkerFactory() { + return null; + } + + @Override + public MDCAdapter getMDCAdapter() { + return null; + } + + @Override + public String getRequestedApiVersion() { + return "2.0.99"; + } + + @Override + public void initialize() { + //nothing to initialize + } +} diff --git a/bukkit/src/main/resources/META-INF/services/tk.bluetree242.discordsrvutils.dependencies.slf4j.spi.SLF4JServiceProvider b/bukkit/src/main/resources/META-INF/services/tk.bluetree242.discordsrvutils.dependencies.slf4j.spi.SLF4JServiceProvider new file mode 100644 index 00000000..a8b65705 --- /dev/null +++ b/bukkit/src/main/resources/META-INF/services/tk.bluetree242.discordsrvutils.dependencies.slf4j.spi.SLF4JServiceProvider @@ -0,0 +1 @@ +tk.bluetree242.discordsrvutils.bukkit.logging.LoggerProvider \ No newline at end of file diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml index b1adf2cd..c61a1ff1 100644 --- a/bukkit/src/main/resources/plugin.yml +++ b/bukkit/src/main/resources/plugin.yml @@ -42,5 +42,8 @@ permissions: discordsrvutils.removeslash: default: op description: Allows use of /dsu removeslash + discordsrvutils.resetlevel: + default: op + description: Allows use of /dsu resetlevel diff --git a/core/build.gradle b/core/build.gradle index 62ae1b4b..dad7d8d5 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -57,6 +57,7 @@ rootProject.allprojects { relocate 'com.google.errorprone', 'tk.bluetree242.discordsrvutils.dependencies.google' relocate 'org.apache.commons', 'tk.bluetree242.discordsrvutils.dependencies.commons' relocate 'org.jooq', 'tk.bluetree242.discordsrvutils.dependencies.jooq' + relocate 'org.slf4j', 'tk.bluetree242.discordsrvutils.dependencies.slf4j' } } @@ -81,6 +82,8 @@ dependencies { //using h2 database for code generation as it doesnt uppercase the table/column names, without it, we get into unfixable issues testImplementation 'com.h2database:h2:1.4.197' jooqGenerator 'com.h2database:h2:1.4.197' + + implementation('org.slf4j:slf4j-api:2.0.1') } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/DiscordSRVUtils.java b/core/src/main/java/tk/bluetree242/discordsrvutils/DiscordSRVUtils.java index 5e1e0cfc..0005cdb4 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/DiscordSRVUtils.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/DiscordSRVUtils.java @@ -48,6 +48,7 @@ import tk.bluetree242.discordsrvutils.systems.commandmanagement.CommandManager; import tk.bluetree242.discordsrvutils.systems.invitetracking.InviteTrackingManager; import tk.bluetree242.discordsrvutils.systems.leveling.LevelingManager; +import tk.bluetree242.discordsrvutils.systems.leveling.LevelingRewardsManager; import tk.bluetree242.discordsrvutils.systems.leveling.listeners.game.GameLevelingListener; import tk.bluetree242.discordsrvutils.systems.messages.MessageManager; import tk.bluetree242.discordsrvutils.systems.status.StatusManager; @@ -67,6 +68,7 @@ public class DiscordSRVUtils { private static DiscordSRVUtils instance; //file separator string public final String fileseparator = System.getProperty("file.separator"); + @Getter private final MessageFilter messageFilter = new MessageFilter(this); private final PluginPlatform main; @Getter @@ -78,7 +80,7 @@ public class DiscordSRVUtils { @Getter private final WaiterManager waiterManager = new WaiterManager(this); @Getter - private final LevelingManager levelingManager = new LevelingManager(this); + private final LevelingManager levelingManager = new LevelingManager(this, new LevelingRewardsManager(this)); @Getter private final SuggestionManager suggestionManager = new SuggestionManager(this); @Getter @@ -193,7 +195,6 @@ public void onEnable() { main.disable(); return; } - messageFilter.add(); try { //Reload Configurations reloadConfigs(); @@ -249,7 +250,6 @@ public void onEnable() { public void onDisable() { if (dsrvlistener != null) DiscordSRV.api.unsubscribe(dsrvlistener); - messageFilter.remove(); pluginHookManager.removeHookAll(); jdaManager.removeListeners(); if (getJDA() != null) { @@ -291,7 +291,8 @@ public void reloadConfigs() throws IOException, InvalidConfigException { suggestionsConfig = suggestionsConfigManager.reloadConfigData(); statusConfigConfManager.reloadConfig(); statusConfig = statusConfigConfManager.reloadConfigData(); - levelingManager.reloadLevelingRoles(); + levelingManager.getLevelingRewardsManager().reloadLevelingRewards(); + levelingManager.getLevelingRewardsManager().reloadRewardCache(); setSettings(false); } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/HelpCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/HelpCommand.java index 5bd6e96a..fa0d606e 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/HelpCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/HelpCommand.java @@ -44,6 +44,10 @@ public HelpCommand(DiscordSRVUtils core) { @Override public void run(CommandEvent e) throws Exception { if (e.getOption("command") == null) { + if (!core.getMainConfig().help_response().equals("")) { + e.replyMessage(core.getMainConfig().help_response()).queue(); + return; + } EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.GREEN); embed.setThumbnail(e.getJDA().getSelfUser().getEffectiveAvatarUrl()); diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/leveling/LeaderboardCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/leveling/LeaderboardCommand.java index e6fe26b0..98216a2a 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/leveling/LeaderboardCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/leveling/LeaderboardCommand.java @@ -42,7 +42,7 @@ public void run(CommandEvent e) throws Exception { EmbedBuilder embed = new EmbedBuilder(); embed.setColor(Color.GREEN); StringJoiner joiner = new StringJoiner("\n"); - for (PlayerStats player : core.getLevelingManager().getLeaderboard(10, core.getDatabaseManager().newJooqConnection())) { + for (PlayerStats player : core.getLevelingManager().getLeaderboard(10)) { String prefix = ""; switch (player.getRank()) { case 1: diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/leveling/LevelCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/leveling/LevelCommand.java index b0484b46..84da83f5 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/leveling/LevelCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/leveling/LevelCommand.java @@ -54,7 +54,7 @@ public void run(CommandEvent e) throws Exception { } } else if (e.getOption("player_name") != null) { String name = e.getOption("player_name").getAsString(); - target = core.getLevelingManager().getPlayerStats(name, e.getConnection()); + target = core.getLevelingManager().getPlayerStats(name); if (target == null) { e.replyErr(core.getLevelingConfig().level_command_invalid_player()).queue(); return; diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/ApproveSuggestionCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/ApproveSuggestionCommand.java index 747d4eb8..b0119fbc 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/ApproveSuggestionCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/ApproveSuggestionCommand.java @@ -45,12 +45,12 @@ public void run(CommandEvent e) throws Exception { } int number = (int) e.getOption("number").getAsLong(); - Suggestion suggestion = core.getSuggestionManager().getSuggestionByNumber(number, e.getConnection()); + Suggestion suggestion = core.getSuggestionManager().getSuggestionByNumber(number); if (suggestion == null) { e.replyErr("Suggestion not found").queue(); return; } - suggestion.setApproved(true, e.getAuthor().getIdLong(), e.getConnection()); + suggestion.setApproved(true, e.getAuthor().getIdLong()); e.replySuccess("Successfully approved suggestion").queue(); } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/DenySuggestionCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/DenySuggestionCommand.java index 6dc42b58..ca022375 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/DenySuggestionCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/DenySuggestionCommand.java @@ -45,12 +45,12 @@ public void run(CommandEvent e) throws Exception { } int number = (int) e.getOption("number").getAsLong(); - Suggestion suggestion = core.getSuggestionManager().getSuggestionByNumber(number, e.getConnection()); + Suggestion suggestion = core.getSuggestionManager().getSuggestionByNumber(number); if (suggestion == null) { e.replyErr("Suggestion not found").queue(); return; } - suggestion.setApproved(false, e.getAuthor().getIdLong(), e.getConnection()); + suggestion.setApproved(false, e.getAuthor().getIdLong()); e.replySuccess("Successfully denied suggestion").queue(); } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/SuggestCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/SuggestCommand.java index b4a1e4dd..68471d54 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/SuggestCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/SuggestCommand.java @@ -73,7 +73,7 @@ public void run(CommandEvent e) throws Exception { } String suggestionText = e.getOption("suggestion").getAsString(); - Suggestion suggestion = core.getSuggestionManager().makeSuggestion(suggestionText, e.getAuthor().getIdLong(), e.getConnection()); + Suggestion suggestion = core.getSuggestionManager().makeSuggestion(suggestionText, e.getAuthor().getIdLong()); e.replySuccess("Successfully created suggestion").queue(); } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/SuggestionNoteCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/SuggestionNoteCommand.java index e5cff4b7..1755d388 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/SuggestionNoteCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/suggestions/SuggestionNoteCommand.java @@ -47,12 +47,12 @@ public void run(CommandEvent e) throws Exception { int number = (int) e.getOption("number").getAsLong(); String noteText = e.getOption("note").getAsString(); - Suggestion suggestion = core.getSuggestionManager().getSuggestionByNumber(number, e.getConnection()); + Suggestion suggestion = core.getSuggestionManager().getSuggestionByNumber(number); if (suggestion == null) { e.replyErr("Suggestion not found").queue(); return; } - suggestion.addNote(e.getAuthor().getIdLong(), noteText, e.getConnection()); + suggestion.addNote(e.getAuthor().getIdLong(), noteText); e.replySuccess("Successfully added note").queue(); } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/CloseCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/CloseCommand.java index 7e6575a6..055e8e51 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/CloseCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/CloseCommand.java @@ -35,7 +35,7 @@ public CloseCommand(DiscordSRVUtils core) { @Override public void run(CommandEvent e) throws Exception { - Ticket ticket = core.getTicketManager().getTicketByChannel(e.getChannel().getIdLong(), e.getConnection()); + Ticket ticket = core.getTicketManager().getTicketByChannel(e.getChannel().getIdLong()); if (ticket == null) { e.replyErr("You are not in a ticket").queue(); return; @@ -44,7 +44,7 @@ public void run(CommandEvent e) throws Exception { e.replyErr("Ticket is already closed").queue(); } else { e.reply("Closing Ticket...").setEphemeral(true).queue(); - ticket.close(e.getAuthor(), e.getConnection()); + ticket.close(e.getAuthor()); } } } \ No newline at end of file diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/CreatePanelCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/CreatePanelCommand.java index d160c9e2..77bd617c 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/CreatePanelCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/CreatePanelCommand.java @@ -35,7 +35,7 @@ public class CreatePanelCommand extends Command { public CreatePanelCommand(DiscordSRVUtils core) { - super(core, "createpanel", "Create a ticket panel", "[P]createpanel", null, CommandCategory.TICKETS, "cp"); + super(core, "createpanel", "Create a ticket panel", "[P]createpanel", null, CommandCategory.TICKETS_ADMIN, "cp"); setAdminOnly(true); } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/DeletePanelCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/DeletePanelCommand.java index 8c9d03ed..35dbd053 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/DeletePanelCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/DeletePanelCommand.java @@ -42,7 +42,7 @@ public DeletePanelCommand(DiscordSRVUtils core) { @Override public void run(CommandEvent e) throws Exception { - Panel panel = core.getTicketManager().getPanelById(e.getOption("id").getAsString(), e.getConnection()); + Panel panel = core.getTicketManager().getPanelById(e.getOption("id").getAsString()); if (panel == null) { e.reply(Embed.error("Panel not found, use /panelist for list of panels")).queue(); } else { diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/EditPanelCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/EditPanelCommand.java index 192a9bf6..ede31090 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/EditPanelCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/EditPanelCommand.java @@ -44,7 +44,7 @@ public EditPanelCommand(DiscordSRVUtils core) { @Override public void run(CommandEvent e) throws Exception { String id = e.getOption("id").getAsString(); - Panel panel = core.getTicketManager().getPanelById(id, e.getConnection()); + Panel panel = core.getTicketManager().getPanelById(id); if (panel == null) { e.reply(Embed.error("Panel not found, use /panelist for list of panels")).queue(); } else { diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/ReopenCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/ReopenCommand.java index ec8fb8bf..1747dda5 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/ReopenCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/discord/tickets/ReopenCommand.java @@ -35,7 +35,7 @@ public ReopenCommand(DiscordSRVUtils core) { @Override public void run(CommandEvent e) throws Exception { - Ticket ticket = core.getTicketManager().getTicketByChannel(e.getChannel().getIdLong(), e.getConnection()); + Ticket ticket = core.getTicketManager().getTicketByChannel(e.getChannel().getIdLong()); if (ticket == null) { e.replyErr("You are not in a ticket").queue(); return; @@ -44,7 +44,7 @@ public void run(CommandEvent e) throws Exception { e.replyErr("Ticket is already opened").queue(); } else { e.reply("Reopening Ticket...").setEphemeral(true).queue(); - ticket.reopen(e.getAuthor(), e.getConnection()); + ticket.reopen(e.getAuthor()); } } } \ No newline at end of file diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/game/DiscordSRVUtilsCommand.java b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/game/DiscordSRVUtilsCommand.java index 6a8da80a..f05d987e 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/commands/game/DiscordSRVUtilsCommand.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/commands/game/DiscordSRVUtilsCommand.java @@ -23,29 +23,30 @@ package tk.bluetree242.discordsrvutils.commands.game; import lombok.RequiredArgsConstructor; +import org.json.JSONObject; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; import tk.bluetree242.discordsrvutils.exceptions.ConfigurationLoadException; import tk.bluetree242.discordsrvutils.platform.PlatformPlayer; import tk.bluetree242.discordsrvutils.platform.command.CommandUser; import tk.bluetree242.discordsrvutils.platform.command.ConsoleCommandUser; import tk.bluetree242.discordsrvutils.platform.command.PlatformCommand; +import tk.bluetree242.discordsrvutils.systems.leveling.PlayerStats; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; @RequiredArgsConstructor public class DiscordSRVUtilsCommand implements PlatformCommand { private final DiscordSRVUtils core; - + private boolean migrated = false; @Override public void onRunAsync(String[] args, CommandUser sender, String label) throws Throwable { if (args.length == 0) { sender.sendMessage("&eRunning DiscordSRVUtils v" + core.getPlatform().getDescription().getVersion()); String build = core.getVersionConfig().getString("buildNumber"); - if (!build.equals("NONE")) { - sender.sendMessage("&eBuild #" + build); - } + sender.sendMessage("&eBuild " + (build.equalsIgnoreCase("NONE") ? "&aNone/Unknown" : "&a#" + build)); sender.sendMessage("&bStatus: " + (core.isReady() ? "&aRunning and functioning" : "&cNot running")); return; } @@ -81,6 +82,45 @@ public void onRunAsync(String[] args, CommandUser sender, String label) throws T } return; } + } else if (args[0].equalsIgnoreCase("resetlevel")) { + if (sender.hasPermission("discordsrvutils.resetlevel")) { + String name = args.length >= 2 ? args[1] : null; + if (name == null) { + sender.sendMessage("&cPlease provide player name or all for all players."); + return; + } + if (name.equalsIgnoreCase("all")) { + core.getLevelingManager().resetLeveling(); + core.getLevelingManager().cachedUUIDS.invalidateAll(); + core.getLevelingManager().getLevelingRewardsManager().setRewardCache(new JSONObject()); + core.getLevelingManager().getLevelingRewardsManager().saveRewardCache(); + sender.sendMessage("&eEveryone's level has been reset"); + } else { + PlayerStats stats = core.getLevelingManager().getPlayerStats(name); + if (stats == null) { + sender.sendMessage("&cPlayer not found"); + } else { + stats.setLevel(0); + stats.setXP(0); + core.getLevelingManager().getLevelingRewardsManager().getRewardCache().remove(stats.getUuid().toString()); + core.getLevelingManager().getLevelingRewardsManager().saveRewardCache(); + sender.sendMessage("&ePlayer's level has been reset."); + } + } + return; + } + } else if (args[0].equalsIgnoreCase("migrateLeveling")) { + if (sender instanceof ConsoleCommandUser) { //only console + if (migrated) { + sender.sendMessage("&cAlready migrated."); + return; + } + migrated = true; + sender.sendMessage("&cMigrating leveling to new mee6 leveling, please wait...."); + core.getLevelingManager().convertToMee6(); + sender.sendMessage("&eSuccessfully migrated, If you used leveling roles before, please reconfigure according to the new leveling system, keep in mind that leveling roles was upgraded to leveling-&lrewards&e.json (https://wiki.discordsrvutils.xyz/leveling-conversion)"); + return; + } } } sender.sendMessage("&cSubCommand not found"); @@ -98,7 +138,12 @@ public List onTabComplete(String[] args, CommandUser sender, String labe values.add("updatecheck"); if (sender.hasPermission("discordsrvutils.removeslash")) values.add("removeslash"); - + if (sender.hasPermission("discordsrvutils.resetlevel")) + values.add("resetlevel"); + } else if (args.length == 2 && args[0].equalsIgnoreCase("resetlevel") && sender.hasPermission("discordsrvutils.resetlevel")) { + List result = core.getPlatform().getServer().getOnlinePlayers().stream().map(PlatformPlayer::getName).collect(Collectors.toList()); + result.add("all"); + return result; } List result = new ArrayList<>(); diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/config/Config.java b/core/src/main/java/tk/bluetree242/discordsrvutils/config/Config.java index e8a92d17..ad2b0894 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/config/Config.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/config/Config.java @@ -136,6 +136,12 @@ public interface Config { @ConfDefault.DefaultString("message:no-longer-afk") String no_longer_afk_message(); + @AnnotationBasedSorter.Order(141) + @ConfKey("help-response") + @ConfComments("# Response of /help command, leave blank to generate. You can use message:msgfile where msgfile is the name of the message file in your messages folder (without json, and you can make a new file)") + @ConfDefault.DefaultString("") + String help_response(); + @AnnotationBasedSorter.Order(150) @ConfKey("bungee-mode") @ConfComments("# Bungee Mode. This will make bot not respond to commands, and nothing will happen as if plugin not installed (only mc leveling is active). This option should be enabled on all servers except lobby if you use bungee") diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/database/DatabaseManager.java b/core/src/main/java/tk/bluetree242/discordsrvutils/database/DatabaseManager.java index 37562ef3..8bb5a7db 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/database/DatabaseManager.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/database/DatabaseManager.java @@ -32,7 +32,6 @@ import org.jooq.conf.Settings; import org.jooq.impl.DSL; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; -import tk.bluetree242.discordsrvutils.exceptions.UnCheckedSQLException; import java.nio.file.Paths; import java.sql.Connection; @@ -46,40 +45,44 @@ public class DatabaseManager { //database connection pool private HikariDataSource sql; private boolean hsqldb = false; + private DSLContext jooq; public void setupDatabase() throws SQLException { - System.setProperty("hsqldb.reconfig_logging", "false"); - try { - Class.forName("tk.bluetree242.discordsrvutils.dependencies.hsqldb.jdbc.JDBCDriver"); - } catch (ClassNotFoundException e) { - core.getLogger().severe("Could not set JDBCDriver"); - return; - } HikariConfig settings = new HikariConfig(); String jdbcurl = null; String user = null; String pass = null; - if (core.getSqlconfig().isEnabled()) { - jdbcurl = "jdbc:mysql://" + - core.getSqlconfig().Host() + - ":" + core.getSqlconfig().Port() + "/" + core.getSqlconfig().DatabaseName(); - user = core.getSqlconfig().UserName(); - pass = core.getSqlconfig().Password(); - } else { - core.logger.info("MySQL is disabled, using hsqldb"); - hsqldb = true; - jdbcurl = "jdbc:hsqldb:file:" + Paths.get(core.getPlatform().getDataFolder() + core.fileseparator + "database").resolve("Database") + ";hsqldb.lock_file=false;sql.syntax_mys=true;sql.lowercase_ident=true"; - user = "SA"; - pass = ""; + ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(DatabaseManager.class.getClassLoader()); + try { + if (core.getSqlconfig().isEnabled()) { + jdbcurl = "jdbc:mysql://" + + core.getSqlconfig().Host() + + ":" + core.getSqlconfig().Port() + "/" + core.getSqlconfig().DatabaseName(); + user = core.getSqlconfig().UserName(); + pass = core.getSqlconfig().Password(); + } else { + core.logger.info("MySQL is disabled, using hsqldb"); + hsqldb = true; + jdbcurl = "jdbc:hsqldb:file:" + Paths.get(core.getPlatform().getDataFolder() + core.fileseparator + "database").resolve("Database") + ";hsqldb.lock_file=false;sql.syntax_mys=true;sql.lowercase_ident=true"; + user = "SA"; + pass = ""; + } + //load jooq classes + new Thread(() -> new JooqClassLoading(core).preInitializeJooqClasses()).start(); + settings.setDriverClassName(hsqldb ? "tk.bluetree242.discordsrvutils.dependencies.hsqldb.jdbc.JDBCDriver" : "tk.bluetree242.discordsrvutils.dependencies.mariadb.Driver"); + settings.setJdbcUrl(jdbcurl); + settings.setUsername(user); + settings.setPassword(pass); + sql = new HikariDataSource(settings); + jooq = DSL.using(sql, hsqldb ? SQLDialect.HSQLDB : SQLDialect.MYSQL, this.settings); + migrate(); + core.getLogger().info("MySQL/HsqlDB Connected & Setup"); + } catch (Exception ex) { + throw new RuntimeException(ex); + } finally { + Thread.currentThread().setContextClassLoader(oldCl); } - //load jooq classes - new Thread(() -> new JooqClassLoading(core).preInitializeJooqClasses()).start(); - settings.setJdbcUrl(jdbcurl); - settings.setUsername(user); - settings.setPassword(pass); - sql = new HikariDataSource(settings); - migrate(); - core.getLogger().info("MySQL/HsqlDB Connected & Setup"); } public void migrate() { @@ -99,20 +102,11 @@ public Connection getConnection() throws SQLException { return sql.getConnection(); } - - public DSLContext jooq(Connection conn) { - return DSL.using(conn, hsqldb ? SQLDialect.HSQLDB : SQLDialect.MYSQL, settings); - } - - public DSLContext newJooqConnection() { - try { - return jooq(getConnection()); - } catch (SQLException ex) { - throw new UnCheckedSQLException(ex); - } + public DSLContext jooq() { + return jooq; } - public DSLContext newRenderOnlyJooq() { + protected DSLContext newRenderOnlyJooq() { return DSL.using(hsqldb ? SQLDialect.HSQLDB : SQLDialect.MYSQL, settings); } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/interfaces/Punishment.java b/core/src/main/java/tk/bluetree242/discordsrvutils/interfaces/Punishment.java index 4a38b63c..47492b1d 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/interfaces/Punishment.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/interfaces/Punishment.java @@ -60,10 +60,8 @@ static void announcePunishment(Punishment punishment, DiscordSRVUtils core) { if (punishment.isPermanent()) { msg = punishmentMsg(core, core.getBansConfig().MutedMessage(), placeholder); } else { - if (punishment.isIp()) - msg = punishmentMsg(core, core.getBansConfig().TempMutedMessage(), placeholder); - else - msg = punishmentMsg(core, core.getBansConfig().tempBannedMessage(), placeholder); + //there is no temp ip mute message for now + msg = punishmentMsg(core, core.getBansConfig().TempMutedMessage(), placeholder); } break; case WARN: diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/listeners/discordsrv/DiscordSRVListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/listeners/discordsrv/DiscordSRVListener.java index 8b965f63..721a1f8e 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/listeners/discordsrv/DiscordSRVListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/listeners/discordsrv/DiscordSRVListener.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.List; @RequiredArgsConstructor public class DiscordSRVListener { @@ -60,20 +61,20 @@ public void onLink(AccountLinkedEvent e) { core.getAsyncManager().executeAsync(() -> { LevelingManager manager = core.getLevelingManager(); PlayerStats stats = manager.getPlayerStats(e.getUser().getIdLong()); - int level = stats.getLevel(); if (stats == null) return; + int level = stats.getLevel(); String id = e.getUser().getId(); if (id == null) return; Member member = Utils.retrieveMember(core.getDiscordSRV().getMainGuild(), e.getUser().getIdLong()); if (member == null) return; Collection actions = new ArrayList<>(); - for (Role role : manager.getRolesToRemove(stats.getLevel())) { + for (Role role : manager.getLevelingRewardsManager().getRolesToRemove(stats.getLevel())) { if (member.getRoles().contains(role)) actions.add(core.getPlatform().getDiscordSRV().getMainGuild().removeRoleFromMember(member, role).reason("User should not have this role")); } - Role toAdd = manager.getRoleForLevel(level); - if (toAdd != null && !member.getRoles().contains(toAdd)) { - actions.add(core.getPlatform().getDiscordSRV().getMainGuild().addRoleToMember(member, toAdd).reason("Account Linked")); + List toAdd = manager.getLevelingRewardsManager().getRolesForLevel(level); + for (Role role : toAdd) { + actions.add(core.getPlatform().getDiscordSRV().getMainGuild().addRoleToMember(member, role).reason("Account Linked")); } if (!actions.isEmpty()) RestAction.allOf(actions).queue(); }); @@ -87,7 +88,7 @@ public void onUnlink(AccountUnlinkedEvent e) { core.getAsyncManager().executeAsync(() -> { Member member = Utils.retrieveMember(core.getDiscordSRV().getMainGuild(), e.getDiscordUser().getIdLong()); if (member != null) { - for (Role role : manager.getRolesToRemove(null)) { + for (Role role : manager.getLevelingRewardsManager().getRolesToRemove(null)) { if (member.getRoles().contains(role)) core.getPlatform().getDiscordSRV().getMainGuild().removeRoleFromMember(member, role).reason("Account Unlinked").queue(); } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/listeners/jda/WelcomerAndGoodByeListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/listeners/jda/WelcomerAndGoodByeListener.java index 0811828a..1ace2a22 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/listeners/jda/WelcomerAndGoodByeListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/listeners/jda/WelcomerAndGoodByeListener.java @@ -37,8 +37,6 @@ import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObjectList; import tk.bluetree242.discordsrvutils.systems.invitetracking.InviteTrackingManager; -import java.sql.Connection; -import java.sql.SQLException; import java.util.Iterator; import java.util.List; @@ -68,11 +66,7 @@ public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent e) { } //store in db if (!core.getMainConfig().bungee_mode() && core.getMainConfig().track_invites() && invite != null) { - try (Connection conn = core.getDatabaseManager().getConnection()) { - core.getInviteTrackingManager().addInvite(core.getDatabaseManager().jooq(conn), e.getUser().getIdLong(), invite.getUserId(), invite.getGuildId()); - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex); - } + core.getInviteTrackingManager().addInvite(core.getDatabaseManager().jooq(), e.getUser().getIdLong(), invite.getUserId(), invite.getGuildId()); } //welcomer if (core.getMainConfig().welcomer_enabled()) { @@ -103,11 +97,7 @@ public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent e) { public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent e) { core.getAsyncManager().executeAsync(() -> { if (!e.getUser().isBot()) { - try (Connection conn = core.getDatabaseManager().getConnection()) { - core.getInviteTrackingManager().leftServer(core.getDatabaseManager().jooq(conn), e.getUser().getIdLong()); - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex); - } + core.getInviteTrackingManager().leftServer(core.getDatabaseManager().jooq(), e.getUser().getIdLong()); if (core.getMainConfig().goodbye_enabled()) { MessageChannel channel = core.getJdaManager().getChannel(core.getMainConfig().goodbye_channel()); if (channel == null) { diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/other/MessageFilter.java b/core/src/main/java/tk/bluetree242/discordsrvutils/other/MessageFilter.java index 23fb12a1..0da36e3e 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/other/MessageFilter.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/other/MessageFilter.java @@ -23,152 +23,47 @@ package tk.bluetree242.discordsrvutils.other; import lombok.RequiredArgsConstructor; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.core.Filter; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.message.Message; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; -import java.lang.reflect.Field; +import java.util.logging.Level; +import java.util.logging.LogRecord; //fix the big messages that look like spam @RequiredArgsConstructor -public class MessageFilter implements Filter { +public class MessageFilter { private final DiscordSRVUtils core; - @Override - public Result getOnMismatch() { - return Result.NEUTRAL; - } - - @Override - public Result getOnMatch() { - return Result.NEUTRAL; - } - - public Result handle(String loggerName, Level level, String message) { + public boolean canLog(String loggerName, LogRecord record) { + String message = record.getMessage(); + Level level = record.getLevel(); if (loggerName.startsWith("tk.bluetree242.discordsrvutils.dependencies.hikariCP.hikari")) { //Ignorable message if (!message.contains("Driver does not support get/set network timeout for connections.")) log(level, message, "HikariCP"); - return Result.DENY; + return false; } if (loggerName.startsWith("tk.bluetree242.discordsrvutils.dependencies.flywaydb")) { if (message.contains("failed") || message.contains("is up to date. No migration necessary.")) { //Only log when success or an error, other migration, or it look like spam or error if (!message.contains("No failed migration detected.")) //This message mean everything fine, why log it log(level, message, "Flyway"); } - return Result.DENY; + return false; } - if (loggerName.contains("hsqldb.db") && level == Level.INFO) return Result.DENY; - if (loggerName.startsWith("tk.bluetree242.discordsrvutils.dependencies.jooq")) return Result.DENY; - return Result.NEUTRAL; - } - - //Redirect to 1 method so i don't recode - @Override - public Result filter(LogEvent logEvent) { - return handle( - logEvent.getLoggerName(), - logEvent.getLevel(), - logEvent.getMessage() - .getFormattedMessage()); - } - - @Override - public Result filter(Logger logger, Level level, Marker marker, String message, Object... parameters) { - return handle( - logger.getName(), - level, - message - ); - } - - @Override - public Result filter(Logger logger, Level level, Marker marker, Object message, Throwable throwable) { - return handle( - logger.getName(), - level, - message.toString() - ); - } - - @Override - public Result filter(Logger logger, Level level, Marker marker, Message message, Throwable throwable) { - return handle( - logger.getName(), - level, - message.getFormattedMessage() - ); + if (loggerName.contains("hsqldb.db") && level == Level.INFO) return false; + if (loggerName.startsWith("tk.bluetree242.discordsrvutils.dependencies.jooq")) return false; + return true; } //1 method so i can easily reformat the messages public void log(Level level, String msg, String prefix) { - switch (level.name()) { - case "INFO": - core.getLogger().info("[" + prefix + "] " + msg); - break; - case "WARN": - core.getLogger().warning("[" + prefix + "] " + msg); - break; - case "ERROR": - core.getLogger().severe("[" + prefix + "] " + msg); - break; - default: - core.getLogger().info("[" + prefix + "] " + msg); - } - } - - public void add() { - try { - ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).addFilter(this); - } catch (Exception e) { - core.logger.severe("Failed to add Message Filter"); - e.printStackTrace(); + if (Level.INFO.equals(level)) { + core.getLogger().info("[" + prefix + "] " + msg); + } else if (Level.SEVERE.equals(level)) { + core.getLogger().severe("[" + prefix + "] " + msg); + } else { + core.getLogger().warning("[" + prefix + "] " + msg); } } - public void remove() { - try { - org.apache.logging.log4j.core.Logger logger = ((org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager.getRootLogger()); - - Field configField = null; - Class targetClass = logger.getClass(); - - while (targetClass != null) { - try { - configField = targetClass.getDeclaredField("config"); - break; - } catch (NoSuchFieldException ignored) { - } - - try { - configField = targetClass.getDeclaredField("privateConfig"); - break; - } catch (NoSuchFieldException ignored) { - } - - targetClass = targetClass.getSuperclass(); - } - - if (configField != null) { - if (!configField.isAccessible()) configField.setAccessible(true); - - Object config = configField.get(logger); - Field configField2 = config.getClass().getDeclaredField("config"); - if (!configField2.isAccessible()) configField2.setAccessible(true); - - Object config2 = configField2.get(config); - if (config2 instanceof org.apache.logging.log4j.core.filter.Filterable) { - ((org.apache.logging.log4j.core.filter.Filterable) config2).removeFilter(this); - } - } - } catch (Throwable t) { - core.logger.severe("Failed to remove Message Filter"); - } - } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/platform/PlatformServer.java b/core/src/main/java/tk/bluetree242/discordsrvutils/platform/PlatformServer.java index b13ffd4a..f0a43b71 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/platform/PlatformServer.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/platform/PlatformServer.java @@ -47,4 +47,8 @@ public abstract class PlatformServer { public abstract PlatformPlayer getOfflinePlayer(UUID uuid); + public abstract PlatformPlayer getPlayer(UUID uuid); + + public abstract void executeConsoleCommands(String... cmds); + } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/commandmanagement/CommandEvent.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/commandmanagement/CommandEvent.java index cdc836d9..6145aeed 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/commandmanagement/CommandEvent.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/commandmanagement/CommandEvent.java @@ -115,7 +115,7 @@ public OptionMapping getOption(String name) { } public DSLContext getConnection() { - if (!isConnOpen()) return connection = core.getDatabaseManager().newJooqConnection(); + if (!isConnOpen()) return connection = core.getDatabaseManager().jooq(); return connection; } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/LevelingManager.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/LevelingManager.java index 7b3c3ee8..f6f55b3f 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/LevelingManager.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/LevelingManager.java @@ -24,72 +24,25 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; -import github.scarsz.discordsrv.dependencies.jda.api.entities.Role; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.jooq.DSLContext; -import org.json.JSONException; -import org.json.JSONObject; +import org.jooq.Result; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; -import tk.bluetree242.discordsrvutils.exceptions.UnCheckedSQLException; import tk.bluetree242.discordsrvutils.jooq.tables.LevelingTable; import tk.bluetree242.discordsrvutils.jooq.tables.records.LevelingRecord; -import tk.bluetree242.discordsrvutils.utils.FileWriter; -import tk.bluetree242.discordsrvutils.utils.Utils; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.sql.Connection; -import java.sql.SQLException; + import java.time.Duration; import java.util.*; -import java.util.stream.Collectors; @RequiredArgsConstructor public class LevelingManager { public final Long MAP_EXPIRATION_NANOS = Duration.ofSeconds(60L).toNanos(); public final Map antispamMap = new HashMap<>(); private final DiscordSRVUtils core; - private boolean adding = false; - //leveling roles jsonobject, Initialized on startup @Getter - private JSONObject levelingRolesRaw; - - public void reloadLevelingRoles() { - try { - File levelingRoles = new File(core.getPlatform().getDataFolder(), core.fileseparator + "leveling-roles.json"); - if (!levelingRoles.exists()) { - levelingRoles.createNewFile(); - FileWriter writer = new FileWriter(levelingRoles); - writer.write(new JSONObject().put("_wiki", "https://wiki.discordsrvutils.xyz/leveling-roles/").toString(1)); - writer.close(); - levelingRolesRaw = new JSONObject(); - } else { - levelingRolesRaw = new JSONObject(Utils.readFile(levelingRoles)); - } - } catch (FileNotFoundException e) { - core.getLogger().severe("Error creating leveling-roles.json"); - levelingRolesRaw = new JSONObject(); - } catch (IOException e) { - core.getLogger().severe("Error creating leveling-roles.json: " + e.getMessage()); - } catch (JSONException e) { - core.getLogger().severe("Error loading leveling-roles.json: " + e.getMessage()); - } - } public LoadingCache cachedUUIDS = Caffeine.newBuilder() - .maximumSize(120) - .expireAfterWrite(Duration.ofMinutes(1)) - .refreshAfterWrite(Duration.ofSeconds(30)) - .build(key -> { - DiscordSRVUtils core = DiscordSRVUtils.get(); - adding = true; - PlayerStats stats = null; - try (Connection conn = core.getDatabaseManager().getConnection()) { - stats = getPlayerStats(key, core.getDatabaseManager().jooq(conn)); - } catch (SQLException ignored) {} //not print trillion messages in console if something goes wrong - adding = false; - return stats; - }); + private final LevelingRewardsManager levelingRewardsManager; + private boolean adding = false; public PlayerStats getCachedStats(UUID uuid) { return cachedUUIDS.get(uuid); @@ -104,32 +57,32 @@ public PlayerStats getCachedStats(long discordID) { public boolean isLinked(UUID uuid) { String discord = core.getDiscordSRV().getDiscordId(uuid); return discord != null; - } - - public PlayerStats getPlayerStats(long discordID, DSLContext conn) { - UUID uuid = core.getDiscordSRV().getUuid(discordID + ""); - if (uuid == null) return null; - return getPlayerStats(uuid, conn); - } + } public LoadingCache cachedUUIDS = Caffeine.newBuilder() + .maximumSize(120) + .expireAfterWrite(Duration.ofMinutes(1)) + .refreshAfterWrite(Duration.ofSeconds(30)) + .build(key -> { + DiscordSRVUtils core = DiscordSRVUtils.get(); + adding = true; + PlayerStats stats = getPlayerStats(key); + adding = false; + return stats; + }); public PlayerStats getPlayerStats(long discordID) { + DSLContext conn = core.getDatabaseManager().jooq(); UUID uuid = core.getDiscordSRV().getUuid(discordID + ""); if (uuid == null) return null; - DSLContext conn = core.getDatabaseManager().newJooqConnection(); - PlayerStats result = getPlayerStats(uuid, conn); - try { - conn.configuration().connectionProvider().acquire().close(); - } catch (SQLException throwables) { - throw new UnCheckedSQLException(throwables); - } - return result; + return getPlayerStats(uuid); } - public PlayerStats getPlayerStats(String name, DSLContext conn) { + public PlayerStats getPlayerStats(String name) { + DSLContext conn = core.getDatabaseManager().jooq(); return getPlayerStats(conn, name); } - public PlayerStats getPlayerStats(UUID uuid, DSLContext conn) { + public PlayerStats getPlayerStats(UUID uuid) { + DSLContext conn = core.getDatabaseManager().jooq(); List records = conn.selectFrom(LevelingTable.LEVELING).orderBy(LevelingTable.LEVELING.LEVEL.desc()).fetch(); int num = 0; for (LevelingRecord record : records) { @@ -166,7 +119,8 @@ public PlayerStats getPlayerStats(LevelingRecord r, int rank) { return stats; } - public List getLeaderboard(int max, DSLContext conn) { + public List getLeaderboard(int max) { + DSLContext conn = core.getDatabaseManager().jooq(); List records = conn.selectFrom(LevelingTable.LEVELING).orderBy(LevelingTable.LEVELING.LEVEL.desc()).limit(max).fetch(); List leaderboard = new ArrayList<>(); int num = 0; @@ -177,43 +131,38 @@ public List getLeaderboard(int max, DSLContext conn) { return leaderboard; } - public Role getRoleForLevel(int level) { - Map map = levelingRolesRaw.toMap(); - List keys = new ArrayList<>(map.keySet()); - keys = keys.stream() - .filter(num -> { - try { - return Integer.parseInt(num) <= level; - } catch (NumberFormatException ex) { - return false; //not a level, maybe the _wiki one? - } - }) - .collect(Collectors.toList()); - if (keys.isEmpty()) return null; - keys.sort((o1, o2) -> Integer.parseInt(o2) - Integer.parseInt(o1)); - Long id = (Long) map.get(keys.get(0)); - if (id != null) { - return core.getPlatform().getDiscordSRV().getMainGuild().getRoleById(id); - } - return null; + public void resetLeveling() { + core.getDatabaseManager().jooq().update(LevelingTable.LEVELING).set(LevelingTable.LEVELING.LEVEL, 0).set(LevelingTable.LEVELING.XP, 0).execute(); } - public List getRolesToRemove(Integer level) { - - List roles = new ArrayList<>(); - Map map = levelingRolesRaw.toMap(); - List values = new ArrayList<>(map.values()); - for (Object value : values) { - if (!(value instanceof Long)) continue; - Long id = (Long) value; - roles.add(core.getPlatform().getDiscordSRV().getMainGuild().getRoleById(id)); + public void convertToMee6() { + DSLContext conn = core.getDatabaseManager().jooq(); + Result results = conn.selectFrom(LevelingTable.LEVELING).fetch(); + + for (LevelingRecord result : results) { + if (cachedUUIDS.getIfPresent(UUID.fromString(result.getUuid())) != null) cachedUUIDS.invalidate(cachedUUIDS.get(UUID.fromString(result.getUuid()))); + int totalXP = (result.getLevel() * 300) + result.getXp(); + int level = 0; + Integer xp = null; + while (xp == null) { + totalXP = totalXP - getRequiredXP(level); + if (totalXP > 0) level++; + else if (totalXP == 0) { + xp = 0; + level++; + } + else xp = getRequiredXP(level) - Math.abs(totalXP); + } + conn.update(LevelingTable.LEVELING) + .set(LevelingTable.LEVELING.LEVEL, level) + .set(LevelingTable.LEVELING.XP, xp) + .where(LevelingTable.LEVELING.UUID.eq(result.getUuid())).execute(); } - if (level != null) - roles.remove(getRoleForLevel(level)); - return roles; } - + private int getRequiredXP(int level) { + return (int) (5 * (Math.pow(level, 2)) + (50 * level) + 100); + } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/LevelingRewardsManager.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/LevelingRewardsManager.java new file mode 100644 index 00000000..a3f7fd01 --- /dev/null +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/LevelingRewardsManager.java @@ -0,0 +1,241 @@ +/* + * LICENSE + * DiscordSRVUtils + * ------------- + * Copyright (C) 2020 - 2022 BlueTree242 + * ------------- + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * END + */ + +package tk.bluetree242.discordsrvutils.systems.leveling; + +import github.scarsz.discordsrv.dependencies.jackson.databind.ObjectMapper; +import github.scarsz.discordsrv.dependencies.jda.api.entities.Role; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import tk.bluetree242.discordsrvutils.DiscordSRVUtils; +import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObject; +import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObjectList; +import tk.bluetree242.discordsrvutils.platform.PlatformPlayer; +import tk.bluetree242.discordsrvutils.utils.FileWriter; +import tk.bluetree242.discordsrvutils.utils.Utils; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class LevelingRewardsManager { + private final DiscordSRVUtils core; + @Getter + private JSONObject levelingRewardsRaw; + @Getter + @Setter + private JSONObject rewardCache; + private File rewardCacheFile; + + public void reloadLevelingRewards() { + rewardCacheFile = new File(core.getPlatform().getDataFolder(), core.fileseparator + "data" + core.fileseparator + "leveling-reward-cache.json"); + try { + File file = new File(core.getPlatform().getDataFolder(), core.fileseparator + "leveling-roles.json"); + File filer = new File(core.getPlatform().getDataFolder(), core.fileseparator + "leveling-rewards.json"); + JSONObject json; + if (file.exists()) { + if (filer.exists()) { + core.getLogger().warning("Found leveling-roles.json, and leveling-rewards.json. Not converting, using new leveling-rewards.json"); + levelingRewardsRaw = new JSONObject(Utils.readFile(filer)); + return; + } + json = new JSONObject(Utils.readFile(file)); + file.renameTo(filer); + filer = file; + levelingRewardsRaw = new JSONObject(); + if (json.isEmpty() || (json.length() == 1 && json.has("_wiki"))) return; + json = convertToRewards(json); + } else { + if (filer.exists()) { + levelingRewardsRaw = new JSONObject(Utils.readFile(filer)); + return; + } else { + json = new JSONObject().put("_wiki", "https://wiki.discordsrvutils.xyz/leveling-rewards/"); //the time i wrote this, it's a 404 + } + } + FileWriter writer = new FileWriter(filer); + writer.write(new ObjectMapper().readTree(json.toString()).toPrettyString()); + writer.close(); + levelingRewardsRaw = json; + } catch (IOException | JSONException e) { + levelingRewardsRaw = new JSONObject(); + core.severe("Failed to load leveling-rewards.json: " + e.getClass().getName() + ": " + e.getMessage()); + } + } + + public void reloadRewardCache() { + try { + if (rewardCacheFile.exists()) { + rewardCache = new JSONObject(Utils.readFile(rewardCacheFile)); + } else { + rewardCache = new JSONObject(); + if (needCache()) { + rewardCacheFile.getParentFile().mkdirs(); + rewardCacheFile.createNewFile(); + FileWriter writer = new FileWriter(rewardCacheFile); + writer.write(rewardCache.toString()); + writer.close(); + } + } + } catch (IOException e) { + rewardCache = new JSONObject(); + core.severe("Failed to load leveling reward cache: " + e.getClass().getName() + ": " + e.getMessage()); + } + } + + private List getCommands(JSONObject level, PlayerStats stats) { + if (!level.has("commands")) return null; + return level.getJSONArray("commands").toList().stream() + .map(o -> (String) o) + .map(c -> PlaceholdObjectList.ofArray(core, new PlaceholdObject(core, stats, "stats")).apply(c)) //placeholders + .collect(Collectors.toList()); + } + + private List getCommands(int level, int lastLevel, PlayerStats stats) { + List result = new ArrayList<>(); + for (int num = (lastLevel + 1); num <= level; num++) { + Object o = getLevelObject(num); + if (o == null) continue; + if (o instanceof JSONObject) { + JSONObject json = (JSONObject) o; + List resultLevel = getCommands(json, stats); + if (resultLevel != null) result.addAll(resultLevel); + } + } + return result; + } + + private int getLastLevel(UUID uuid) { + return rewardCache.has(uuid.toString()) ? rewardCache.getInt(uuid.toString()) : 0; + } + + public void rewardIfOnline(PlayerStats stats) { + int lastLevel = getLastLevel(stats.getUuid()); + if (lastLevel == stats.getLevel()) return; //they got all rewards + if (lastLevel > stats.getLevel()) { + rewardCache.remove(stats.getUuid().toString()); + saveRewardCache(); + } + PlatformPlayer player = core.getPlatform().getServer().getPlayer(stats.getUuid()); + if (player == null) return; + List commands = getCommands(stats.getLevel(), lastLevel, stats); + if (commands.isEmpty()) return; + core.getPlatform().getServer().executeConsoleCommands(commands.stream().toArray(i -> new String[commands.size()])); + rewardCache.put(stats.getUuid().toString(), stats.getLevel()); + saveRewardCache(); + } + + public void saveRewardCache() { + try { + FileWriter writer = new FileWriter(rewardCacheFile); + writer.write(rewardCache.toString()); + writer.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private boolean needCache() { + for (String key : levelingRewardsRaw.toMap().keySet()) { + try { + int num = Integer.parseInt(key); + Object v = getLevelObject(num); + if (v == null) continue; //unreachable but just in case + if (v instanceof JSONObject && ((JSONObject) v).has("commands")) return true; + } catch (NumberFormatException ex) { + //not a level + } + } + return false; + } + + private JSONObject convertToRewards(JSONObject roles) { + JSONObject result = new JSONObject(); + for (String key : roles.toMap().keySet()) { + Object value = roles.get(key); + if (value instanceof Long) result.put(key + "", new JSONObject().put("roles", new JSONArray().put(value))); + else result.put(key, value); + } + return result; + } + + public List getRolesForLevel(int level) { + List result = new ArrayList<>(); + boolean found; + int num = getLastLevelWithRoles(level); + if (num == -1) return result; + JSONObject json = levelingRewardsRaw.getJSONObject(num + ""); + result.addAll(getRoleIds(json)); + return result; + } + + private int getLastLevelWithRoles(int level) { + int result = -1; + int num = level; + while (num >= 0 && result == -1) { + Object o = getLevelObject(num); + num--; + if (o instanceof JSONObject && ((JSONObject) o).has("roles")) result = num + 1; + } + return result; + } + + private Object getLevelObject(int level) { + if (levelingRewardsRaw.has(level + "")) return levelingRewardsRaw.get(level + ""); + return null; + } + + public List getRolesToRemove(Integer level) { + + List roles = new ArrayList<>(); + Map map = levelingRewardsRaw.toMap(); + List keys = new ArrayList<>(map.keySet()); + int num = level == null ? -1 : getLastLevelWithRoles(level); + for (String key : keys) { + if (key.equals(num + "")) continue; + Object value = levelingRewardsRaw.get(key); + if (!(value instanceof JSONObject)) continue; + roles.addAll(getRoleIds((JSONObject) value)); + } + return roles; + } + + private List getRoleIds(JSONObject json) { + List result = new ArrayList<>(); + if (json.has("roles")) { + JSONArray roles = json.getJSONArray("roles"); + roles.forEach(r -> result.add(core.getPlatform().getDiscordSRV().getMainGuild().getRoleById((Long) r))); + } + + return result; + } + +} diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/PlayerStats.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/PlayerStats.java index 9bd01697..340efa86 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/PlayerStats.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/PlayerStats.java @@ -26,6 +26,7 @@ import github.scarsz.discordsrv.dependencies.jda.api.entities.Member; import github.scarsz.discordsrv.dependencies.jda.api.entities.Role; import github.scarsz.discordsrv.dependencies.jda.api.requests.RestAction; +import lombok.Setter; import org.jooq.DSLContext; import org.jooq.TableField; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; @@ -34,15 +35,17 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.UUID; public class PlayerStats { private final DiscordSRVUtils core; private final UUID uuid; - private final String name; private final int minecraftMessages; private final int discordMessages; private final int rank; + @Setter + private String name; private int level; private int xp; @@ -69,31 +72,34 @@ public int getLevel() { return level; } - public int getXp() { - return xp; - } - - public void setLevel(int level, DSLContext conn) { + public void setLevel(int level) { + DSLContext conn = core.getDatabaseManager().jooq(); conn.update(LevelingTable.LEVELING).set(LevelingTable.LEVELING.LEVEL, level) .where(LevelingTable.LEVELING.UUID.eq(uuid.toString())) .execute(); this.level = level; } - public boolean setXP(int xp, DSLContext conn) { + public int getXp() { + return xp; + } + + public boolean setXP(int xp) { + DSLContext conn = core.getDatabaseManager().jooq(); return setXP(xp, null); } + public int getTotalXpRequired() { + return (int) (5 * (Math.pow(level, 2)) + (50 * level) + 100); //mee6's algorithm + } + /** * @param xp XP to add * @return true if player leveled up, false if not */ - public boolean setXP(int xp, LevelupEvent event, DSLContext conn) { - if (event == null) { - event = new LevelupEvent(this, uuid); - } - LevelupEvent finalEvent = event; - if (xp >= 300) { + public boolean setXP(int xp, LevelupEvent event) { + DSLContext conn = core.getDatabaseManager().jooq(); + if (xp >= getTotalXpRequired()) { conn.update(LevelingTable.LEVELING) .set(LevelingTable.LEVELING.LEVEL, level + 1) .set(LevelingTable.LEVELING.XP, 0) @@ -101,23 +107,9 @@ public boolean setXP(int xp, LevelupEvent event, DSLContext conn) { .execute(); this.level = level + 1; this.xp = 0; - String id = core.getDiscordSRV().getDiscordId(uuid); - if (id == null) return true; - LevelingManager manager = core.getLevelingManager(); - Member member = core.getPlatform().getDiscordSRV().getMainGuild().retrieveMemberById(id).complete(); - if (member == null) return true; - Collection actions = new ArrayList<>(); - for (Role role : manager.getRolesToRemove(level)) { - if (member.getRoles().contains(role)) - actions.add(core.getPlatform().getDiscordSRV().getMainGuild().removeRoleFromMember(member, role).reason("User Leveled Up")); - } - Role toAdd = manager.getRoleForLevel(level); - if (toAdd != null) { - actions.add(core.getPlatform().getDiscordSRV().getMainGuild().addRoleToMember(member, toAdd).reason("User Leveled Up")); - } - if (!actions.isEmpty()) - RestAction.allOf(actions).queue(); - DiscordSRV.api.callEvent(finalEvent); + handleRewards(); + if (event != null) + DiscordSRV.api.callEvent(event); return true; } conn.update(LevelingTable.LEVELING) @@ -127,6 +119,29 @@ public boolean setXP(int xp, LevelupEvent event, DSLContext conn) { return false; } + public int getXpPercentage() { + return (int) (((double) xp) * 100 / (double) getTotalXpRequired()); + } + + private void handleRewards() { + LevelingManager manager = core.getLevelingManager(); + String id = core.getDiscordSRV().getDiscordId(uuid); + if (id == null) return; + Member member = core.getPlatform().getDiscordSRV().getMainGuild().retrieveMemberById(id).complete(); + if (member == null) return; + Collection actions = new ArrayList<>(); + for (Role role : manager.getLevelingRewardsManager().getRolesToRemove(level)) { + if (member.getRoles().contains(role)) + actions.add(core.getPlatform().getDiscordSRV().getMainGuild().removeRoleFromMember(member, role).reason("User Leveled Up")); + } + List toAdd = manager.getLevelingRewardsManager().getRolesForLevel(level); + for (Role role : toAdd) { + actions.add(core.getPlatform().getDiscordSRV().getMainGuild().addRoleToMember(member, role).reason("Account Linked")); + } + if (!actions.isEmpty()) + RestAction.allOf(actions).queue(); + } + public int getMinecraftMessages() { return minecraftMessages; } @@ -135,7 +150,8 @@ public int getDiscordMessages() { return discordMessages; } - public void addMessage(MessageType type, DSLContext conn) { + public void addMessage(MessageType type) { + DSLContext conn = core.getDatabaseManager().jooq(); TableField toUpdate = null; int value = 0; switch (type) { @@ -157,4 +173,8 @@ public void addMessage(MessageType type, DSLContext conn) { public int getRank() { return rank; } + + public List getRoles() { + return core.getLevelingManager().getLevelingRewardsManager().getRolesForLevel(level); + } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/listeners/game/GameLevelingListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/listeners/game/GameLevelingListener.java index 18ed1b53..b34a3a7f 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/listeners/game/GameLevelingListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/listeners/game/GameLevelingListener.java @@ -26,9 +26,7 @@ import org.jooq.DSLContext; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; import tk.bluetree242.discordsrvutils.events.MinecraftLevelupEvent; -import tk.bluetree242.discordsrvutils.exceptions.UnCheckedSQLException; import tk.bluetree242.discordsrvutils.jooq.tables.LevelingTable; -import tk.bluetree242.discordsrvutils.jooq.tables.records.LevelingRecord; import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObject; import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObjectList; import tk.bluetree242.discordsrvutils.platform.events.PlatformChatEvent; @@ -36,10 +34,9 @@ import tk.bluetree242.discordsrvutils.platform.listener.PlatformListener; import tk.bluetree242.discordsrvutils.systems.leveling.MessageType; import tk.bluetree242.discordsrvutils.systems.leveling.PlayerStats; +import tk.bluetree242.discordsrvutils.utils.Utils; import java.security.SecureRandom; -import java.sql.Connection; -import java.sql.SQLException; @RequiredArgsConstructor public class GameLevelingListener extends PlatformListener { @@ -47,29 +44,24 @@ public class GameLevelingListener extends PlatformListener { public void onJoin(PlatformJoinEvent e) { core.getAsyncManager().executeAsync(() -> { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - LevelingRecord record = jooq - .selectFrom(LevelingTable.LEVELING) - .where(LevelingTable.LEVELING.UUID.eq(e.getPlayer().getUniqueId().toString())) - .fetchOne(); - if (record == null) { - jooq.insertInto(LevelingTable.LEVELING) - .set(LevelingTable.LEVELING.UUID, e.getPlayer().getUniqueId().toString()) + PlayerStats stats = core.getLevelingManager().getPlayerStats(e.getPlayer().getUniqueId()); + DSLContext jooq = core.getDatabaseManager().jooq(); + if (stats == null) { + jooq.insertInto(LevelingTable.LEVELING) + .set(LevelingTable.LEVELING.UUID, e.getPlayer().getUniqueId().toString()) + .set(LevelingTable.LEVELING.NAME, e.getPlayer().getName()) + .set(LevelingTable.LEVELING.LEVEL, 0) + .set(LevelingTable.LEVELING.XP, 0) + .execute(); + } else { + if (!stats.getName().equals(e.getPlayer().getName())) { + jooq.update(LevelingTable.LEVELING) .set(LevelingTable.LEVELING.NAME, e.getPlayer().getName()) - .set(LevelingTable.LEVELING.LEVEL, 0) - .set(LevelingTable.LEVELING.XP, 0) + .where(LevelingTable.LEVELING.UUID.eq(e.getPlayer().getUniqueId().toString())) .execute(); - } else { - if (!record.getName().equals(e.getPlayer().getName())) { - jooq.update(LevelingTable.LEVELING) - .set(LevelingTable.LEVELING.NAME, e.getPlayer().getName()) - .where(LevelingTable.LEVELING.UUID.eq(e.getPlayer().getUniqueId().toString())) - .execute(); - } } - } catch (SQLException ex) { - throw new UnCheckedSQLException(ex); + stats.setName(e.getPlayer().getName()); + core.getLevelingManager().getLevelingRewardsManager().rewardIfOnline(stats); } }); } @@ -78,30 +70,26 @@ public void onChat(PlatformChatEvent e) { if (!core.getLevelingConfig().enabled()) return; if (e.isCancelled()) return; core.getAsyncManager().executeAsync(() -> { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - PlayerStats stats = core.getLevelingManager().getPlayerStats(e.getPlayer().getUniqueId(), jooq); - if (stats == null) { - return; - } - if (core.getLevelingConfig().antispam_messages()) { - Long val = core.getLevelingManager().antispamMap.get(stats.getUuid()); - if (val == null) { - core.getLevelingManager().antispamMap.put(stats.getUuid(), System.nanoTime()); - } else { - if (!(System.nanoTime() - val >= core.getLevelingManager().MAP_EXPIRATION_NANOS)) return; - core.getLevelingManager().antispamMap.remove(stats.getUuid()); - core.getLevelingManager().antispamMap.put(stats.getUuid(), System.nanoTime()); - } - } - int toAdd = new SecureRandom().nextInt(50); - boolean leveledUp = stats.setXP(stats.getXp() + toAdd, new MinecraftLevelupEvent(stats, e.getPlayer()), jooq); - stats.addMessage(MessageType.MINECRAFT, jooq); - if (leveledUp) { - e.getPlayer().sendMessage(PlaceholdObjectList.ofArray(core, new PlaceholdObject(core, stats, "stats"), new PlaceholdObject(core, e.getPlayer(), "player")).apply(String.join("\n", core.getLevelingConfig().minecraft_levelup_message()), e.getPlayer())); + PlayerStats stats = core.getLevelingManager().getPlayerStats(e.getPlayer().getUniqueId()); + if (stats == null) { + return; + } + if (core.getLevelingConfig().antispam_messages()) { + Long val = core.getLevelingManager().antispamMap.get(stats.getUuid()); + if (val == null) { + core.getLevelingManager().antispamMap.put(stats.getUuid(), System.nanoTime()); + } else { + if (!(System.nanoTime() - val >= core.getLevelingManager().MAP_EXPIRATION_NANOS)) return; + core.getLevelingManager().antispamMap.remove(stats.getUuid()); + core.getLevelingManager().antispamMap.put(stats.getUuid(), System.nanoTime()); } - } catch (SQLException ex) { - throw new UnCheckedSQLException(ex); + } + int toAdd = Utils.nextInt(15, 25); + boolean leveledUp = stats.setXP(stats.getXp() + toAdd, new MinecraftLevelupEvent(stats, e.getPlayer())); + stats.addMessage(MessageType.MINECRAFT); + if (leveledUp) { + e.getPlayer().sendMessage(PlaceholdObjectList.ofArray(core, new PlaceholdObject(core, stats, "stats"), new PlaceholdObject(core, e.getPlayer(), "player")).apply(String.join("\n", core.getLevelingConfig().minecraft_levelup_message()), e.getPlayer())); + core.getLevelingManager().getLevelingRewardsManager().rewardIfOnline(stats); } }); diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/listeners/jda/DiscordLevelingListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/listeners/jda/DiscordLevelingListener.java index 6591bd3f..39b63f2c 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/listeners/jda/DiscordLevelingListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/leveling/listeners/jda/DiscordLevelingListener.java @@ -27,19 +27,21 @@ import github.scarsz.discordsrv.dependencies.jda.api.events.guild.member.GuildMemberJoinEvent; import github.scarsz.discordsrv.dependencies.jda.api.events.message.guild.GuildMessageReceivedEvent; import github.scarsz.discordsrv.dependencies.jda.api.hooks.ListenerAdapter; +import github.scarsz.discordsrv.dependencies.jda.api.requests.RestAction; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; -import org.jooq.DSLContext; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; import tk.bluetree242.discordsrvutils.events.DiscordLevelupEvent; import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObject; import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObjectList; import tk.bluetree242.discordsrvutils.systems.leveling.MessageType; import tk.bluetree242.discordsrvutils.systems.leveling.PlayerStats; +import tk.bluetree242.discordsrvutils.utils.Utils; import java.security.SecureRandom; -import java.sql.Connection; -import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; @RequiredArgsConstructor public class DiscordLevelingListener extends ListenerAdapter { @@ -51,38 +53,34 @@ public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent e) { if (e.getMessage().isWebhookMessage()) return; if (e.getAuthor().isBot()) return; if (core.getPlatform().getDiscordSRV().getMainGuild().getIdLong() == core.getPlatform().getDiscordSRV().getMainGuild().getIdLong()) { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - if (core.getLevelingConfig().enabled()) { - PlayerStats stats = core.getLevelingManager().getPlayerStats(e.getMember().getIdLong()); - if (stats == null) { - return; - } - if (core.getLevelingConfig().antispam_messages()) { - Long val = core.getLevelingManager().antispamMap.get(stats.getUuid()); - if (val == null) { - core.getLevelingManager().antispamMap.put(stats.getUuid(), System.nanoTime()); - } else { - if (!(System.nanoTime() - val >= core.getLevelingManager().MAP_EXPIRATION_NANOS)) - return; - core.getLevelingManager().antispamMap.remove(stats.getUuid()); - core.getLevelingManager().antispamMap.put(stats.getUuid(), System.nanoTime()); - } - } - int toAdd = new SecureRandom().nextInt(50); - boolean leveledUp = stats.setXP(stats.getXp() + toAdd, new DiscordLevelupEvent(stats, e.getChannel(), e.getAuthor()), jooq); - stats.addMessage(MessageType.DISCORD, jooq); - if (leveledUp) { - core.queueMsg(core.getMessageManager().getMessage(core.getLevelingConfig().discord_message(), PlaceholdObjectList.ofArray(core, - new PlaceholdObject(core, stats, "stats"), - new PlaceholdObject(core, e.getAuthor(), "user"), - new PlaceholdObject(core, e.getMember(), "member"), - new PlaceholdObject(core, core.getPlatform().getDiscordSRV().getMainGuild(), "guild") - ), null).build(), core.getJdaManager().getChannel(core.getLevelingConfig().discord_channel(), e.getChannel())).queue(); + if (core.getLevelingConfig().enabled()) { + PlayerStats stats = core.getLevelingManager().getPlayerStats(e.getMember().getIdLong()); + if (stats == null) { + return; + } + if (core.getLevelingConfig().antispam_messages()) { + Long val = core.getLevelingManager().antispamMap.get(stats.getUuid()); + if (val == null) { + core.getLevelingManager().antispamMap.put(stats.getUuid(), System.nanoTime()); + } else { + if (!(System.nanoTime() - val >= core.getLevelingManager().MAP_EXPIRATION_NANOS)) + return; + core.getLevelingManager().antispamMap.remove(stats.getUuid()); + core.getLevelingManager().antispamMap.put(stats.getUuid(), System.nanoTime()); } } - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex, e.getChannel()); + int toAdd = Utils.nextInt(15, 25); + boolean leveledUp = stats.setXP(stats.getXp() + toAdd, new DiscordLevelupEvent(stats, e.getChannel(), e.getAuthor())); + stats.addMessage(MessageType.DISCORD); + if (leveledUp) { + core.queueMsg(core.getMessageManager().getMessage(core.getLevelingConfig().discord_message(), PlaceholdObjectList.ofArray(core, + new PlaceholdObject(core, stats, "stats"), + new PlaceholdObject(core, e.getAuthor(), "user"), + new PlaceholdObject(core, e.getMember(), "member"), + new PlaceholdObject(core, core.getPlatform().getDiscordSRV().getMainGuild(), "guild") + ), null).build(), core.getJdaManager().getChannel(core.getLevelingConfig().discord_channel(), e.getChannel())).queue(); + core.getLevelingManager().getLevelingRewardsManager().rewardIfOnline(stats); + } } } }); @@ -95,10 +93,12 @@ public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent e) { if (core.getDiscordSRV().getUuid(e.getUser().getId()) != null) { PlayerStats stats = core.getLevelingManager().getPlayerStats(e.getUser().getIdLong()); if (stats == null) return; - Role role = core.getLevelingManager().getRoleForLevel(stats.getLevel()); - if (role != null) { - core.getPlatform().getDiscordSRV().getMainGuild().addRoleToMember(e.getMember(), role).reason("User ReJoined").queue(); + List toAdd = core.getLevelingManager().getLevelingRewardsManager().getRolesForLevel(stats.getLevel()); + Collection actions = new ArrayList<>(); + for (Role role : toAdd) { + actions.add(core.getPlatform().getDiscordSRV().getMainGuild().addRoleToMember(e.getMember(), role).reason("Account Linked")); } + if (!actions.isEmpty()) RestAction.allOf(actions).queue(); } }); } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/messages/MessageManager.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/messages/MessageManager.java index a661315d..645f8639 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/messages/MessageManager.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/messages/MessageManager.java @@ -127,7 +127,7 @@ public EmbedBuilder parseEmbedFromJSON(JSONObject json, PlaceholdObjectList hold } if (!json.isNull("footer")) { JSONObject footer = json.getJSONObject("footer"); - embed.setFooter(getStringFromJson(footer, "text", holders, placehold), getStringFromJson(footer, "icon_url")); + embed.setFooter(getStringFromJson(footer, "text", holders, placehold), getStringFromJson(footer, "icon_url", holders, placehold)); } if (!json.isNull("thumbnail")) { JSONObject thumbnail = json.getJSONObject("thumbnail"); diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/Suggestion.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/Suggestion.java index 5ac58a42..5de418a3 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/Suggestion.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/Suggestion.java @@ -113,7 +113,8 @@ public Long getChannelID() { return ChannelID; } - public SuggestionNote addNote(Long staff, String note, DSLContext conn) { + public SuggestionNote addNote(Long staff, String note) { + DSLContext conn = core.getDatabaseManager().jooq(); conn.insertInto(SuggestionNotesTable.SUGGESTION_NOTES) .set(SuggestionNotesTable.SUGGESTION_NOTES.STAFFID, staff) .set(SuggestionNotesTable.SUGGESTION_NOTES.NOTETEXT, Utils.b64Encode(note)) @@ -126,7 +127,8 @@ public SuggestionNote addNote(Long staff, String note, DSLContext conn) { return suggestionNote; } - public void setApproved(boolean approved, Long staffID, DSLContext conn) { + public void setApproved(boolean approved, Long staffID) { + DSLContext conn = core.getDatabaseManager().jooq(); conn.update(SuggestionsTable.SUGGESTIONS) .set(SuggestionsTable.SUGGESTIONS.APPROVED, Utils.getDBoolean(approved)) .set(SuggestionsTable.SUGGESTIONS.APPROVER, staffID) diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/SuggestionManager.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/SuggestionManager.java index 259f84e0..029c5631 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/SuggestionManager.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/SuggestionManager.java @@ -33,7 +33,6 @@ import lombok.RequiredArgsConstructor; import org.jooq.DSLContext; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; -import tk.bluetree242.discordsrvutils.exceptions.UnCheckedSQLException; import tk.bluetree242.discordsrvutils.jooq.tables.SuggestionNotesTable; import tk.bluetree242.discordsrvutils.jooq.tables.SuggestionsTable; import tk.bluetree242.discordsrvutils.jooq.tables.SuggestionsVotesTable; @@ -45,8 +44,6 @@ import tk.bluetree242.discordsrvutils.utils.Emoji; import tk.bluetree242.discordsrvutils.utils.Utils; -import java.sql.Connection; -import java.sql.SQLException; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -78,21 +75,23 @@ public static ActionRow getActionRow(int yes, int no) { } - public Suggestion getSuggestionByNumber(int number, DSLContext conn) throws SQLException { + public Suggestion getSuggestionByNumber(int number) { + DSLContext conn = core.getDatabaseManager().jooq(); SuggestionsRecord record = conn.selectFrom(SuggestionsTable.SUGGESTIONS) .where(SuggestionsTable.SUGGESTIONS.SUGGESTIONNUMBER.eq(number)).fetchOne(); if (record == null) return null; return getSuggestion(record); } - public Suggestion getSuggestionByMessageID(Long MessageID, DSLContext conn) throws SQLException { + public Suggestion getSuggestionByMessageID(Long MessageID) { + DSLContext conn = core.getDatabaseManager().jooq(); SuggestionsRecord record = conn.selectFrom(SuggestionsTable.SUGGESTIONS) .where(SuggestionsTable.SUGGESTIONS.MESSAGEID.eq(MessageID)).fetchOne(); if (record == null) return null; return getSuggestion(record); } - public Suggestion getSuggestion(SuggestionsRecord r) throws SQLException { + public Suggestion getSuggestion(SuggestionsRecord r) { return getSuggestion(r, null, null); } @@ -133,7 +132,8 @@ public Suggestion getSuggestion(SuggestionsRecord r, List return suggestion; } - public Suggestion makeSuggestion(String text, Long SubmitterID, DSLContext conn) { + public Suggestion makeSuggestion(String text, Long SubmitterID) { + DSLContext conn = core.getDatabaseManager().jooq(); if (!core.getSuggestionsConfig().enabled()) { throw new IllegalStateException("Suggestions are not enabled"); } @@ -185,60 +185,56 @@ public void migrateSuggestions() { String warnmsg = "Suggestions are being migrated to the new Suggestions Mode. Users may not vote for suggestions during this time"; boolean sent = false; loading = true; - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - List records = jooq - .selectFrom(SuggestionsTable.SUGGESTIONS) - .where(SuggestionsTable.SUGGESTIONS.VOTE_MODE.notEqual(voteMode.name())) - .or(SuggestionsTable.SUGGESTIONS.VOTE_MODE.isNull()) - .fetch(); - for (SuggestionsRecord record : records) { - Suggestion suggestion = core.getSuggestionManager().getSuggestion(record); - try { - Message msg = suggestion.getMessage(); - if (msg != null) { - if (msg.getButtons().isEmpty()) { - if (voteMode == SuggestionVoteMode.REACTIONS) { - } else { - if (!sent) { - core.logger.info(warnmsg); - sent = true; - core.getSuggestionManager().loading = true; - } - msg.clearReactions().queue(); - msg.editMessage(suggestion.getCurrentMsg()).setActionRow( - Button.success("yes", SuggestionManager.getYesEmoji().toJDAEmoji()), - Button.danger("no", SuggestionManager.getNoEmoji().toJDAEmoji()), - Button.secondary("reset", github.scarsz.discordsrv.dependencies.jda.api.entities.Emoji.fromUnicode("⬜"))).queue(); - } + DSLContext jooq = core.getDatabaseManager().jooq(); + List records = jooq + .selectFrom(SuggestionsTable.SUGGESTIONS) + .where(SuggestionsTable.SUGGESTIONS.VOTE_MODE.notEqual(voteMode.name())) + .or(SuggestionsTable.SUGGESTIONS.VOTE_MODE.isNull()) + .fetch(); + for (SuggestionsRecord record : records) { + Suggestion suggestion = core.getSuggestionManager().getSuggestion(record); + try { + Message msg = suggestion.getMessage(); + if (msg != null) { + if (msg.getButtons().isEmpty()) { + if (voteMode == SuggestionVoteMode.REACTIONS) { } else { - if (voteMode == SuggestionVoteMode.REACTIONS) { - if (!sent) { - core.getSuggestionManager().loading = true; - core.logger.info(warnmsg); - sent = true; - } - msg.addReaction(SuggestionManager.getYesEmoji().getNameInReaction()).queue(); - msg.addReaction(SuggestionManager.getNoEmoji().getNameInReaction()).queue(); - msg.editMessage(msg).setActionRows(Collections.EMPTY_LIST).queue(); + if (!sent) { + core.logger.info(warnmsg); + sent = true; + core.getSuggestionManager().loading = true; + } + msg.clearReactions().queue(); + msg.editMessage(suggestion.getCurrentMsg()).setActionRow( + Button.success("yes", SuggestionManager.getYesEmoji().toJDAEmoji()), + Button.danger("no", SuggestionManager.getNoEmoji().toJDAEmoji()), + Button.secondary("reset", github.scarsz.discordsrv.dependencies.jda.api.entities.Emoji.fromUnicode("⬜"))).queue(); + } + } else { + if (voteMode == SuggestionVoteMode.REACTIONS) { + if (!sent) { + core.getSuggestionManager().loading = true; + core.logger.info(warnmsg); + sent = true; } + msg.addReaction(SuggestionManager.getYesEmoji().getNameInReaction()).queue(); + msg.addReaction(SuggestionManager.getNoEmoji().getNameInReaction()).queue(); + msg.editMessage(msg).setActionRows(Collections.EMPTY_LIST).queue(); } - jooq.update(SuggestionsTable.SUGGESTIONS) - .set(SuggestionsTable.SUGGESTIONS.VOTE_MODE, voteMode.name()) - .where(SuggestionsTable.SUGGESTIONS.SUGGESTIONNUMBER.eq(suggestion.getNumber())) - .execute(); } - } catch (ErrorResponseException ignored) { - + jooq.update(SuggestionsTable.SUGGESTIONS) + .set(SuggestionsTable.SUGGESTIONS.VOTE_MODE, voteMode.name()) + .where(SuggestionsTable.SUGGESTIONS.SUGGESTIONNUMBER.eq(suggestion.getNumber())) + .execute(); } + } catch (ErrorResponseException ignored) { + } - if (sent) { - core.logger.info("Suggestions Migration has finished."); - } - core.getSuggestionManager().loading = false; - } catch (SQLException e) { - throw new UnCheckedSQLException(e); } + if (sent) { + core.logger.info("Suggestions Migration has finished."); + } + core.getSuggestionManager().loading = false; } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/listeners/SuggestionListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/listeners/SuggestionListener.java index 8f4c9dff..cefe9250 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/listeners/SuggestionListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/suggestions/listeners/SuggestionListener.java @@ -32,7 +32,6 @@ import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; -import tk.bluetree242.discordsrvutils.exceptions.UnCheckedSQLException; import tk.bluetree242.discordsrvutils.jooq.tables.SuggestionsVotesTable; import tk.bluetree242.discordsrvutils.systems.suggestions.Suggestion; import tk.bluetree242.discordsrvutils.systems.suggestions.SuggestionManager; @@ -40,9 +39,6 @@ import tk.bluetree242.discordsrvutils.utils.Emoji; import tk.bluetree242.discordsrvutils.utils.Utils; -import java.sql.Connection; -import java.sql.SQLException; - @RequiredArgsConstructor public class SuggestionListener extends ListenerAdapter { @@ -53,49 +49,39 @@ public void onGuildMessageReactionAdd(@NotNull GuildMessageReactionAddEvent e) { if (core.getMainConfig().bungee_mode()) return; if (e.getUser().isBot()) return; core.getAsyncManager().executeAsync(() -> { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - Suggestion suggestion = core.getSuggestionManager().getSuggestionByMessageID(e.getMessageIdLong(), jooq); - if (suggestion == null) return; - Message msg = e.getChannel().retrieveMessageById(e.getMessageIdLong()).complete(); - Emoji yes = Utils.getEmoji(core.getSuggestionsConfig().yes_reaction(), new Emoji("✅")); - Emoji no = Utils.getEmoji(core.getSuggestionsConfig().no_reaction(), new Emoji("❌")); - if (core.getSuggestionManager().loading) { + Suggestion suggestion = core.getSuggestionManager().getSuggestionByMessageID(e.getMessageIdLong()); + if (suggestion == null) return; + Message msg = e.getChannel().retrieveMessageById(e.getMessageIdLong()).complete(); + Emoji yes = Utils.getEmoji(core.getSuggestionsConfig().yes_reaction(), new Emoji("✅")); + Emoji no = Utils.getEmoji(core.getSuggestionsConfig().no_reaction(), new Emoji("❌")); + if (core.getSuggestionManager().loading) { + e.getReaction().removeReaction(e.getUser()).queue(); + return; + } + if (!core.getSuggestionsConfig().allow_submitter_vote()) { + if (e.getUser().getIdLong() == suggestion.getSubmitter()) { e.getReaction().removeReaction(e.getUser()).queue(); return; } - if (!core.getSuggestionsConfig().allow_submitter_vote()) { - if (e.getUser().getIdLong() == suggestion.getSubmitter()) { - e.getReaction().removeReaction(e.getUser()).queue(); - return; - } - } + } - if (e.getReactionEmote().getName().equals(yes.getName())) { - msg.removeReaction(no.getNameInReaction(), e.getUser()).queue(); - } else if (e.getReactionEmote().getName().equals(no.getName())) { - msg.removeReaction(yes.getNameInReaction(), e.getUser()).queue(); - } - msg.editMessage(suggestion.getCurrentMsg()).queue(); - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex); + if (e.getReactionEmote().getName().equals(yes.getName())) { + msg.removeReaction(no.getNameInReaction(), e.getUser()).queue(); + } else if (e.getReactionEmote().getName().equals(no.getName())) { + msg.removeReaction(yes.getNameInReaction(), e.getUser()).queue(); } + msg.editMessage(suggestion.getCurrentMsg()).queue(); }); } public void onGuildMessageReactionRemove(@NotNull GuildMessageReactionRemoveEvent e) { if (core.getMainConfig().bungee_mode()) return; core.getAsyncManager().executeAsync(() -> { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - Suggestion suggestion = core.getSuggestionManager().getSuggestionByMessageID(e.getMessageIdLong(), jooq); - if (suggestion == null) return; - Message msg = suggestion.getMessage(); - if (!msg.isEdited() || (System.currentTimeMillis() - msg.getTimeEdited().toEpochSecond()) > 1000) { - msg.editMessage(suggestion.getCurrentMsg()).queue(); - } - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex); + Suggestion suggestion = core.getSuggestionManager().getSuggestionByMessageID(e.getMessageIdLong()); + if (suggestion == null) return; + Message msg = suggestion.getMessage(); + if (!msg.isEdited() || (System.currentTimeMillis() - msg.getTimeEdited().toEpochSecond()) > 1000) { + msg.editMessage(suggestion.getCurrentMsg()).queue(); } }); } @@ -105,57 +91,53 @@ public void onButtonClick(@NotNull ButtonClickEvent e) { if (core.getMainConfig().bungee_mode()) return; if (e.getUser().isBot()) return; core.getAsyncManager().executeAsync(() -> { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - Suggestion suggestion = core.getSuggestionManager().getSuggestionByMessageID(e.getMessageIdLong(), jooq); - if (suggestion == null) return; - Message msg = e.getChannel().retrieveMessageById(e.getMessageIdLong()).complete(); - Emoji yes = Utils.getEmoji(core.getSuggestionsConfig().yes_reaction(), new Emoji("✅")); - Emoji no = Utils.getEmoji(core.getSuggestionsConfig().no_reaction(), new Emoji("❌")); - if (core.getSuggestionManager().loading) { + DSLContext jooq = core.getDatabaseManager().jooq(); + Suggestion suggestion = core.getSuggestionManager().getSuggestionByMessageID(e.getMessageIdLong()); + if (suggestion == null) return; + Message msg = e.getChannel().retrieveMessageById(e.getMessageIdLong()).complete(); + Emoji yes = Utils.getEmoji(core.getSuggestionsConfig().yes_reaction(), new Emoji("✅")); + Emoji no = Utils.getEmoji(core.getSuggestionsConfig().no_reaction(), new Emoji("❌")); + if (core.getSuggestionManager().loading) { + return; + } + if (!core.getSuggestionsConfig().allow_submitter_vote()) { + if (e.getUser().getIdLong() == suggestion.getSubmitter()) { + e.deferReply(true).setContent("You may not vote your own suggestion").queue(); return; } - if (!core.getSuggestionsConfig().allow_submitter_vote()) { - if (e.getUser().getIdLong() == suggestion.getSubmitter()) { - e.deferReply(true).setContent("You may not vote your own suggestion").queue(); - return; - } - } - jooq.deleteFrom(SuggestionsVotesTable.SUGGESTIONS_VOTES) - .where(SuggestionsVotesTable.SUGGESTIONS_VOTES.USERID.eq(e.getUser().getIdLong())) - .and(SuggestionsVotesTable.SUGGESTIONS_VOTES.SUGGESTIONNUMBER.eq((long) suggestion.getNumber())) - .execute(); - switch (e.getButton().getId()) { - case "yes": - jooq.insertInto(SuggestionsVotesTable.SUGGESTIONS_VOTES) - .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.USERID, e.getUser().getIdLong()) - .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.SUGGESTIONNUMBER, (long) suggestion.getNumber()) - .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.AGREE, "true") - .execute(); - suggestion.getVotes().removeIf(vote -> vote.getId() == e.getUser().getIdLong()); - suggestion.getVotes().add(new SuggestionVote(e.getUser().getIdLong(), suggestion.getNumber(), true)); - e.deferEdit().queue(); - break; - case "no": - jooq.insertInto(SuggestionsVotesTable.SUGGESTIONS_VOTES) - .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.USERID, e.getUser().getIdLong()) - .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.SUGGESTIONNUMBER, (long) suggestion.getNumber()) - .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.AGREE, "false") - .execute(); - suggestion.getVotes().removeIf(vote -> vote.getId() == e.getUser().getIdLong()); - suggestion.getVotes().add(new SuggestionVote(e.getUser().getIdLong(), suggestion.getNumber(), false)); + } + jooq.deleteFrom(SuggestionsVotesTable.SUGGESTIONS_VOTES) + .where(SuggestionsVotesTable.SUGGESTIONS_VOTES.USERID.eq(e.getUser().getIdLong())) + .and(SuggestionsVotesTable.SUGGESTIONS_VOTES.SUGGESTIONNUMBER.eq((long) suggestion.getNumber())) + .execute(); + switch (e.getButton().getId()) { + case "yes": + jooq.insertInto(SuggestionsVotesTable.SUGGESTIONS_VOTES) + .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.USERID, e.getUser().getIdLong()) + .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.SUGGESTIONNUMBER, (long) suggestion.getNumber()) + .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.AGREE, "true") + .execute(); + suggestion.getVotes().removeIf(vote -> vote.getId() == e.getUser().getIdLong()); + suggestion.getVotes().add(new SuggestionVote(e.getUser().getIdLong(), suggestion.getNumber(), true)); + e.deferEdit().queue(); + break; + case "no": + jooq.insertInto(SuggestionsVotesTable.SUGGESTIONS_VOTES) + .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.USERID, e.getUser().getIdLong()) + .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.SUGGESTIONNUMBER, (long) suggestion.getNumber()) + .set(SuggestionsVotesTable.SUGGESTIONS_VOTES.AGREE, "false") + .execute(); + suggestion.getVotes().removeIf(vote -> vote.getId() == e.getUser().getIdLong()); + suggestion.getVotes().add(new SuggestionVote(e.getUser().getIdLong(), suggestion.getNumber(), false)); - e.deferEdit().queue(); - break; - case "reset": - suggestion.getVotes().removeIf(vote -> vote.getId() == e.getUser().getIdLong()); - e.deferEdit().queue(); - break; - } - msg.editMessage(suggestion.getCurrentMsg()).setActionRows(SuggestionManager.getActionRow(suggestion.getYesCount(), suggestion.getNoCount())).queue(); - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex); + e.deferEdit().queue(); + break; + case "reset": + suggestion.getVotes().removeIf(vote -> vote.getId() == e.getUser().getIdLong()); + e.deferEdit().queue(); + break; } + msg.editMessage(suggestion.getCurrentMsg()).setActionRows(SuggestionManager.getActionRow(suggestion.getYesCount(), suggestion.getNoCount())).queue(); }); } @@ -167,12 +149,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent e) { if (e.getChannel().getIdLong() == core.getSuggestionsConfig().suggestions_channel()) { if (core.getSuggestionsConfig().set_suggestion_from_channel()) { e.getMessage().delete().queue(); - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - core.getSuggestionManager().makeSuggestion(e.getMessage().getContentDisplay(), e.getMessage().getAuthor().getIdLong(), jooq); - } catch (SQLException ex) { - throw new UnCheckedSQLException(ex); - } + core.getSuggestionManager().makeSuggestion(e.getMessage().getContentDisplay(), e.getMessage().getAuthor().getIdLong()); } } }); diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/Panel.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/Panel.java index 3eb4cf36..bd1c3954 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/Panel.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/Panel.java @@ -126,7 +126,8 @@ public void delete(DSLContext conn) { getTickets(conn).forEach(Ticket::delete); } - public Set getTicketsForUser(User user, boolean includeClosed, DSLContext conn) { + public Set getTicketsForUser(User user, boolean includeClosed) { + DSLContext conn = core.getDatabaseManager().jooq(); Set result = new HashSet<>(); List records = conn .selectFrom(TicketsTable.TICKETS) @@ -144,7 +145,8 @@ public Set getTicketsForUser(User user, boolean includeClosed, DSLContex return result; } - public @Nullable Ticket openTicket(User user, DSLContext conn) { + public @Nullable Ticket openTicket(User user) { + DSLContext conn = core.getDatabaseManager().jooq(); if (user.isBot()) return null; TicketsRecord check = conn .selectFrom(TicketsTable.TICKETS) diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/Ticket.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/Ticket.java index 3d6417dd..217261c7 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/Ticket.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/Ticket.java @@ -30,6 +30,7 @@ import tk.bluetree242.discordsrvutils.jooq.tables.TicketsTable; import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObject; import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObjectList; +import tk.bluetree242.discordsrvutils.utils.Utils; public class Ticket { private final DiscordSRVUtils core; @@ -75,7 +76,8 @@ public long getMessageID() { } - public void close(User userWhoClosed, DSLContext conn) { + public void close(User userWhoClosed) { + DSLContext conn = core.getDatabaseManager().jooq(); if (closed) return; //set it without the message id conn.update(TicketsTable.TICKETS) @@ -83,9 +85,9 @@ public void close(User userWhoClosed, DSLContext conn) { .where(TicketsTable.TICKETS.CHANNEL.eq(channelID)) .execute(); User user = core.getJDA().retrieveUserById(userID).complete(); - Member member = core.getPlatform().getDiscordSRV().getMainGuild().getMember(user); + Member member = Utils.retrieveMember(core.getDiscordSRV().getMainGuild(), userID); core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(channelID).getManager().setParent(core.getPlatform().getDiscordSRV().getMainGuild().getCategoryById(panel.getClosedCategory())).setName("ticket-" + user.getName()).queue(); - PermissionOverride override = core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(channelID).getPermissionOverride(member); + PermissionOverride override = member == null ? null : core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(channelID).getPermissionOverride(member); if (override != null) { override.getManager().deny(Permission.VIEW_CHANNEL).deny(Permission.MESSAGE_WRITE).queue(); } @@ -108,16 +110,17 @@ public void close(User userWhoClosed, DSLContext conn) { .execute(); } - public void reopen(User userWhoOpened, DSLContext conn) { + public void reopen(User userWhoOpened) { + DSLContext conn = core.getDatabaseManager().jooq(); if (!closed) return; conn.update(TicketsTable.TICKETS) .set(TicketsTable.TICKETS.CLOSED, "false") .where(TicketsTable.TICKETS.CHANNEL.eq(channelID)) .execute(); User user = core.getJDA().retrieveUserById(userID).complete(); - Member member = core.getPlatform().getDiscordSRV().getMainGuild().getMember(user); + Member member = Utils.retrieveMember(core.getDiscordSRV().getMainGuild(), userID); core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(channelID).getManager().setParent(core.getPlatform().getDiscordSRV().getMainGuild().getCategoryById(panel.getOpenedCategory())).setName("ticket-" + user.getName()).queue(); - PermissionOverride override = core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(channelID).getPermissionOverride(member); + PermissionOverride override = member == null ? null : core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(channelID).getPermissionOverride(member); if (override != null) { override.getManager().setAllow(Permission.VIEW_CHANNEL, Permission.MESSAGE_WRITE).queue(); } else { diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/TicketManager.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/TicketManager.java index 959e4e0a..6df657c9 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/TicketManager.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/TicketManager.java @@ -31,7 +31,6 @@ import lombok.RequiredArgsConstructor; import org.jooq.DSLContext; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; -import tk.bluetree242.discordsrvutils.exceptions.UnCheckedSQLException; import tk.bluetree242.discordsrvutils.jooq.tables.PanelAllowedRolesTable; import tk.bluetree242.discordsrvutils.jooq.tables.TicketPanelsTable; import tk.bluetree242.discordsrvutils.jooq.tables.TicketsTable; @@ -40,8 +39,6 @@ import tk.bluetree242.discordsrvutils.jooq.tables.records.TicketsRecord; import tk.bluetree242.discordsrvutils.utils.Utils; -import java.sql.Connection; -import java.sql.SQLException; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -51,7 +48,8 @@ public class TicketManager { private final DiscordSRVUtils core; - public Panel getPanelById(String id, DSLContext conn) { + public Panel getPanelById(String id) { + DSLContext conn = core.getDatabaseManager().jooq(); TicketPanelsRecord record = conn .selectFrom(TicketPanelsTable.TICKET_PANELS) .where(TicketPanelsTable.TICKET_PANELS.ID.eq(id)) @@ -90,7 +88,8 @@ public Panel getPanel(TicketPanelsRecord r) { allowedRoles); } - public Panel getPanelByMessageId(long messageId, DSLContext conn) { + public Panel getPanelByMessageId(long messageId) { + DSLContext conn = core.getDatabaseManager().jooq(); TicketPanelsRecord record = conn .selectFrom(TicketPanelsTable.TICKET_PANELS) .where(TicketPanelsTable.TICKET_PANELS.MESSAGEID.eq(messageId)) @@ -99,7 +98,8 @@ public Panel getPanelByMessageId(long messageId, DSLContext conn) { return getPanel(record); } - public Ticket getTicketByMessageId(long messageId, DSLContext conn) { + public Ticket getTicketByMessageId(long messageId) { + DSLContext conn = core.getDatabaseManager().jooq(); TicketsRecord record = conn .selectFrom(TicketsTable.TICKETS) .where(TicketsTable.TICKETS.MESSAGEID.eq(messageId)) @@ -108,7 +108,8 @@ public Ticket getTicketByMessageId(long messageId, DSLContext conn) { return getTicket(record); } - public Ticket getTicketByChannel(long channelId, DSLContext conn) { + public Ticket getTicketByChannel(long channelId) { + DSLContext conn = core.getDatabaseManager().jooq(); TicketsRecord record = conn .selectFrom(TicketsTable.TICKETS) .where(TicketsTable.TICKETS.CHANNEL.eq(channelId)) @@ -120,7 +121,7 @@ public Ticket getTicketByChannel(long channelId, DSLContext conn) { protected Ticket getTicket(TicketsRecord r, Panel panel) { if (panel == null) { DSLContext conn = r.configuration().dsl(); - panel = getPanelById(r.getId(), conn); + panel = getPanelById(r.getId()); } return new Ticket(core, r.getId(), @@ -136,40 +137,36 @@ protected Ticket getTicket(TicketsRecord r) { } public void fixTickets() { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - List tickets = jooq - .selectFrom(TicketsTable.TICKETS) - .fetch(); - for (TicketsRecord record : tickets) { - TextChannel channel = core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(record.getChannel()); - if (channel == null) { - jooq.deleteFrom(TicketsTable.TICKETS) - .where(TicketsTable.TICKETS.CHANNEL.eq(record.getChannel())) - .execute(); - } + DSLContext jooq = core.getDatabaseManager().jooq(); + List tickets = jooq + .selectFrom(TicketsTable.TICKETS) + .fetch(); + for (TicketsRecord record : tickets) { + TextChannel channel = core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(record.getChannel()); + if (channel == null) { + jooq.deleteFrom(TicketsTable.TICKETS) + .where(TicketsTable.TICKETS.CHANNEL.eq(record.getChannel())) + .execute(); } + } - //work with panels - List panels = jooq - .selectFrom(TicketPanelsTable.TICKET_PANELS) - .fetch(); - for (TicketPanelsRecord record : panels) { - Panel panel = getPanel(record); - try { - Message msg = core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(panel.getChannelId()).retrieveMessageById(panel.getMessageId()).complete(); - if (msg.getButtons().isEmpty()) { - msg.clearReactions().queue(); - msg.editMessage(msg).setActionRow(Button.secondary("open_ticket", Emoji.fromUnicode("\uD83C\uDFAB")).withLabel(core.getTicketsConfig().open_ticket_button())).queue(); - } else if (!msg.getButtons().get(0).getLabel().equals(core.getTicketsConfig().open_ticket_button())) { - msg.editMessage(msg).setActionRows(ActionRow.of(Button.secondary("open_ticket", Emoji.fromUnicode("\uD83C\uDFAB")).withLabel(core.getTicketsConfig().open_ticket_button()))).queue(); - } - } catch (ErrorResponseException ex) { - panel.getEditor().apply(jooq); + //work with panels + List panels = jooq + .selectFrom(TicketPanelsTable.TICKET_PANELS) + .fetch(); + for (TicketPanelsRecord record : panels) { + Panel panel = getPanel(record); + try { + Message msg = core.getPlatform().getDiscordSRV().getMainGuild().getTextChannelById(panel.getChannelId()).retrieveMessageById(panel.getMessageId()).complete(); + if (msg.getButtons().isEmpty()) { + msg.clearReactions().queue(); + msg.editMessage(msg).setActionRow(Button.secondary("open_ticket", Emoji.fromUnicode("\uD83C\uDFAB")).withLabel(core.getTicketsConfig().open_ticket_button())).queue(); + } else if (!msg.getButtons().get(0).getLabel().equals(core.getTicketsConfig().open_ticket_button())) { + msg.editMessage(msg).setActionRows(ActionRow.of(Button.secondary("open_ticket", Emoji.fromUnicode("\uD83C\uDFAB")).withLabel(core.getTicketsConfig().open_ticket_button()))).queue(); } + } catch (ErrorResponseException ex) { + panel.getEditor().apply(jooq); } - } catch (SQLException e) { - throw new UnCheckedSQLException(e); } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/PanelOpenListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/PanelOpenListener.java index 77f0ce1a..20387b49 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/PanelOpenListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/PanelOpenListener.java @@ -28,16 +28,12 @@ import github.scarsz.discordsrv.dependencies.jda.api.requests.restaction.interactions.ReplyAction; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; -import org.jooq.DSLContext; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObject; import tk.bluetree242.discordsrvutils.placeholder.PlaceholdObjectList; import tk.bluetree242.discordsrvutils.systems.tickets.Panel; import tk.bluetree242.discordsrvutils.systems.tickets.Ticket; -import java.sql.Connection; -import java.sql.SQLException; - @RequiredArgsConstructor public class PanelOpenListener extends ListenerAdapter { private final DiscordSRVUtils core; @@ -45,27 +41,22 @@ public class PanelOpenListener extends ListenerAdapter { public void onButtonClick(@NotNull ButtonClickEvent e) { if (core.getMainConfig().bungee_mode()) return; core.getAsyncManager().executeAsync(() -> { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - Panel panel = core.getTicketManager().getPanelByMessageId(e.getMessageIdLong(), jooq); - if (panel != null) { - if (e.getUser().isBot()) return; - if (e.getMember().getRoles().contains(core.getPlatform().getDiscordSRV().getMainGuild().getRoleById(core.getTicketsConfig().ticket_banned_role()))) { - e.deferReply(true).setContent("You are Ticket Muted").queue(); - return; - } - Ticket t = panel.openTicket(e.getUser(), jooq); - ReplyAction action = e.deferReply(true); - PlaceholdObjectList holders = PlaceholdObjectList.ofArray(core, - new PlaceholdObject(core, core.getJDA().getTextChannelById(t.getChannelID()), "channel"), - new PlaceholdObject(core, e.getUser(), "user"), - new PlaceholdObject(core, t, "ticket"), - new PlaceholdObject(core, panel, "panel") - ); - core.getMessageManager().messageToReplyAction(action, core.getMessageManager().getMessage(core.getTicketsConfig().ticket_open_ephemeral_msg(), holders, null).build()).queue(); + Panel panel = core.getTicketManager().getPanelByMessageId(e.getMessageIdLong()); + if (panel != null) { + if (e.getUser().isBot()) return; + if (e.getMember().getRoles().contains(core.getPlatform().getDiscordSRV().getMainGuild().getRoleById(core.getTicketsConfig().ticket_banned_role()))) { + e.deferReply(true).setContent("You are Ticket Muted").queue(); + return; } - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex, e.getChannel()); + Ticket t = panel.openTicket(e.getUser()); + ReplyAction action = e.deferReply(true); + PlaceholdObjectList holders = PlaceholdObjectList.ofArray(core, + new PlaceholdObject(core, core.getJDA().getTextChannelById(t.getChannelID()), "channel"), + new PlaceholdObject(core, e.getUser(), "user"), + new PlaceholdObject(core, t, "ticket"), + new PlaceholdObject(core, panel, "panel") + ); + core.getMessageManager().messageToReplyAction(action, core.getMessageManager().getMessage(core.getTicketsConfig().ticket_open_ephemeral_msg(), holders, null).build()).queue(); } }); } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/TicketCloseListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/TicketCloseListener.java index 80d7fb0c..56b0e066 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/TicketCloseListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/TicketCloseListener.java @@ -27,13 +27,9 @@ import github.scarsz.discordsrv.dependencies.jda.api.hooks.ListenerAdapter; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; -import org.jooq.DSLContext; import tk.bluetree242.discordsrvutils.DiscordSRVUtils; import tk.bluetree242.discordsrvutils.systems.tickets.Ticket; -import java.sql.Connection; -import java.sql.SQLException; - @RequiredArgsConstructor public class TicketCloseListener extends ListenerAdapter { @@ -42,30 +38,25 @@ public class TicketCloseListener extends ListenerAdapter { public void onButtonClick(@NotNull ButtonClickEvent e) { if (core.getMainConfig().bungee_mode()) return; core.getAsyncManager().executeAsync(() -> { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - Ticket ticket = core.getTicketManager().getTicketByMessageId(e.getMessageIdLong(), jooq); - if (ticket != null) { - if (e.getUser().isBot()) return; - if (e.getButton().getId().equals("close_ticket")) { - e.deferEdit().queue(); - if (!ticket.isClosed()) - ticket.close(e.getUser(), jooq); - } else if (e.getButton().getId().equals("delete_ticket")) { - e.deferEdit().queue(); - if (ticket.isClosed()) { - ticket.delete(); - } + Ticket ticket = core.getTicketManager().getTicketByMessageId(e.getMessageIdLong()); + if (ticket != null) { + if (e.getUser().isBot()) return; + if (e.getButton().getId().equals("close_ticket")) { + e.deferEdit().queue(); + if (!ticket.isClosed()) + ticket.close(e.getUser()); + } else if (e.getButton().getId().equals("delete_ticket")) { + e.deferEdit().queue(); + if (ticket.isClosed()) { + ticket.delete(); } - if (e.getButton().getId().equals("reopen_ticket")) { - e.deferEdit().queue(); - if (ticket.isClosed()) { - ticket.reopen(e.getUser(), jooq); - } + } + if (e.getButton().getId().equals("reopen_ticket")) { + e.deferEdit().queue(); + if (ticket.isClosed()) { + ticket.reopen(e.getUser()); } } - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex, e.getChannel()); } }); } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/TicketDeleteListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/TicketDeleteListener.java index 5c0bd584..5533d87e 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/TicketDeleteListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/systems/tickets/listeners/TicketDeleteListener.java @@ -31,9 +31,6 @@ import tk.bluetree242.discordsrvutils.DiscordSRVUtils; import tk.bluetree242.discordsrvutils.jooq.tables.TicketsTable; -import java.sql.Connection; -import java.sql.SQLException; - @RequiredArgsConstructor public class TicketDeleteListener extends ListenerAdapter { private final DiscordSRVUtils core; @@ -41,14 +38,10 @@ public class TicketDeleteListener extends ListenerAdapter { public void onTextChannelDelete(@NotNull TextChannelDeleteEvent e) { if (core.getMainConfig().bungee_mode()) return; core.getAsyncManager().executeAsync(() -> { - try (Connection conn = core.getDatabaseManager().getConnection()) { - DSLContext jooq = core.getDatabaseManager().jooq(conn); - jooq.deleteFrom(TicketsTable.TICKETS) - .where(TicketsTable.TICKETS.CHANNEL.eq(e.getChannel().getIdLong())) - .execute(); - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex, e.getChannel()); - } + DSLContext jooq = core.getDatabaseManager().jooq(); + jooq.deleteFrom(TicketsTable.TICKETS) + .where(TicketsTable.TICKETS.CHANNEL.eq(e.getChannel().getIdLong())) + .execute(); }); } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/utils/Utils.java b/core/src/main/java/tk/bluetree242/discordsrvutils/utils/Utils.java index d659770f..ab313158 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/utils/Utils.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/utils/Utils.java @@ -38,6 +38,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; +import java.security.SecureRandom; import java.util.Base64; import java.util.List; import java.util.concurrent.TimeUnit; @@ -235,4 +236,8 @@ public static Member retrieveMember(Guild guild, long id) { return null; } } + + public static int nextInt(int min, int max) { + return new SecureRandom().nextInt(max - min) + min; + } } diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/waiters/listeners/CreatePanelListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/waiters/listeners/CreatePanelListener.java index f25eddbb..fff30234 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/waiters/listeners/CreatePanelListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/waiters/listeners/CreatePanelListener.java @@ -37,8 +37,6 @@ import tk.bluetree242.discordsrvutils.waiters.CreatePanelWaiter; import java.awt.*; -import java.sql.Connection; -import java.sql.SQLException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -142,18 +140,12 @@ public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent e) { } } Set rls = new HashSet<>(); - roles.forEach(r -> { - rls.add(r.getIdLong()); - }); + roles.forEach(r -> rls.add(r.getIdLong())); waiter.getBuilder().setAllowedRoles(rls); } waiter.expire(false); - try (Connection conn = core.getDatabaseManager().getConnection()) { - Panel panel = waiter.getBuilder().create(core.getDatabaseManager().jooq(conn)); - e.getChannel().sendMessageEmbeds(Embed.success("Panel created with id " + panel.getId())).queue(); - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex, e.getChannel()); - } + Panel panel = waiter.getBuilder().create(core.getDatabaseManager().jooq()); + e.getChannel().sendMessageEmbeds(Embed.success("Panel created with id " + panel.getId())).queue(); } } }); diff --git a/core/src/main/java/tk/bluetree242/discordsrvutils/waiters/listeners/EditPanelListener.java b/core/src/main/java/tk/bluetree242/discordsrvutils/waiters/listeners/EditPanelListener.java index ce4273d3..74450b9f 100644 --- a/core/src/main/java/tk/bluetree242/discordsrvutils/waiters/listeners/EditPanelListener.java +++ b/core/src/main/java/tk/bluetree242/discordsrvutils/waiters/listeners/EditPanelListener.java @@ -38,8 +38,6 @@ import tk.bluetree242.discordsrvutils.waiters.EditPanelWaiter; import java.awt.*; -import java.sql.Connection; -import java.sql.SQLException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -158,15 +156,11 @@ public void onButtonClick(@NotNull ButtonClickEvent e) { if (name.equals("apply")) { e.deferEdit().queue(); waiter.expire(false); - try (Connection conn = core.getDatabaseManager().getConnection()) { - Panel panel = waiter.getEditor().apply(core.getDatabaseManager().jooq(conn)); - if (panel == null) { - e.getChannel().sendMessageEmbeds(Embed.error("Something unexpected happened, please contact the devs")).queue(); - } else { - e.getChannel().sendMessageEmbeds(Embed.success("Successfully applied changes")).queue(); - } - } catch (SQLException ex) { - core.getErrorHandler().defaultHandle(ex, e.getChannel()); + Panel panel = waiter.getEditor().apply(core.getDatabaseManager().jooq()); + if (panel == null) { + e.getChannel().sendMessageEmbeds(Embed.error("Something unexpected happened, please contact the devs")).queue(); + } else { + e.getChannel().sendMessageEmbeds(Embed.success("Successfully applied changes")).queue(); } } else if (name.equals("cancel")) { e.deferEdit().queue(); diff --git a/core/src/main/resources/messages/level.json b/core/src/main/resources/messages/level.json index f1d7e769..a122acaf 100644 --- a/core/src/main/resources/messages/level.json +++ b/core/src/main/resources/messages/level.json @@ -4,7 +4,7 @@ "url": "https://minotar.net/avatar/[stats.name]" }, "color": "cyan", - "description": "**Level:** [stats.level]\n**XP:** [stats.xp]\n**Rank:** #[stats.rank]", + "description": "**Level:** [stats.level]\n**XP:** [stats.xp] / [stats.totalXpRequired] ([stats.xpPercentage]%)\n**Rank:** #[stats.rank]", "title": "Level for [stats.name]" } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 75eb329a..e4f8f949 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,5 +21,5 @@ # group=tk.bluetree242 name=DiscordSRVUtils -version=1.2.10 +version=1.2.11 description=Utilities for your Discord Server!