diff --git a/pom.xml b/pom.xml index ec4c2ec..969c5cb 100644 --- a/pom.xml +++ b/pom.xml @@ -16,40 +16,60 @@ + net.dv8tion JDA 5.0.0-beta.19 + io.github.lycoon clash-api - 5.1.4 + 5.1.5 + com.google.code.gson gson 2.9.0 + - com.zaxxer - HikariCP - 5.0.1 + org.projectlombok + lombok + 1.18.30 + provided + - org.mariadb.jdbc - mariadb-java-client - 3.0.6 + org.hibernate.orm + hibernate-core + 6.4.2.Final - ch.qos.logback - logback-classic - 1.4.14 + org.hibernate + hibernate-hikaricp + 6.4.2.Final + pom + + + + + org.slf4j + slf4j-api + 2.0.11 + + + + org.slf4j + slf4j-simple + 2.0.11 diff --git a/src/main/java/com/lycoon/clashbot/commands/CommandConfig.java b/src/main/java/com/lycoon/clashbot/commands/CommandConfig.java index e96d1b3..62ddcca 100644 --- a/src/main/java/com/lycoon/clashbot/commands/CommandConfig.java +++ b/src/main/java/com/lycoon/clashbot/commands/CommandConfig.java @@ -4,10 +4,12 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.interactions.commands.OptionType; -import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import net.dv8tion.jda.api.interactions.commands.build.Commands; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; -public class CommandConfig { +public class CommandConfig +{ private final JDA jda; private final Guild guild; private final String CLASHBOT_GUILD = "817384284507209768"; @@ -22,23 +24,23 @@ public void createCommands() ClashBotMain.LOGGER.info("Creating commands..."); // Miscellaneous - CommandData infoCommand = new CommandData("info", "Shows bot information"); + SlashCommandData infoCommand = Commands.slash("info", "Shows bot information"); jda.upsertCommand(infoCommand).complete(); - CommandData inviteCommand = new CommandData("invite", "Shows bot's invite link"); + SlashCommandData inviteCommand = Commands.slash("invite", "Shows bot's invite link"); jda.upsertCommand(inviteCommand).complete(); - CommandData langCommand = new CommandData("lang", "Shows your current language"); + SlashCommandData langCommand = Commands.slash("lang", "Shows your current language"); jda.upsertCommand(langCommand).complete(); - CommandData helpCommand = new CommandData("help", "Shows commands and their usage"); + SlashCommandData helpCommand = Commands.slash("help", "Shows commands and their usage"); jda.upsertCommand(helpCommand).complete(); // Settings - CommandData clearCommand = new CommandData("clear", "Deletes all the data the bot database has about you"); + SlashCommandData clearCommand = Commands.slash("clear", "Deletes all the data the bot database has about you"); jda.upsertCommand(clearCommand).complete(); - CommandData setCommand = new CommandData("set", "Shows clan profile"); + SlashCommandData setCommand = Commands.slash("set", "Shows clan profile"); SubcommandData setClanSubcommand = new SubcommandData("clan", "Sets default clan tag"); setClanSubcommand.addOption(OptionType.STRING, "clan_tag", "Clan tag from the profile starting with a #", true); @@ -52,27 +54,27 @@ public void createCommands() jda.upsertCommand(setCommand).complete(); // Clan - CommandData clanCommand = new CommandData("clan", "Shows clan profile"); + SlashCommandData clanCommand = Commands.slash("clan", "Shows clan profile"); clanCommand.addOption(OptionType.STRING, "clan_tag", "Clan tag from the profile starting with a #", false); jda.upsertCommand(clanCommand).complete(); - CommandData warCommand = new CommandData("war", "Shows current war occurring in the clan"); + SlashCommandData warCommand = Commands.slash("war", "Shows current war occurring in the clan"); warCommand.addOption(OptionType.INTEGER, "page", "Page number you want to access", true); warCommand.addOption(OptionType.STRING, "clan_tag", "Clan tag from the profile starting with a #", false); jda.upsertCommand(warCommand).complete(); - CommandData warlogCommand = new CommandData("warlog", "Shows clan warlog"); + SlashCommandData warlogCommand = Commands.slash("warlog", "Shows clan warlog"); warlogCommand.addOption(OptionType.INTEGER, "page", "Page number you want to access", true); warlogCommand.addOption(OptionType.STRING, "clan_tag", "Clan tag from the profile starting with a #", false); jda.upsertCommand(warlogCommand).complete(); - CommandData warleagueCommand = new CommandData("warleague", "Shows current warleague occurring in the clan"); + SlashCommandData warleagueCommand = Commands.slash("warleague", "Shows current warleague occurring in the clan"); warleagueCommand.addOption(OptionType.INTEGER, "page", "Page number you want to access", true); warleagueCommand.addOption(OptionType.STRING, "clan_tag", "Clan tag from the profile starting with a #", false); jda.upsertCommand(warleagueCommand).complete(); // Player - CommandData playerCommand = new CommandData("player", "Shows player profile"); + SlashCommandData playerCommand = Commands.slash("player", "Shows player profile"); playerCommand.addOption(OptionType.STRING, "player_tag", "Player tag from the profile starting with a #", false); jda.upsertCommand(playerCommand).complete(); diff --git a/src/main/java/com/lycoon/clashbot/commands/Command.java b/src/main/java/com/lycoon/clashbot/commands/CommandData.java similarity index 84% rename from src/main/java/com/lycoon/clashbot/commands/Command.java rename to src/main/java/com/lycoon/clashbot/commands/CommandData.java index 563e323..bac93a0 100644 --- a/src/main/java/com/lycoon/clashbot/commands/Command.java +++ b/src/main/java/com/lycoon/clashbot/commands/CommandData.java @@ -1,60 +1,58 @@ -package com.lycoon.clashbot.commands; - -public enum Command -{ - INVITE(CommandCategory.MISC, "invite", "cmd.invite.desc"), - LANG(CommandCategory.MISC, "lang", "cmd.lang.desc"), - INFO(CommandCategory.MISC, "info", "cmd.info.desc"), - HELP(CommandCategory.MISC, "help", "cmd.help.desc"), - CLEAR(CommandCategory.SETTINGS, "clear", "cmd.clear.desc"), - SET_PLAYER(CommandCategory.SETTINGS, "set", "cmd.setplayer.desc", "player "), - SET_CLAN(CommandCategory.SETTINGS, "set", "cmd.setclan.desc", "clan "), - SET_LANG(CommandCategory.SETTINGS, "set", "cmd.setlang.desc", "lang "), - CLAN(CommandCategory.CLAN, "clan", "cmd.clan.desc", "[clanTag]"), - WARLEAGUE(CommandCategory.CLAN, "warleague", "cmd.warleague.round.desc", " [clanTag]"), - //WARLEAGUE_ALL (CommandCategory.CLAN, "warleague", "cmd.warleague.all.desc", "all [clanTag]"), - //WARLEAGUE_CLAN (CommandCategory.CLAN, "warleague", "cmd.warleague.clan.desc", "[clanTag]"), - WARLOG(CommandCategory.CLAN, "warlog", "cmd.warlog.desc", " [clanTag]"), - WAR(CommandCategory.CLAN, "war", "cmd.war.desc", " [clanTag]"), - PLAYER(CommandCategory.PLAYER, "player", "cmd.player.desc", "[playerTag]"); - - final CommandCategory category; - final String name, desc; - String usage; - - Command(CommandCategory category, String name, String desc, String usage) - { - this.category = category; - this.name = name; - this.desc = desc; - this.usage = usage; - } - - Command(CommandCategory category, String name, String desc) - { - this.category = category; - this.name = name; - this.desc = desc; - } - - @Override - public String toString() - { - return name; - } - - public String getDescription() - { - return desc; - } - - public CommandCategory getCategory() - { - return category; - } - - public String formatCommand() - { - return "/" + name + (usage == null ? "" : " " + usage); - } -} +package com.lycoon.clashbot.commands; + +public enum CommandData +{ + INVITE(CommandCategory.MISC, "invite", "cmd.invite.desc"), + LANG(CommandCategory.MISC, "lang", "cmd.lang.desc"), + INFO(CommandCategory.MISC, "info", "cmd.info.desc"), + HELP(CommandCategory.MISC, "help", "cmd.help.desc"), + CLEAR(CommandCategory.SETTINGS, "clear", "cmd.clear.desc"), + SET_PLAYER(CommandCategory.SETTINGS, "set", "cmd.setplayer.desc", "player "), + SET_CLAN(CommandCategory.SETTINGS, "set", "cmd.setclan.desc", "clan "), + SET_LANG(CommandCategory.SETTINGS, "set", "cmd.setlang.desc", "lang "), + CLAN(CommandCategory.CLAN, "clan", "cmd.clan.desc", "[clanTag]"), + WARLEAGUE(CommandCategory.CLAN, "warleague", "cmd.warleague.round.desc", " [clanTag]"), + //WARLEAGUE_ALL (CommandCategory.CLAN, "warleague", "cmd.warleague.all.desc", "all [clanTag]"), + //WARLEAGUE_CLAN (CommandCategory.CLAN, "warleague", "cmd.warleague.clan.desc", "[clanTag]"), + WARLOG(CommandCategory.CLAN, "warlog", "cmd.warlog.desc", " [clanTag]"), + WAR(CommandCategory.CLAN, "war", "cmd.war.desc", " [clanTag]"), + PLAYER(CommandCategory.PLAYER, "player", "cmd.player.desc", "[playerTag]"); + + final CommandCategory category; + final String name, desc; + final String usage; + + CommandData(CommandCategory category, String name, String desc, String usage) + { + this.category = category; + this.name = name; + this.desc = desc; + this.usage = usage; + } + + CommandData(CommandCategory category, String name, String desc) + { + this(category, name, desc, null); + } + + @Override + public String toString() + { + return name; + } + + public String getDescription() + { + return desc; + } + + public CommandCategory getCategory() + { + return category; + } + + public String formatCommand() + { + return "/" + name + (usage == null ? "" : " " + usage); + } +} diff --git a/src/main/java/com/lycoon/clashbot/commands/clan/ClanCommand.java b/src/main/java/com/lycoon/clashbot/commands/clan/ClanCommand.java index c1bf056..044b893 100644 --- a/src/main/java/com/lycoon/clashbot/commands/clan/ClanCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/clan/ClanCommand.java @@ -3,7 +3,7 @@ import static com.lycoon.clashbot.utils.DrawUtils.*; import static com.lycoon.clashbot.utils.FileUtils.*; import static com.lycoon.clashbot.utils.ErrorUtils.*; -import static com.lycoon.clashbot.utils.DatabaseUtils.*; +import static com.lycoon.clashbot.utils.database.DatabaseUtils.*; import static com.lycoon.clashbot.utils.CoreUtils.*; import com.lycoon.clashapi.core.exceptions.ClashAPIException; @@ -11,13 +11,14 @@ import com.lycoon.clashapi.models.clan.Clan; import com.lycoon.clashapi.models.common.Label; import com.lycoon.clashapi.models.player.enums.Role; -import com.lycoon.clashbot.commands.Command; +import com.lycoon.clashbot.commands.CommandData; import com.lycoon.clashbot.core.ClashBotMain; import com.lycoon.clashbot.lang.LangUtils; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import java.awt.*; import java.awt.image.BufferedImage; +import java.io.IOException; import java.text.MessageFormat; import java.text.NumberFormat; import java.util.List; @@ -97,16 +98,16 @@ public static Clan getClan(SlashCommandInteractionEvent event, Locale lang, Stri if (tag == null) { sendError(event, i18n.getString("set.clan.error"), - MessageFormat.format(i18n.getString("cmd.general.tip"), Command.SET_CLAN.formatCommand())); + MessageFormat.format(i18n.getString("cmd.general.tip"), CommandData.SET_CLAN.formatCommand())); return null; } - try { - clan = ClashBotMain.clashAPI.getClan(tag); - } catch (ClashAPIException e) { + try { clan = ClashBotMain.clashAPI.getClan(tag); } + catch (ClashAPIException | IOException e) { sendExceptionError(event, i18n, e, tag, "clan"); return null; } + return clan; } diff --git a/src/main/java/com/lycoon/clashbot/commands/clan/WarCommand.java b/src/main/java/com/lycoon/clashbot/commands/clan/WarCommand.java index 3296818..16301b5 100644 --- a/src/main/java/com/lycoon/clashbot/commands/clan/WarCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/clan/WarCommand.java @@ -3,23 +3,19 @@ import static com.lycoon.clashbot.utils.DrawUtils.*; import static com.lycoon.clashbot.utils.FileUtils.*; import static com.lycoon.clashbot.utils.ErrorUtils.*; -import static com.lycoon.clashbot.utils.DatabaseUtils.*; +import static com.lycoon.clashbot.utils.database.DatabaseUtils.*; import static com.lycoon.clashbot.utils.CoreUtils.*; import static com.lycoon.clashbot.utils.GameUtils.*; -import com.lycoon.clashapi.core.ClashAPI; import com.lycoon.clashapi.core.exceptions.ClashAPIException; import com.lycoon.clashapi.models.war.WarAttack; import com.lycoon.clashapi.models.war.WarMember; import com.lycoon.clashapi.models.war.War; -import com.lycoon.clashapi.core.exception.ClashAPIException; import com.lycoon.clashapi.models.war.enums.WarState; -import com.lycoon.clashbot.commands.Command; +import com.lycoon.clashbot.commands.CommandData; import com.lycoon.clashbot.core.CacheComponents; import com.lycoon.clashbot.core.ClashBotMain; import com.lycoon.clashbot.lang.LangUtils; -import net.dv8tion.jda.api.entities.MessageChannel; -import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import java.awt.*; @@ -50,14 +46,16 @@ public class WarCommand { private final static Color notUsedAttackColor = new Color(0xfbbf70); private final static Color attackColor = new Color(0x4c493a); - static class SortMemberByOrder implements Comparator { + static class SortMemberByOrder implements Comparator + { @Override public int compare(WarMember a, WarMember b) { return a.getMapPosition() - b.getMapPosition(); } } - static class SortAttackByOrder implements Comparator { + static class SortAttackByOrder implements Comparator + { @Override public int compare(WarAttack a, WarAttack b) { return a.getOrder() - b.getOrder(); @@ -92,8 +90,7 @@ public static List getAttacksByOrder(List members) { List sortedAttacks = new ArrayList<>(); for (WarMember member : members) { List attacks = member.getAttacks(); - if (attacks != null) - sortedAttacks.addAll(attacks); + sortedAttacks.addAll(attacks); } sortedAttacks.sort(new SortAttackByOrder()); return sortedAttacks; @@ -127,7 +124,7 @@ public static int drawMemberResults(Graphics2D g2d, WarMember member, List { if (event.getOptions().isEmpty()) @@ -86,8 +83,9 @@ public static void drawRound(Graphics2D g2d, SlashCommandInteractionEvent event, int[] timeLeft; War firstWar = wars.get(0); - switch (firstWar.getState()) { - case "preparation" -> { + switch (firstWar.getState()) + { + case PREPARATION -> { timeLeft = getTimeLeft(firstWar.getStartTime()); g2d.drawImage(getImageFromFile("backgrounds/cwl/cwl-preparation.png"), 0, 0, null); drawSimpleCenteredString(g2d, @@ -96,7 +94,7 @@ public static void drawRound(Graphics2D g2d, SlashCommandInteractionEvent event, timeRect, 19f, Color.BLACK); drawCenteredString(g2d, stateLabel, font.deriveFont(24f), i18n.getString("war.preparation")); } - case "warEnded" -> { + case ENDED -> { timeLeft = getTimeLeft(firstWar.getEndTime()); g2d.drawImage(getImageFromFile("backgrounds/cwl/cwl-ended.png"), 0, 0, null); drawSimpleCenteredString(g2d, @@ -105,7 +103,7 @@ public static void drawRound(Graphics2D g2d, SlashCommandInteractionEvent event, timeRect, 19f, Color.BLACK); drawCenteredString(g2d, stateLabel, font.deriveFont(24f), i18n.getString("war.ended")); } - case "notInWar" -> { + case NOT_IN_WAR -> { sendError(event, i18n.getString("exception.warleague.notinwar")); return; } @@ -128,9 +126,9 @@ public static void drawRound(Graphics2D g2d, SlashCommandInteractionEvent event, WarClan clan1 = war.getClan(); WarClan clan2 = war.getOpponent(); - if (war.getState().equals("warEnded")) { - if (clan2.getStars() > clan1.getStars() || - (clan2.getStars() == clan1.getStars() && + if (war.getState() == WarState.ENDED) + { + if (clan2.getStars() > clan1.getStars() || (clan2.getStars() == clan1.getStars() && clan2.getDestructionPercentage() > clan1.getDestructionPercentage())) { WarClan tmp = clan1; clan1 = clan2; @@ -145,7 +143,8 @@ public static void drawRound(Graphics2D g2d, SlashCommandInteractionEvent event, drawCenteredString(g2d, rectStarClan1, font.deriveFont(18f), String.valueOf(clan1.getStars())); drawCenteredString(g2d, rectStarClan2, font.deriveFont(18f), String.valueOf(clan2.getStars())); - if (firstWar.getState().equals("inWar")) { + if (firstWar.getState() == WarState.IN_WAR) + { // Drawing clan names drawShadowedStringLeft(g2d, clan1.getName(), 255, 113 + i * 60, 16f, Color.WHITE); drawShadowedString(g2d, clan2.getName(), 670, 113 + i * 60, 16f); @@ -157,7 +156,9 @@ public static void drawRound(Graphics2D g2d, SlashCommandInteractionEvent event, // Drawing clan attacks drawShadowedString(g2d, String.valueOf(clan2.getAttacks()), 350, 109 + i * 60, 12f); drawShadowedString(g2d, String.valueOf(clan1.getAttacks()), 569, 109 + i * 60, 12f); - } else { + } + else + { // Drawing clan names drawShadowedStringLeft(g2d, clan1.getName(), 300, 113 + i * 60, 16f, Color.WHITE); drawShadowedString(g2d, clan2.getName(), 625, 113 + i * 60, 16f); @@ -170,8 +171,10 @@ public static void drawRound(Graphics2D g2d, SlashCommandInteractionEvent event, } } - public static void updateStats(WarClan clan, HashMap stats) { - if (clan != null) { + public static void updateStats(WarClan clan, HashMap stats) + { + if (clan != null) + { if (stats.containsKey(clan.getTag())) { ClanWarStats stats1 = stats.get(clan.getTag()); stats1.addStars(clan.getStars()); @@ -182,10 +185,13 @@ public static void updateStats(WarClan clan, HashMap stats } } - public static void drawStats(List rounds) { + public static void drawStats(List rounds) + { HashMap stats = new HashMap<>(); - for (RoundWarInfo roundWars : rounds) { - for (int j = 0; j < roundWars.getWars().size(); j++) { + for (RoundWarInfo roundWars : rounds) + { + for (int j = 0; j < roundWars.getWars().size(); j++) + { War warInfo = roundWars.getWars().get(j); updateStats(warInfo.getClan(), stats); updateStats(warInfo.getOpponent(), stats); @@ -193,7 +199,8 @@ public static void drawStats(List rounds) { } } - public static WarLeagueGroup getLeagueGroup(SlashCommandInteractionEvent event, Locale lang, String[] args) { + public static WarLeagueGroup getLeagueGroup(SlashCommandInteractionEvent event, Locale lang, String[] args) + { // If rate limitation has exceeded if (!checkThrottle(event, lang)) return null; @@ -204,20 +211,21 @@ public static WarLeagueGroup getLeagueGroup(SlashCommandInteractionEvent event, if (tag == null) { sendError(event, i18n.getString("set.clan.error"), - MessageFormat.format(i18n.getString("cmd.general.tip"), Command.SET_CLAN.formatCommand())); + MessageFormat.format(i18n.getString("cmd.general.tip"), CommandData.SET_CLAN.formatCommand())); return null; } try { leagueGroup = ClashBotMain.clashAPI.getWarLeagueGroup(tag); - } catch (ClashAPIException e) { + } catch (ClashAPIException | IOException e) { sendExceptionError(event, i18n, e, tag, "warleague"); return null; } return leagueGroup; } - public static void executeRound(SlashCommandInteractionEvent event, String... args) { + public static void executeRound(SlashCommandInteractionEvent event, String... args) + { Locale lang = LangUtils.getLanguage(event.getMember().getIdLong()); ResourceBundle i18n = LangUtils.getTranslations(lang); @@ -263,11 +271,12 @@ else if (clan1.getDestructionPercentage() < clan2.getDestructionPercentage()) return clan2; } - public static int getWinStars(WarClan clan1, WarClan clan2, War war) { - if (!war.getState().equals("warEnded")) { + public static int getWinStars(WarClan clan1, WarClan clan2, War war) + { + if (war.getState() != WarState.ENDED) + { if (getWinner(clan1, clan2) == null) return 0; - if (Objects.equals(getWinner(clan1, clan2), clan1)) return 10; } diff --git a/src/main/java/com/lycoon/clashbot/commands/clan/WarlogCommand.java b/src/main/java/com/lycoon/clashbot/commands/clan/WarlogCommand.java index 85f1252..b0fd189 100644 --- a/src/main/java/com/lycoon/clashbot/commands/clan/WarlogCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/clan/WarlogCommand.java @@ -3,20 +3,18 @@ import static com.lycoon.clashbot.utils.DrawUtils.*; import static com.lycoon.clashbot.utils.FileUtils.*; import static com.lycoon.clashbot.utils.ErrorUtils.*; -import static com.lycoon.clashbot.utils.DatabaseUtils.*; +import static com.lycoon.clashbot.utils.database.DatabaseUtils.*; import static com.lycoon.clashbot.utils.CoreUtils.*; import static com.lycoon.clashbot.utils.GameUtils.*; import com.lycoon.clashapi.core.exceptions.ClashAPIException; import com.lycoon.clashapi.models.war.WarlogClan; import com.lycoon.clashapi.models.war.WarlogEntry; -import com.lycoon.clashapi.core.exception.ClashAPIException; import com.lycoon.clashapi.models.war.enums.WarResult; -import com.lycoon.clashbot.commands.Command; +import com.lycoon.clashbot.commands.CommandData; import com.lycoon.clashbot.core.CacheComponents; import com.lycoon.clashbot.core.ClashBotMain; import com.lycoon.clashbot.lang.LangUtils; -import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import java.awt.*; @@ -48,7 +46,8 @@ public class WarlogCommand { private final static Color versusColor = new Color(0xffffc0); private final static Color percentageColor = new Color(0x5e5d60); - public static void call(SlashCommandInteractionEvent event) { + public static void call(SlashCommandInteractionEvent event) + { CompletableFuture.runAsync(() -> { if (event.getOptions().isEmpty()) { @@ -139,17 +138,17 @@ public static List getWarlog(SlashCommandInteractionEvent event, Lo if (tag == null) { sendError(event, i18n.getString("set.clan.error"), - MessageFormat.format(i18n.getString("cmd.general.tip"), Command.SET_CLAN.formatCommand())); + MessageFormat.format(i18n.getString("cmd.general.tip"), CommandData.SET_CLAN.formatCommand())); return null; } - try { - warlog = ClashBotMain.clashAPI.getWarlog(tag); - } catch (IOException ignored) { - } catch (ClashAPIException e) { + try { warlog = ClashBotMain.clashAPI.getWarlog(tag, null); } + catch (ClashAPIException | IOException e) + { sendExceptionError(event, i18n, e, tag, "warlog"); return null; } + return warlog; } diff --git a/src/main/java/com/lycoon/clashbot/commands/misc/ClearCommand.java b/src/main/java/com/lycoon/clashbot/commands/misc/ClearCommand.java index 14c387f..52db5b1 100644 --- a/src/main/java/com/lycoon/clashbot/commands/misc/ClearCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/misc/ClearCommand.java @@ -2,7 +2,7 @@ import com.lycoon.clashbot.lang.LangUtils; import com.lycoon.clashbot.utils.CoreUtils; -import com.lycoon.clashbot.utils.DatabaseUtils; +import com.lycoon.clashbot.utils.database.DatabaseUtils; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; diff --git a/src/main/java/com/lycoon/clashbot/commands/misc/HelpCommand.java b/src/main/java/com/lycoon/clashbot/commands/misc/HelpCommand.java index dff9faf..9c31172 100644 --- a/src/main/java/com/lycoon/clashbot/commands/misc/HelpCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/misc/HelpCommand.java @@ -1,6 +1,6 @@ package com.lycoon.clashbot.commands.misc; -import com.lycoon.clashbot.commands.Command; +import com.lycoon.clashbot.commands.CommandData; import com.lycoon.clashbot.commands.CommandCategory; import com.lycoon.clashbot.lang.LangUtils; import com.lycoon.clashbot.utils.CoreUtils; @@ -20,10 +20,10 @@ public static void call(SlashCommandInteractionEvent event) execute(event); } - public static void drawCategory(CommandCategory category, Command[] commands) + public static void drawCategory(CommandCategory category, CommandData[] commands) { StringBuilder categoryField = new StringBuilder(); - for (Command cmd : commands) + for (CommandData cmd : commands) if (cmd.getCategory().equals(category)) { categoryField.append("▫ `").append(cmd.formatCommand()).append("` "); categoryField.append(i18n.getString(cmd.getDescription())).append("\n"); @@ -42,7 +42,7 @@ public static void execute(SlashCommandInteractionEvent event) CommandCategory[] categories = CommandCategory.values(); for (CommandCategory category : categories) - drawCategory(category, Command.values()); + drawCategory(category, CommandData.values()); CoreUtils.sendMessage(event, i18n, builder); } diff --git a/src/main/java/com/lycoon/clashbot/commands/misc/InfoCommand.java b/src/main/java/com/lycoon/clashbot/commands/misc/InfoCommand.java index fb8766d..d214a0a 100644 --- a/src/main/java/com/lycoon/clashbot/commands/misc/InfoCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/misc/InfoCommand.java @@ -4,7 +4,9 @@ import com.lycoon.clashbot.lang.LangUtils; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.components.buttons.Button; import java.awt.*; import java.text.NumberFormat; @@ -15,7 +17,7 @@ public class InfoCommand { private static final String TWITTER = "@LycoonMC"; - private static final String DISCORD = "Lycoon#7542"; + private static final String AUTHOR = "@lycoon"; private static final String WEBSITE = "https://clashbot.app/"; private static final String DISCORD_INVITE = "https://discord.gg/Cy86PDA"; private static final String PATREON = "https://www.patreon.com/clashbot"; @@ -43,15 +45,15 @@ public static void execute(SlashCommandInteractionEvent event) builder.addField("Version", ClashBotMain.VERSION, true); builder.addField("Library", "Discord JDA", true); - builder.addField("Author", "Lycoon#7542", true); + builder.addField("Author", AUTHOR, true); builder.addField("Members", nf.format(guilds.stream().mapToInt(Guild::getMemberCount).sum()), true); builder.addField("Servers", nf.format(guilds.size()), true); builder.addField("Ping", nf.format(ClashBotMain.jda.getRestPing().complete()) + "ms", true); event.getHook().sendMessageEmbeds(builder.build()).addActionRow( - Button.link(WEBSITE, "Official Website").withEmoji(Emoji.fromMarkdown(CLASHBOT_EMOJI)), - Button.link(DISCORD_INVITE, "Official Discord").withEmoji(Emoji.fromMarkdown(DISCORD_EMOJI)), - Button.link(PATREON, "Contribute").withEmoji(Emoji.fromMarkdown(PATREON_EMOJI)) + Button.link(WEBSITE, "Official Website").withEmoji(Emoji.fromFormatted(CLASHBOT_EMOJI)), + Button.link(DISCORD_INVITE, "Official Discord").withEmoji(Emoji.fromFormatted(DISCORD_EMOJI)), + Button.link(PATREON, "Contribute").withEmoji(Emoji.fromFormatted(PATREON_EMOJI)) ).queue(); } } diff --git a/src/main/java/com/lycoon/clashbot/commands/misc/InviteCommand.java b/src/main/java/com/lycoon/clashbot/commands/misc/InviteCommand.java index 06d43fd..478a99e 100644 --- a/src/main/java/com/lycoon/clashbot/commands/misc/InviteCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/misc/InviteCommand.java @@ -25,9 +25,7 @@ public static void execute(SlashCommandInteractionEvent event) EmbedBuilder builder = new EmbedBuilder(); builder.setColor(Color.GRAY); - builder.setDescription(INVITE_EMOJI + " " + MessageFormat.format( - i18n.getString("cmd.invite.panel"), - ClashBotMain.INVITE)); + builder.setDescription(INVITE_EMOJI + " " + MessageFormat.format(i18n.getString("cmd.invite.panel"), ClashBotMain.INVITE)); CoreUtils.sendMessage(event, i18n, builder); } diff --git a/src/main/java/com/lycoon/clashbot/commands/misc/LangCommand.java b/src/main/java/com/lycoon/clashbot/commands/misc/LangCommand.java index c69a754..5894fdf 100644 --- a/src/main/java/com/lycoon/clashbot/commands/misc/LangCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/misc/LangCommand.java @@ -1,6 +1,6 @@ package com.lycoon.clashbot.commands.misc; -import com.lycoon.clashbot.commands.Command; +import com.lycoon.clashbot.commands.CommandData; import com.lycoon.clashbot.lang.LangUtils; import com.lycoon.clashbot.utils.CoreUtils; import net.dv8tion.jda.api.EmbedBuilder; @@ -29,7 +29,7 @@ public static void execute(SlashCommandInteractionEvent event) i18n.getString("lang.flag") + " " + MessageFormat.format( i18n.getString("lang.current"), lang.getDisplayLanguage(lang))); builder.setDescription(MessageFormat.format( - i18n.getString("lang.info.other"), Command.SET_LANG.formatCommand())); + i18n.getString("lang.info.other"), CommandData.SET_LANG.formatCommand())); CoreUtils.sendMessage(event, i18n, builder); } diff --git a/src/main/java/com/lycoon/clashbot/commands/PlayerCommand.java b/src/main/java/com/lycoon/clashbot/commands/player/PlayerCommand.java similarity index 96% rename from src/main/java/com/lycoon/clashbot/commands/PlayerCommand.java rename to src/main/java/com/lycoon/clashbot/commands/player/PlayerCommand.java index 5a5c6dc..06ddca6 100644 --- a/src/main/java/com/lycoon/clashbot/commands/PlayerCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/player/PlayerCommand.java @@ -1,249 +1,251 @@ -package com.lycoon.clashbot.commands; - -import static com.lycoon.clashbot.utils.DrawUtils.*; -import static com.lycoon.clashbot.utils.FileUtils.*; -import static com.lycoon.clashbot.utils.ErrorUtils.*; -import static com.lycoon.clashbot.utils.DatabaseUtils.*; -import static com.lycoon.clashbot.utils.CoreUtils.*; -import static com.lycoon.clashbot.utils.GameUtils.*; - -import com.lycoon.clashapi.core.exceptions.ClashAPIException; -import com.lycoon.clashapi.models.player.Player; -import com.lycoon.clashapi.models.player.Troop; -import com.lycoon.clashbot.core.CacheComponents; -import com.lycoon.clashbot.core.ClashBotMain; -import com.lycoon.clashbot.lang.LangUtils; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.text.MessageFormat; -import java.text.NumberFormat; -import java.util.List; -import java.util.Locale; -import java.util.ResourceBundle; -import java.util.concurrent.CompletableFuture; - -public class PlayerCommand { - private final static int WIDTH = 932; - private final static int HEIGHT = 559; - private final static float FONT_SIZE = 12f; - - private final static int COLUMNS = 4; - private final static int ARMY_TOPLINE = 238; - private final static int ARMY_BOTLINE = 436; - - private final static String[] TROOPS = {"Barbarian", "Archer", "Giant", "Goblin", "Wall Breaker", "Balloon", - "Wizard", "Healer", "Dragon", "P.E.K.K.A", "Baby Dragon", "Miner", "Electro Dragon", "Yeti", "Minion", - "Hog Rider", "Valkyrie", "Golem", "Witch", "Lava Hound", "Bowler", "Ice Golem", "Headhunter", "Dragon Rider"}; - private final static String[] SPELLS = {"Lightning Spell", "Healing Spell", "Rage Spell", "Jump Spell", - "Freeze Spell", "Clone Spell", "Invisibility Spell", "Poison Spell", "Earthquake Spell", "Haste Spell", - "Skeleton Spell", "Bat Spell"}; - private final static String[] BUILDER_TROOPS = {"Raged Barbarian", "Sneaky Archer", "Boxer Giant", "Beta Minion", - "Bomber", "Baby Dragon", "Cannon Cart", "Night Witch", "Drop Ship", "Super P.E.K.K.A", "Hog Glider"}; - private final static String[] SUPER_TROOPS = {"Super Barbarian", "Super Archer", "Super Giant", "Sneaky Goblin", - "Super Wall Breaker", "Super Wizard", "Inferno Dragon", "Super Minion", "Super Valkyrie", "Super Witch", - "Ice Hound", "Rocket Balloon", "Super Dragon", "Super Bowler"}; - private final static String[] HEROES = {"Barbarian King", "Archer Queen", "Grand Warden", "Royal Champion", - "Battle Machine"}; - private final static String[] MACHINES = {"Wall Wrecker", "Battle Blimp", "Stone Slammer", "Siege Barracks", - "Log Launcher", "Flame Flinger"}; - private final static String[] PETS = {"L.A.S.S.I", "Electro Owl", "Mighty Yak", "Unicorn"}; - - public static void call(SlashCommandInteractionEvent event) { - CompletableFuture.runAsync(() -> { - if (event.getOptions().isEmpty()) - execute(event); - else - execute(event, event.getOption("player_tag").getAsString()); - }); - } - - public static void drawSuperTroop(Graphics2D g2d, Troop troop, String troopName, int x, int y) { - if (troop == null || !troop.getSuperTroopIsActive()) - g2d.drawImage(getImageFromFile("troops/locked/" + troopName + ".png"), x, y, 44, 44, null); - else - g2d.drawImage(getImageFromFile("troops/" + troop.getName() + ".png"), x, y, 44, 44, null); - } - - public static void drawTroop(Graphics2D g2d, Font font, Troop troop, String troopName, int x, int y) { - // If the player has not unlocked the troop yet - if (troop == null) - g2d.drawImage(getImageFromFile("troops/locked/" + troopName + ".png"), x, y, 44, 44, null); - else { - g2d.drawImage(getImageFromFile("troops/" + troop.getName() + ".png"), x, y, 44, 44, null); - if (troop.getLevel() == troop.getMaxLevel()) - g2d.drawImage(getImageFromFile("icons/level-label-max.png"), x + 1, y + 22, 20, 20, null); - else if (troop.getLevel() != 1) - g2d.drawImage(getImageFromFile("icons/level-label.png"), x + 1, y + 22, 20, 20, null); - - if (troop.getLevel() != 1) { - Rectangle levelRect = new Rectangle(x + 1, y + 22, 20, 20); - drawCenteredString(g2d, levelRect, font.deriveFont(font.getSize() - 2f), String.valueOf(troop.getLevel())); - } - } - } - - public static void drawTroops(Graphics2D g2d, Font font, List troops, int y) { - for (int i = 0, j = 0; i < TROOPS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) - drawTroop(g2d, font, getHomeTroopByName(troops, TROOPS[i]), TROOPS[i], (i % COLUMNS) * 50 + 20, y + j * 50); - } - - public static void drawSpells(Graphics2D g2d, Font font, List spells, int y) { - for (int i = 0, j = 0; i < SPELLS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) - drawTroop(g2d, font, getTroopByName(spells, SPELLS[i]), SPELLS[i], (i % COLUMNS) * 50 + 250, y + j * 50); - } - - public static void drawBuilderTroops(Graphics2D g2d, Font font, List builderTroops, int y) { - for (int i = 0, j = 0; i < BUILDER_TROOPS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) - drawTroop(g2d, font, getBuilderTroopByName(builderTroops, BUILDER_TROOPS[i]), BUILDER_TROOPS[i], (i % COLUMNS) * 50 + 480, y + j * 50); - } - - public static void drawSuperTroops(Graphics2D g2d, List superTroops, int y) { - for (int i = 0, j = 0; i < SUPER_TROOPS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) - drawSuperTroop(g2d, getTroopByName(superTroops, SUPER_TROOPS[i]), SUPER_TROOPS[i], (i % COLUMNS) * 50 + 710, y + j * 50); - } - - public static void drawHeroes(Graphics2D g2d, Font font, List heroes, int y) { - for (int i = 0, j = 0; i < HEROES.length; i++, j += i % COLUMNS == 0 ? 1 : 0) - drawTroop(g2d, font, getTroopByName(heroes, HEROES[i]), HEROES[i], (i % COLUMNS) * 50 + 250, y + j * 50); - } - - public static void drawMachines(Graphics2D g2d, Font font, List machines, int y) { - for (int i = 0, j = 0; i < MACHINES.length; i++, j += i % COLUMNS == 0 ? 1 : 0) - drawTroop(g2d, font, getTroopByName(machines, MACHINES[i]), MACHINES[i], (i % COLUMNS) * 50 + 480, y + j * 50); - } - - public static void drawPets(Graphics2D g2d, Font font, List pets, int y) { - for (int i = 0, j = 0; i < PETS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) - drawTroop(g2d, font, getTroopByName(pets, PETS[i]), PETS[i], (i % COLUMNS) * 50 + 710, y + j * 50); - } - - public static void execute(SlashCommandInteractionEvent event, String... args) { - Locale lang = LangUtils.getLanguage(event.getMember().getIdLong()); - ResourceBundle i18n = LangUtils.getTranslations(lang); - NumberFormat nf = NumberFormat.getInstance(lang); - - // Checking rate limitation - if (!checkThrottle(event, lang)) - return; - - Player player; - String tag = args.length > 0 ? args[0] : getPlayerTag(event.getMember().getIdLong()); - - if (tag == null) { - sendError(event, i18n.getString("set.player.error"), - MessageFormat.format(i18n.getString("cmd.general.tip"), Command.SET_PLAYER.formatCommand())); - return; - } - - try { - player = ClashBotMain.clashAPI.getPlayer(tag); - } catch (ClashAPIException e) { - sendExceptionError(event, i18n, e, tag, "player"); - return; - } - - // Initializing image - BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); - Graphics2D g2d = initGraphics(WIDTH, HEIGHT, image); - - Font font = getFont("Supercell.ttf").deriveFont(FONT_SIZE); - g2d.setFont(font); - - g2d.drawImage(getImageFromFile("backgrounds/player-profile.png"), 0, 0, null); - - // Experience level - g2d.drawImage(getImageFromFile("icons/exp-star.png"), 20, 18, 45, 45, null); - Rectangle level = new Rectangle(23, 30, 40, 20); - drawCenteredString(g2d, level, font.deriveFont(FONT_SIZE + 5f), String.valueOf(player.getExpLevel())); - - // Nickname - drawShadowedString(g2d, player.getName(), 75, 36, FONT_SIZE + 8f); - - // Player tag - drawShadowedString(g2d, player.getTag(), 75, 55, FONT_SIZE - 1f); - - // Townhall - g2d.drawImage(CacheComponents.getTownHallImage(player.getTownHallLevel()), 80, 80, 100, 100, null); - drawShadowedString(g2d, i18n.getString("townhall"), 25, 125, FONT_SIZE - 2f); - drawShadowedString(g2d, i18n.getString("level") + " " + player.getTownHallLevel(), 25, 150, FONT_SIZE + 8f); - - // Builder hall - if (player.getBuilderHallLevel() != 0) { - g2d.drawImage(CacheComponents.getBuilderHallImage(player.getBuilderHallLevel()), 265, 85, 95, 95, null); - drawShadowedString(g2d, i18n.getString("level") + " " + player.getBuilderHallLevel(), 200, 150, FONT_SIZE + 8f); - } else { - // In case the player has not built the builder hall yet - drawShadowedString(g2d, i18n.getString("no.builderhall"), 200, 150, FONT_SIZE + 8f); - } - drawShadowedString(g2d, i18n.getString("builderhall"), 200, 125, FONT_SIZE - 2f); - - // League - if (player.getLeague() != null) - g2d.drawImage(getImageFromUrl(player.getLeague().getIconUrls().getMedium()), 383, 30, 90, 90, null); - else { - g2d.drawImage(getImageFromFile("icons/noleague.png"), 383, 30, 90, 90, null); - Rectangle noLeagueRect = new Rectangle(375, 60, 105, 20); - drawCenteredString(g2d, noLeagueRect, font.deriveFont(FONT_SIZE - 4f), i18n.getString("no.league")); - } - - // Clan - if (player.getClan() != null) { - g2d.drawImage(getImageFromUrl(player.getClan().getBadgeUrls().getLarge()), 800, 30, 105, 105, null); - - Rectangle clanNameRect = new Rectangle(775, 130, 148, 30); - Rectangle clanRoleRect = new Rectangle(775, 151, 148, 30); - drawCenteredString(g2d, clanNameRect, font.deriveFont(FONT_SIZE + 2f), player.getClan().getName()); - drawCenteredString(g2d, clanRoleRect, font.deriveFont(FONT_SIZE - 2f), i18n.getString(String.valueOf(player.getRole()))); - } else { - Rectangle noClanRect = new Rectangle(775, 130, 148, 30); - drawCenteredString(g2d, noClanRect, font.deriveFont(FONT_SIZE + 2f), i18n.getString("no.clan")); - g2d.drawImage(getImageFromFile("icons/noclan.png"), 812, 40, 75, 75, null); - } - - // Trophies - Rectangle trophiesRect = new Rectangle(375, 148, 75, 24); - drawCenteredString(g2d, trophiesRect, font.deriveFont(FONT_SIZE + 4f), nf.format(player.getTrophies())); - - // Statistics - drawShadowedString(g2d, i18n.getString("season") + " " + getCurrentSeason(lang), 486, 45, FONT_SIZE + 3f); - drawShadowedString(g2d, i18n.getString("attacks.won"), 486, 77, FONT_SIZE - 1.5f); - drawShadowedString(g2d, i18n.getString("defenses.won"), 486, 107, FONT_SIZE - 1.5f); - drawShadowedString(g2d, i18n.getString("donations"), 486, 143, FONT_SIZE - 1.5f); - drawShadowedString(g2d, i18n.getString("donations.received"), 486, 173, FONT_SIZE - 1.5f); - - drawSimpleString(g2d, nf.format(player.getAttackWins()), 693, 79, FONT_SIZE, new Color(0x444545)); - drawSimpleString(g2d, nf.format(player.getDefenseWins()), 693, 109, FONT_SIZE, new Color(0x444545)); - drawSimpleString(g2d, nf.format(player.getDonations()), 693, 144, FONT_SIZE, new Color(0x444545)); - drawSimpleString(g2d, nf.format(player.getDonationsReceived()), 693, 174, FONT_SIZE, new Color(0x444545)); - - // Army - drawShadowedString(g2d, i18n.getString("troops"), 21, ARMY_TOPLINE - 12, FONT_SIZE + 2f); - drawShadowedString(g2d, i18n.getString("spells"), 251, ARMY_TOPLINE - 12, FONT_SIZE + 2f); - drawShadowedString(g2d, i18n.getString("label.builderbase"), 481, ARMY_TOPLINE - 12, FONT_SIZE + 2f); - drawShadowedString(g2d, i18n.getString("super.troops"), 711, ARMY_TOPLINE - 12, FONT_SIZE + 2f); - drawShadowedString(g2d, i18n.getString("heroes"), 251, ARMY_BOTLINE - 12, FONT_SIZE + 2f); - drawShadowedString(g2d, i18n.getString("machines"), 481, ARMY_BOTLINE - 12, FONT_SIZE + 2f); - drawShadowedString(g2d, i18n.getString("pets"), 711, ARMY_BOTLINE + 38, FONT_SIZE + 2f); - - // Troops - List troops = player.getTroops(); - List heroes = player.getHeroes(); - List spells = player.getSpells(); - - drawTroops(g2d, font, troops, ARMY_TOPLINE); - drawSpells(g2d, font, spells, ARMY_TOPLINE); - drawBuilderTroops(g2d, font, troops, ARMY_TOPLINE); - drawSuperTroops(g2d, troops, ARMY_TOPLINE); - - drawHeroes(g2d, font, heroes, ARMY_BOTLINE); - drawMachines(g2d, font, troops, ARMY_BOTLINE); - drawPets(g2d, font, troops, ARMY_BOTLINE + 50); - - sendImage(event, image); - - g2d.dispose(); - } -} +package com.lycoon.clashbot.commands.player; + +import static com.lycoon.clashbot.utils.DrawUtils.*; +import static com.lycoon.clashbot.utils.FileUtils.*; +import static com.lycoon.clashbot.utils.ErrorUtils.*; +import static com.lycoon.clashbot.utils.database.DatabaseUtils.*; +import static com.lycoon.clashbot.utils.CoreUtils.*; +import static com.lycoon.clashbot.utils.GameUtils.*; + +import com.lycoon.clashapi.core.exceptions.ClashAPIException; +import com.lycoon.clashapi.models.player.Player; +import com.lycoon.clashapi.models.player.Troop; +import com.lycoon.clashbot.commands.CommandData; +import com.lycoon.clashbot.core.CacheComponents; +import com.lycoon.clashbot.core.ClashBotMain; +import com.lycoon.clashbot.lang.LangUtils; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.text.MessageFormat; +import java.text.NumberFormat; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.concurrent.CompletableFuture; + +public class PlayerCommand +{ + private final static int WIDTH = 932; + private final static int HEIGHT = 559; + private final static float FONT_SIZE = 12f; + + private final static int COLUMNS = 4; + private final static int ARMY_TOPLINE = 238; + private final static int ARMY_BOTLINE = 436; + + private final static String[] TROOPS = {"Barbarian", "Archer", "Giant", "Goblin", "Wall Breaker", "Balloon", + "Wizard", "Healer", "Dragon", "P.E.K.K.A", "Baby Dragon", "Miner", "Electro Dragon", "Yeti", "Minion", + "Hog Rider", "Valkyrie", "Golem", "Witch", "Lava Hound", "Bowler", "Ice Golem", "Headhunter", "Dragon Rider"}; + private final static String[] SPELLS = {"Lightning Spell", "Healing Spell", "Rage Spell", "Jump Spell", + "Freeze Spell", "Clone Spell", "Invisibility Spell", "Poison Spell", "Earthquake Spell", "Haste Spell", + "Skeleton Spell", "Bat Spell"}; + private final static String[] BUILDER_TROOPS = {"Raged Barbarian", "Sneaky Archer", "Boxer Giant", "Beta Minion", + "Bomber", "Baby Dragon", "Cannon Cart", "Night Witch", "Drop Ship", "Super P.E.K.K.A", "Hog Glider"}; + private final static String[] SUPER_TROOPS = {"Super Barbarian", "Super Archer", "Super Giant", "Sneaky Goblin", + "Super Wall Breaker", "Super Wizard", "Inferno Dragon", "Super Minion", "Super Valkyrie", "Super Witch", + "Ice Hound", "Rocket Balloon", "Super Dragon", "Super Bowler"}; + private final static String[] HEROES = {"Barbarian King", "Archer Queen", "Grand Warden", "Royal Champion", + "Battle Machine"}; + private final static String[] MACHINES = {"Wall Wrecker", "Battle Blimp", "Stone Slammer", "Siege Barracks", + "Log Launcher", "Flame Flinger"}; + private final static String[] PETS = {"L.A.S.S.I", "Electro Owl", "Mighty Yak", "Unicorn"}; + + public static void call(SlashCommandInteractionEvent event) { + CompletableFuture.runAsync(() -> { + if (event.getOptions().isEmpty()) + execute(event); + else + execute(event, event.getOption("player_tag").getAsString()); + }); + } + + public static void drawSuperTroop(Graphics2D g2d, Troop troop, String troopName, int x, int y) { + if (troop == null || !troop.getSuperTroopIsActive()) + g2d.drawImage(getImageFromFile("troops/locked/" + troopName + ".png"), x, y, 44, 44, null); + else + g2d.drawImage(getImageFromFile("troops/" + troop.getName() + ".png"), x, y, 44, 44, null); + } + + public static void drawTroop(Graphics2D g2d, Font font, Troop troop, String troopName, int x, int y) { + // If the player has not unlocked the troop yet + if (troop == null) + g2d.drawImage(getImageFromFile("troops/locked/" + troopName + ".png"), x, y, 44, 44, null); + else { + g2d.drawImage(getImageFromFile("troops/" + troop.getName() + ".png"), x, y, 44, 44, null); + if (troop.getLevel() == troop.getMaxLevel()) + g2d.drawImage(getImageFromFile("icons/level-label-max.png"), x + 1, y + 22, 20, 20, null); + else if (troop.getLevel() != 1) + g2d.drawImage(getImageFromFile("icons/level-label.png"), x + 1, y + 22, 20, 20, null); + + if (troop.getLevel() != 1) { + Rectangle levelRect = new Rectangle(x + 1, y + 22, 20, 20); + drawCenteredString(g2d, levelRect, font.deriveFont(font.getSize() - 2f), String.valueOf(troop.getLevel())); + } + } + } + + public static void drawTroops(Graphics2D g2d, Font font, List troops, int y) { + for (int i = 0, j = 0; i < TROOPS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) + drawTroop(g2d, font, getHomeTroopByName(troops, TROOPS[i]), TROOPS[i], (i % COLUMNS) * 50 + 20, y + j * 50); + } + + public static void drawSpells(Graphics2D g2d, Font font, List spells, int y) { + for (int i = 0, j = 0; i < SPELLS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) + drawTroop(g2d, font, getTroopByName(spells, SPELLS[i]), SPELLS[i], (i % COLUMNS) * 50 + 250, y + j * 50); + } + + public static void drawBuilderTroops(Graphics2D g2d, Font font, List builderTroops, int y) { + for (int i = 0, j = 0; i < BUILDER_TROOPS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) + drawTroop(g2d, font, getBuilderTroopByName(builderTroops, BUILDER_TROOPS[i]), BUILDER_TROOPS[i], (i % COLUMNS) * 50 + 480, y + j * 50); + } + + public static void drawSuperTroops(Graphics2D g2d, List superTroops, int y) { + for (int i = 0, j = 0; i < SUPER_TROOPS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) + drawSuperTroop(g2d, getTroopByName(superTroops, SUPER_TROOPS[i]), SUPER_TROOPS[i], (i % COLUMNS) * 50 + 710, y + j * 50); + } + + public static void drawHeroes(Graphics2D g2d, Font font, List heroes, int y) { + for (int i = 0, j = 0; i < HEROES.length; i++, j += i % COLUMNS == 0 ? 1 : 0) + drawTroop(g2d, font, getTroopByName(heroes, HEROES[i]), HEROES[i], (i % COLUMNS) * 50 + 250, y + j * 50); + } + + public static void drawMachines(Graphics2D g2d, Font font, List machines, int y) { + for (int i = 0, j = 0; i < MACHINES.length; i++, j += i % COLUMNS == 0 ? 1 : 0) + drawTroop(g2d, font, getTroopByName(machines, MACHINES[i]), MACHINES[i], (i % COLUMNS) * 50 + 480, y + j * 50); + } + + public static void drawPets(Graphics2D g2d, Font font, List pets, int y) { + for (int i = 0, j = 0; i < PETS.length; i++, j += i % COLUMNS == 0 ? 1 : 0) + drawTroop(g2d, font, getTroopByName(pets, PETS[i]), PETS[i], (i % COLUMNS) * 50 + 710, y + j * 50); + } + + public static void execute(SlashCommandInteractionEvent event, String... args) { + Locale lang = LangUtils.getLanguage(event.getMember().getIdLong()); + ResourceBundle i18n = LangUtils.getTranslations(lang); + NumberFormat nf = NumberFormat.getInstance(lang); + + // Checking rate limitation + if (!checkThrottle(event, lang)) + return; + + Player player; + String tag = args.length > 0 ? args[0] : getPlayerTag(event.getMember().getIdLong()); + + if (tag == null) { + sendError(event, i18n.getString("set.player.error"), + MessageFormat.format(i18n.getString("cmd.general.tip"), CommandData.SET_PLAYER.formatCommand())); + return; + } + + try { + player = ClashBotMain.clashAPI.getPlayer(tag); + } catch (ClashAPIException | IOException e) { + sendExceptionError(event, i18n, e, tag, "player"); + return; + } + + // Initializing image + BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = initGraphics(WIDTH, HEIGHT, image); + + Font font = getFont("Supercell.ttf").deriveFont(FONT_SIZE); + g2d.setFont(font); + + g2d.drawImage(getImageFromFile("backgrounds/player-profile.png"), 0, 0, null); + + // Experience level + g2d.drawImage(getImageFromFile("icons/exp-star.png"), 20, 18, 45, 45, null); + Rectangle level = new Rectangle(23, 30, 40, 20); + drawCenteredString(g2d, level, font.deriveFont(FONT_SIZE + 5f), String.valueOf(player.getExpLevel())); + + // Nickname + drawShadowedString(g2d, player.getName(), 75, 36, FONT_SIZE + 8f); + + // Player tag + drawShadowedString(g2d, player.getTag(), 75, 55, FONT_SIZE - 1f); + + // Townhall + g2d.drawImage(CacheComponents.getTownHallImage(player.getTownHallLevel()), 80, 80, 100, 100, null); + drawShadowedString(g2d, i18n.getString("townhall"), 25, 125, FONT_SIZE - 2f); + drawShadowedString(g2d, i18n.getString("level") + " " + player.getTownHallLevel(), 25, 150, FONT_SIZE + 8f); + + // Builder hall + if (player.getBuilderHallLevel() != 0) { + g2d.drawImage(CacheComponents.getBuilderHallImage(player.getBuilderHallLevel()), 265, 85, 95, 95, null); + drawShadowedString(g2d, i18n.getString("level") + " " + player.getBuilderHallLevel(), 200, 150, FONT_SIZE + 8f); + } else { + // In case the player has not built the builder hall yet + drawShadowedString(g2d, i18n.getString("no.builderhall"), 200, 150, FONT_SIZE + 8f); + } + drawShadowedString(g2d, i18n.getString("builderhall"), 200, 125, FONT_SIZE - 2f); + + // League + if (player.getLeague() != null) + g2d.drawImage(getImageFromUrl(player.getLeague().getIconUrls().getMedium()), 383, 30, 90, 90, null); + else { + g2d.drawImage(getImageFromFile("icons/noleague.png"), 383, 30, 90, 90, null); + Rectangle noLeagueRect = new Rectangle(375, 60, 105, 20); + drawCenteredString(g2d, noLeagueRect, font.deriveFont(FONT_SIZE - 4f), i18n.getString("no.league")); + } + + // Clan + if (player.getClan() != null) { + g2d.drawImage(getImageFromUrl(player.getClan().getBadgeUrls().getLarge()), 800, 30, 105, 105, null); + + Rectangle clanNameRect = new Rectangle(775, 130, 148, 30); + Rectangle clanRoleRect = new Rectangle(775, 151, 148, 30); + drawCenteredString(g2d, clanNameRect, font.deriveFont(FONT_SIZE + 2f), player.getClan().getName()); + drawCenteredString(g2d, clanRoleRect, font.deriveFont(FONT_SIZE - 2f), i18n.getString(String.valueOf(player.getRole()))); + } else { + Rectangle noClanRect = new Rectangle(775, 130, 148, 30); + drawCenteredString(g2d, noClanRect, font.deriveFont(FONT_SIZE + 2f), i18n.getString("no.clan")); + g2d.drawImage(getImageFromFile("icons/noclan.png"), 812, 40, 75, 75, null); + } + + // Trophies + Rectangle trophiesRect = new Rectangle(375, 148, 75, 24); + drawCenteredString(g2d, trophiesRect, font.deriveFont(FONT_SIZE + 4f), nf.format(player.getTrophies())); + + // Statistics + drawShadowedString(g2d, i18n.getString("season") + " " + getCurrentSeason(lang), 486, 45, FONT_SIZE + 3f); + drawShadowedString(g2d, i18n.getString("attacks.won"), 486, 77, FONT_SIZE - 1.5f); + drawShadowedString(g2d, i18n.getString("defenses.won"), 486, 107, FONT_SIZE - 1.5f); + drawShadowedString(g2d, i18n.getString("donations"), 486, 143, FONT_SIZE - 1.5f); + drawShadowedString(g2d, i18n.getString("donations.received"), 486, 173, FONT_SIZE - 1.5f); + + drawSimpleString(g2d, nf.format(player.getAttackWins()), 693, 79, FONT_SIZE, new Color(0x444545)); + drawSimpleString(g2d, nf.format(player.getDefenseWins()), 693, 109, FONT_SIZE, new Color(0x444545)); + drawSimpleString(g2d, nf.format(player.getDonations()), 693, 144, FONT_SIZE, new Color(0x444545)); + drawSimpleString(g2d, nf.format(player.getDonationsReceived()), 693, 174, FONT_SIZE, new Color(0x444545)); + + // Army + drawShadowedString(g2d, i18n.getString("troops"), 21, ARMY_TOPLINE - 12, FONT_SIZE + 2f); + drawShadowedString(g2d, i18n.getString("spells"), 251, ARMY_TOPLINE - 12, FONT_SIZE + 2f); + drawShadowedString(g2d, i18n.getString("label.builderbase"), 481, ARMY_TOPLINE - 12, FONT_SIZE + 2f); + drawShadowedString(g2d, i18n.getString("super.troops"), 711, ARMY_TOPLINE - 12, FONT_SIZE + 2f); + drawShadowedString(g2d, i18n.getString("heroes"), 251, ARMY_BOTLINE - 12, FONT_SIZE + 2f); + drawShadowedString(g2d, i18n.getString("machines"), 481, ARMY_BOTLINE - 12, FONT_SIZE + 2f); + drawShadowedString(g2d, i18n.getString("pets"), 711, ARMY_BOTLINE + 38, FONT_SIZE + 2f); + + // Troops + List troops = player.getTroops(); + List heroes = player.getHeroes(); + List spells = player.getSpells(); + + drawTroops(g2d, font, troops, ARMY_TOPLINE); + drawSpells(g2d, font, spells, ARMY_TOPLINE); + drawBuilderTroops(g2d, font, troops, ARMY_TOPLINE); + drawSuperTroops(g2d, troops, ARMY_TOPLINE); + + drawHeroes(g2d, font, heroes, ARMY_BOTLINE); + drawMachines(g2d, font, troops, ARMY_BOTLINE); + drawPets(g2d, font, troops, ARMY_BOTLINE + 50); + + sendImage(event, image); + + g2d.dispose(); + } +} diff --git a/src/main/java/com/lycoon/clashbot/commands/settings/SetCommand.java b/src/main/java/com/lycoon/clashbot/commands/settings/SetCommand.java index a87c471..e6984ca 100644 --- a/src/main/java/com/lycoon/clashbot/commands/settings/SetCommand.java +++ b/src/main/java/com/lycoon/clashbot/commands/settings/SetCommand.java @@ -1,11 +1,11 @@ package com.lycoon.clashbot.commands.settings; import com.lycoon.clashapi.core.exceptions.ClashAPIException; -import com.lycoon.clashbot.commands.Command; +import com.lycoon.clashbot.commands.CommandData; import com.lycoon.clashbot.core.ClashBotMain; import com.lycoon.clashbot.lang.LangUtils; import com.lycoon.clashbot.utils.CoreUtils; -import com.lycoon.clashbot.utils.DatabaseUtils; +import com.lycoon.clashbot.utils.database.DatabaseUtils; import com.lycoon.clashbot.utils.ErrorUtils; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; @@ -19,15 +19,15 @@ public class SetCommand { public static void call(SlashCommandInteractionEvent event) { - if (event.getSubcommandName() == null) { + String type = event.getSubcommandName(); + if (type == null) + { ResourceBundle i18n = LangUtils.getTranslations(event.getMember().getIdLong()); - ErrorUtils.sendError(event, - i18n.getString("wrong.usage"), + ErrorUtils.sendError(event, i18n.getString("wrong.usage"), MessageFormat.format(i18n.getString("info.help"), "prefix")); return; } - String type = event.getSubcommandName(); switch (type) { case "player" -> executePlayer(event, event.getOption("player_tag").getAsString()); @@ -35,14 +35,14 @@ public static void call(SlashCommandInteractionEvent event) case "lang" -> executeLang(event, event.getOption("language").getAsString()); default -> { ResourceBundle i18n = LangUtils.getTranslations(event.getMember().getIdLong()); - ErrorUtils.sendError(event, - i18n.getString("wrong.usage"), + ErrorUtils.sendError(event, i18n.getString("wrong.usage"), MessageFormat.format(i18n.getString("info.help"), "prefix")); } } } - public static void executePlayer(SlashCommandInteractionEvent event, String tag) { + public static void executePlayer(SlashCommandInteractionEvent event, String tag) + { ResourceBundle i18n = LangUtils.getTranslations(event.getMember().getIdLong()); try { @@ -69,7 +69,7 @@ public static void executeClan(SlashCommandInteractionEvent event, String tag) try { // Checks if the clan exists ClashBotMain.clashAPI.getClan(tag); - } catch (ClashAPIException e) { + } catch (ClashAPIException | IOException e) { ErrorUtils.sendExceptionError(event, i18n, e, tag, "clan"); return; } @@ -98,7 +98,7 @@ public static void executeLang(SlashCommandInteractionEvent event, String langua MessageFormat.format(i18n.getString("lang.success"), lang.getDisplayLanguage(lang))); builder.setDescription( MessageFormat.format(i18n.getString("lang.info.other"), - Command.SET_LANG.formatCommand())); + CommandData.SET_LANG.formatCommand())); CoreUtils.sendMessage(event, i18n, builder); } diff --git a/src/main/java/com/lycoon/clashbot/core/CacheComponents.java b/src/main/java/com/lycoon/clashbot/core/CacheComponents.java index 14bac42..aef5c82 100644 --- a/src/main/java/com/lycoon/clashbot/core/CacheComponents.java +++ b/src/main/java/com/lycoon/clashbot/core/CacheComponents.java @@ -6,7 +6,8 @@ import com.lycoon.clashbot.utils.FileUtils; -public class CacheComponents { +public class CacheComponents +{ public static Image alreadyStar = FileUtils.getImageFromFile("icons/clanwar/alreadyclan-star.png"); public static Image newStar = FileUtils.getImageFromFile("icons/clanwar/clan-star.png"); public static Image noStar = FileUtils.getImageFromFile("icons/clanwar/noclan-star.png"); @@ -22,7 +23,8 @@ public class CacheComponents { private static final CacheComponents singleton = new CacheComponents(); - private CacheComponents() { + private CacheComponents() + { for (int i = 0; i < 14; i++) townhalls.add(FileUtils.getImageFromFile("buildings/townhalls/home/th" + (i + 1) + ".png")); for (int i = 0; i < 9; i++) diff --git a/src/main/java/com/lycoon/clashbot/core/ClashBotMain.java b/src/main/java/com/lycoon/clashbot/core/ClashBotMain.java index 36ac737..7a6ee88 100644 --- a/src/main/java/com/lycoon/clashbot/core/ClashBotMain.java +++ b/src/main/java/com/lycoon/clashbot/core/ClashBotMain.java @@ -8,7 +8,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.security.auth.login.LoginException; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; @@ -16,12 +15,12 @@ public class ClashBotMain { private static final String CONFIG = "tokens.properties"; - private static Properties tokens; + private static final Properties tokens = new Properties(); public static long[] owners = {138282927502000128L, 198485955701768192L}; public static final String VERSION = "2.0.0"; public static final String INVITE = "https://discord.com/api/oauth2/authorize?client_id=734481969630543883&permissions=2147534848&scope=bot%20applications.commands"; - public static Logger LOGGER = LoggerFactory.getLogger(ClashBotMain.class.getName()); + public static Logger LOGGER = LoggerFactory.getLogger(ClashBotMain.class); // Following attributes are initialized on launch public static ClashAPI clashAPI; @@ -34,7 +33,8 @@ public class ClashBotMain * All rights reserved 2024 * ###################################################################### */ - public static void main(String[] args) throws InterruptedException { + public static void main(String[] args) throws InterruptedException + { loadTokensFromConfig(); buildDiscordInstance(); diff --git a/src/main/java/com/lycoon/clashbot/core/EventListener.java b/src/main/java/com/lycoon/clashbot/core/EventListener.java index b93a24e..e0d1364 100644 --- a/src/main/java/com/lycoon/clashbot/core/EventListener.java +++ b/src/main/java/com/lycoon/clashbot/core/EventListener.java @@ -6,10 +6,10 @@ import com.lycoon.clashbot.commands.clan.WarLeagueCommand; import com.lycoon.clashbot.commands.clan.WarlogCommand; import com.lycoon.clashbot.commands.misc.*; +import com.lycoon.clashbot.commands.player.PlayerCommand; import com.lycoon.clashbot.commands.settings.SetCommand; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.unions.DefaultGuildChannelUnion; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; @@ -21,7 +21,7 @@ public class EventListener extends ListenerAdapter { - static boolean isCommand(String arg, Command cmd) { + static boolean isCommand(String arg, CommandData cmd) { return arg.equalsIgnoreCase(cmd.toString()); } @@ -37,9 +37,9 @@ static MessageEmbed warnNotInGuild() } @Override - public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { - if (!event.isFromGuild()) - { + public void onSlashCommandInteraction(SlashCommandInteractionEvent event) + { + if (!event.isFromGuild()){ event.replyEmbeds(warnNotInGuild()).queue(); return; } @@ -47,27 +47,27 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { event.deferReply().queue(); String cmd = event.getName(); - if (isCommand(cmd, Command.SET_LANG)) + if (isCommand(cmd, CommandData.SET_LANG)) SetCommand.call(event); - else if (isCommand(cmd, Command.PLAYER)) + else if (isCommand(cmd, CommandData.PLAYER)) PlayerCommand.call(event); - else if (isCommand(cmd, Command.CLAN)) + else if (isCommand(cmd, CommandData.CLAN)) ClanCommand.call(event); - else if (isCommand(cmd, Command.WAR)) + else if (isCommand(cmd, CommandData.WAR)) WarCommand.call(event); - else if (isCommand(cmd, Command.WARLOG)) + else if (isCommand(cmd, CommandData.WARLOG)) WarlogCommand.call(event); - else if (isCommand(cmd, Command.WARLEAGUE)) + else if (isCommand(cmd, CommandData.WARLEAGUE)) WarLeagueCommand.call(event); - else if (isCommand(cmd, Command.LANG)) + else if (isCommand(cmd, CommandData.LANG)) LangCommand.call(event); - else if (isCommand(cmd, Command.INFO)) + else if (isCommand(cmd, CommandData.INFO)) InfoCommand.call(event); - else if (isCommand(cmd, Command.HELP)) + else if (isCommand(cmd, CommandData.HELP)) HelpCommand.call(event); - else if (isCommand(cmd, Command.CLEAR)) + else if (isCommand(cmd, CommandData.CLEAR)) ClearCommand.call(event); - else if (isCommand(cmd, Command.INVITE)) + else if (isCommand(cmd, CommandData.INVITE)) InviteCommand.call(event); else { event.getHook().deleteOriginal().queue(); @@ -86,7 +86,7 @@ public void onGuildJoin(GuildJoinEvent event) builder.setTitle("Hi, thanks for inviting me!"); builder.setDescription("Run `/help` to get the list of all available commands :scroll:"); - try { Objects.requireNonNull(defaultChannel).asTextChannel().sendMessage(builder.build()).queue(); } + try { Objects.requireNonNull(defaultChannel).asTextChannel().sendMessageEmbeds(builder.build()).queue(); } catch (MissingAccessException ignored) {} } } diff --git a/src/main/java/com/lycoon/clashbot/lang/LangUtils.java b/src/main/java/com/lycoon/clashbot/lang/LangUtils.java index c90342a..c938810 100644 --- a/src/main/java/com/lycoon/clashbot/lang/LangUtils.java +++ b/src/main/java/com/lycoon/clashbot/lang/LangUtils.java @@ -1,6 +1,6 @@ package com.lycoon.clashbot.lang; -import com.lycoon.clashbot.utils.DatabaseUtils; +import com.lycoon.clashbot.utils.database.DatabaseUtils; import java.util.Locale; import java.util.ResourceBundle; diff --git a/src/main/java/com/lycoon/clashbot/lang/UTF16Control.java b/src/main/java/com/lycoon/clashbot/lang/UTF16Control.java index 68a8c1f..134759f 100644 --- a/src/main/java/com/lycoon/clashbot/lang/UTF16Control.java +++ b/src/main/java/com/lycoon/clashbot/lang/UTF16Control.java @@ -11,7 +11,8 @@ import java.util.ResourceBundle; import java.util.ResourceBundle.Control; -public class UTF16Control extends Control { +public class UTF16Control extends Control +{ public ResourceBundle newBundle (String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IOException { diff --git a/src/main/java/com/lycoon/clashbot/utils/CoreUtils.java b/src/main/java/com/lycoon/clashbot/utils/CoreUtils.java index d03bfff..5c7af54 100644 --- a/src/main/java/com/lycoon/clashbot/utils/CoreUtils.java +++ b/src/main/java/com/lycoon/clashbot/utils/CoreUtils.java @@ -6,9 +6,6 @@ import com.lycoon.clashbot.lang.LangUtils; import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.exceptions.InsufficientPermissionException; @@ -19,11 +16,11 @@ import java.time.Duration; import java.time.ZonedDateTime; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.ResourceBundle; -public class CoreUtils { +public class CoreUtils +{ public static final Color validColor = new Color(0x48bd73); public static final Color invalidColor = new Color(0xc24646); public static final String INFO_EMOJI = "<:info:825346959514533928>"; diff --git a/src/main/java/com/lycoon/clashbot/utils/DatabaseUtils.java b/src/main/java/com/lycoon/clashbot/utils/DatabaseUtils.java deleted file mode 100644 index 14ee568..0000000 --- a/src/main/java/com/lycoon/clashbot/utils/DatabaseUtils.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.lycoon.clashbot.utils; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -public class DatabaseUtils -{ - private static final HikariDataSource ds; - - static - { - HikariConfig cfg = new HikariConfig("database.properties"); - ds = new HikariDataSource(cfg); - } - - private DatabaseUtils() {} - - public static Connection getConnection() throws SQLException - { - return ds.getConnection(); - } - - public static String getUserLang(long id) - { - String req = "SELECT lang FROM user WHERE id=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - ResultSet res = statement.executeQuery(); - - statement.close(); - conn.close(); - - if (res.next()) - return res.getString("lang"); - } - catch (SQLException ignored) {} - return "en"; - } - - public static String getPlayerTag(long id) - { - String req = "SELECT player FROM user WHERE id=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - ResultSet res = statement.executeQuery(); - - statement.close(); - conn.close(); - - if (res.next()) - return res.getString("player"); - } - catch (SQLException ignored) {} - return null; - } - - public static String getClanTag(long id) - { - String req = "SELECT clan FROM user WHERE id=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - ResultSet res = statement.executeQuery(); - - statement.close(); - conn.close(); - - if (res.next()) - return res.getString("clan"); - } - catch (SQLException ignored) {} - return null; - } - - public static String getServerPrefix(long id) - { - String req = "SELECT prefix FROM server WHERE id=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - ResultSet res = statement.executeQuery(); - - statement.close(); - conn.close(); - - if (res.next()) - return res.getString("prefix"); - } - catch (SQLException ignored) {} - return "!"; - } - - public static void setUserLang(long id, String lang) - { - String req = "INSERT INTO user(id, lang) VALUES(?, ?) ON DUPLICATE KEY UPDATE lang=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - statement.setString(2, lang); - statement.setString(3, lang); - statement.executeUpdate(); - } - catch (SQLException ignored) {} - } - - public static void setPlayerTag(long id, String playerTag) - { - String req = "INSERT INTO user(id, player) VALUES(?, ?) ON DUPLICATE KEY UPDATE player=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - statement.setString(2, playerTag); - statement.setString(3, playerTag); - statement.executeUpdate(); - } - catch (SQLException ignored) {} - } - - public static void setClanTag(long id, String clanTag) - { - String req = "INSERT INTO user(id, clan) VALUES(?, ?) ON DUPLICATE KEY UPDATE clan=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - statement.setString(2, clanTag); - statement.setString(3, clanTag); - statement.executeUpdate(); - } - catch (SQLException ignored) {} - } - - public static void setServerPrefix(long id, String prefix) - { - String req = "INSERT INTO server(id, prefix) VALUES(?, ?) ON DUPLICATE KEY UPDATE prefix=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - statement.setString(2, prefix); - statement.setString(3, prefix); - statement.executeUpdate(); - } - catch (SQLException ignored) {} - } - - public static void deleteUser(long id) - { - String req = "DELETE FROM user WHERE id=?;"; - try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(req)) - { - statement.setLong(1, id); - statement.executeUpdate(); - } - catch (SQLException ignored) {} - } -} diff --git a/src/main/java/com/lycoon/clashbot/utils/DrawUtils.java b/src/main/java/com/lycoon/clashbot/utils/DrawUtils.java index e28f841..883840d 100644 --- a/src/main/java/com/lycoon/clashbot/utils/DrawUtils.java +++ b/src/main/java/com/lycoon/clashbot/utils/DrawUtils.java @@ -2,13 +2,13 @@ import java.awt.*; import java.awt.font.FontRenderContext; -import java.awt.font.TextAttribute; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; -import java.text.AttributedString; import java.util.Objects; +import static com.lycoon.clashbot.core.ClashBotMain.LOGGER; + public class DrawUtils { private final static Color DEFAULT_COLOR = Color.WHITE; @@ -34,7 +34,7 @@ public static Font getFont(String file) InputStream stream = ClassLoader.getSystemClassLoader().getResourceAsStream("fonts/" + file); font = Font.createFont(Font.TRUETYPE_FONT, Objects.requireNonNull(stream)); } - catch (FontFormatException | IOException e) {e.printStackTrace();} + catch (FontFormatException | IOException e) { LOGGER.error("Error while loading font: " + file, e); } return font; } diff --git a/src/main/java/com/lycoon/clashbot/utils/ErrorUtils.java b/src/main/java/com/lycoon/clashbot/utils/ErrorUtils.java index 2ddc79e..deb01f4 100644 --- a/src/main/java/com/lycoon/clashbot/utils/ErrorUtils.java +++ b/src/main/java/com/lycoon/clashbot/utils/ErrorUtils.java @@ -58,7 +58,8 @@ public static void throwCommandError(MessageChannel channel, ResourceBundle i18n } */ - public static void sendError(SlashCommandInteractionEvent event, String title, String... args) { + public static void sendError(SlashCommandInteractionEvent event, String title, String... args) + { EmbedBuilder error = new EmbedBuilder(); error.setColor(CoreUtils.invalidColor); error.setTitle(title); diff --git a/src/main/java/com/lycoon/clashbot/utils/FileUtils.java b/src/main/java/com/lycoon/clashbot/utils/FileUtils.java index c327c66..1af3280 100644 --- a/src/main/java/com/lycoon/clashbot/utils/FileUtils.java +++ b/src/main/java/com/lycoon/clashbot/utils/FileUtils.java @@ -1,8 +1,8 @@ package com.lycoon.clashbot.utils; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.utils.FileUpload; import static com.lycoon.clashbot.core.ClashBotMain.LOGGER; import static com.lycoon.clashbot.utils.CoreUtils.addUserToGenerating; @@ -40,8 +40,11 @@ public static void sendImage(SlashCommandInteractionEvent event, BufferedImage i removeUserFromGenerating(id); }; - event.getHook().sendFile(bos.toByteArray(), "clashbot.png").queue(sendingCallback); - LOGGER.info("Picture sent to " + event.getMember().getUser().getAsTag() + " on " + event.getGuild().getIdLong()); + + FileUpload file = FileUpload.fromData(bos.toByteArray(), "clashbot.png"); + event.getHook().sendFiles(file).queue(sendingCallback); + + LOGGER.info("Picture sent to " + event.getMember().getUser().getName() + " on " + event.getGuild().getIdLong()); } public static Image getImageFromFile(String file) diff --git a/src/main/java/com/lycoon/clashbot/utils/GameUtils.java b/src/main/java/com/lycoon/clashbot/utils/GameUtils.java index 36340f3..2e037cd 100644 --- a/src/main/java/com/lycoon/clashbot/utils/GameUtils.java +++ b/src/main/java/com/lycoon/clashbot/utils/GameUtils.java @@ -9,19 +9,23 @@ import java.util.Locale; import com.lycoon.clashapi.models.player.Troop; +import com.lycoon.clashapi.models.player.enums.Village; -public class GameUtils { +public class GameUtils +{ public static int getPositive(float value) { return (int) (value * (value < 0 ? -1 : 1)); } - public static String getCurrentSeason(Locale lang) { + public static String getCurrentSeason(Locale lang) + { ZonedDateTime utcDateZoned = ZonedDateTime.now(ZoneId.of("Etc/UTC")); DateTimeFormatter pattern = DateTimeFormatter.ofPattern("MMMM yyyy").withLocale(lang); return utcDateZoned.format(pattern); } - public static int[] getTimeLeft(String toParse) { + public static int[] getTimeLeft(String toParse) + { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSS'Z'"); LocalDateTime endDate = LocalDateTime.parse(toParse, formatter); ZonedDateTime zonedTime = endDate.atZone(ZoneId.of("UTC")); @@ -36,27 +40,27 @@ public static int[] getTimeLeft(String toParse) { return new int[]{getPositive(hours), getPositive(minutes), getPositive(seconds)}; } - public static Troop getTroopByName(List troops, String name) { - for (Troop troop : troops) - if (troop.getName().equals(name)) - return troop; - - return null; + public static Troop getTroopByName(List troops, String name) + { + return troops.stream() + .filter(troop -> troop.getName().equals(name)) + .findFirst() + .orElse(null); } - public static Troop getBuilderTroopByName(List troops, String name) { - for (Troop troop : troops) - if (troop.getVillage().equals("builderBase") && troop.getName().equals(name)) - return troop; - - return null; + public static Troop getBuilderTroopByName(List troops, String name) + { + return troops.stream() + .filter(troop -> troop.getVillage() == Village.BUILDER_BASE && troop.getName().equals(name)) + .findFirst() + .orElse(null); } - public static Troop getHomeTroopByName(List troops, String name) { - for (Troop troop : troops) - if (troop.getVillage().equals("home") && troop.getName().equals(name)) - return troop; - - return null; + public static Troop getHomeTroopByName(List troops, String name) + { + return troops.stream() + .filter(troop -> troop.getVillage() == Village.HOME_VILLAGE && troop.getName().equals(name)) + .findFirst() + .orElse(null); } } diff --git a/src/main/java/com/lycoon/clashbot/utils/database/DatabaseHandler.java b/src/main/java/com/lycoon/clashbot/utils/database/DatabaseHandler.java new file mode 100644 index 0000000..ba5c263 --- /dev/null +++ b/src/main/java/com/lycoon/clashbot/utils/database/DatabaseHandler.java @@ -0,0 +1,71 @@ +package com.lycoon.clashbot.utils.database; + +import com.lycoon.clashbot.core.ClashBotMain; +import com.lycoon.clashbot.utils.database.entities.User; +import jakarta.persistence.EntityNotFoundException; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; + +import java.util.Optional; + +public class DatabaseHandler +{ + private static final StandardServiceRegistry registry; + private static final SessionFactory sessionFactory; + + static + { + registry = new StandardServiceRegistryBuilder().build(); + + try + { + sessionFactory = new MetadataSources(registry) + .addAnnotatedClasses(User.class) + .buildMetadata() + .buildSessionFactory(); + } + catch (Exception e) + { + StandardServiceRegistryBuilder.destroy(registry); + throw new ExceptionInInitializerError(e); + } + } + + protected static Optional getUser(long id) + { + try (Session session = sessionFactory.openSession()) + { + User user = session.get(User.class, id); + return Optional.ofNullable(user); + } + catch (EntityNotFoundException e) { return Optional.empty(); } + catch (Exception e) { ClashBotMain.LOGGER.error(e.getMessage()); return Optional.empty(); } + } + + protected static void saveUser(User user) + { + try (Session session = sessionFactory.openSession()) + { + Transaction transaction = session.beginTransaction(); + session.merge(user); + transaction.commit(); + } + catch (Exception e) { ClashBotMain.LOGGER.error(e.getMessage()); } + } + + protected static void removeUser(long id) + { + try (Session session = sessionFactory.openSession()) + { + Transaction transaction = session.beginTransaction(); + session.remove(new User(id)); + transaction.commit(); + } + catch (EntityNotFoundException ignored) {} + catch (Exception e) { ClashBotMain.LOGGER.error(e.getMessage()); } + } +} diff --git a/src/main/java/com/lycoon/clashbot/utils/database/DatabaseUtils.java b/src/main/java/com/lycoon/clashbot/utils/database/DatabaseUtils.java new file mode 100644 index 0000000..b902de0 --- /dev/null +++ b/src/main/java/com/lycoon/clashbot/utils/database/DatabaseUtils.java @@ -0,0 +1,48 @@ +package com.lycoon.clashbot.utils.database; + +import com.lycoon.clashbot.utils.database.entities.User; +import java.util.Optional; + +public class DatabaseUtils extends DatabaseHandler +{ + public static String getPlayerTag(long id) + { + Optional user = getUser(id); + return user.map(User::getPlayerTag).orElse(null); + } + + public static String getClanTag(long id) + { + Optional user = getUser(id); + return user.map(User::getClanTag).orElse(null); + } + + public static String getUserLang(long id) + { + Optional user = getUser(id); + return user.map(User::getLang).orElse(null); + } + + public static void setUserLang(long id, String lang) + { + User user = new User(id).withLang(lang); + saveUser(user); + } + + public static void setPlayerTag(long id, String playerTag) + { + User user = new User(id).withPlayerTag(playerTag); + saveUser(user); + } + + public static void setClanTag(long id, String clanTag) + { + User user = new User(id).withClanTag(clanTag); + saveUser(user); + } + + public static void deleteUser(long id) + { + removeUser(id); + } +} diff --git a/src/main/java/com/lycoon/clashbot/utils/database/entities/User.java b/src/main/java/com/lycoon/clashbot/utils/database/entities/User.java new file mode 100644 index 0000000..ccdd24a --- /dev/null +++ b/src/main/java/com/lycoon/clashbot/utils/database/entities/User.java @@ -0,0 +1,36 @@ +package com.lycoon.clashbot.utils.database.entities; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "user") +public class User +{ + public User(long id) { this.id = id; } + + @Id + @Column(name = "id") + @Getter @Setter + private Long id; + + @Column(name = "lang") + @Getter @Setter + private String lang; + + @Column(name = "player_tag") + @Getter @Setter + private String playerTag; + + @Column(name = "clan_tag") + @Getter @Setter + private String clanTag; + + public User withLang(String lang) { this.lang = lang; return this; } + public User withPlayerTag(String playerTag) { this.playerTag = playerTag; return this; } + public User withClanTag(String clanTag) { this.clanTag = clanTag; return this; } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml deleted file mode 100644 index 846f8d8..0000000 --- a/src/main/resources/logback.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - %d{dd/MM/yyyy - HH:mm:ss} %boldGreen(%-15.-15logger{0}) %highlight(%-6level) %msg%n - - - - - logs/logs.txt - true - - %d{dd/MM/yyyy - HH:mm:ss} %-15.-15logger{0} %-6level %msg%n - - - - - - - - - \ No newline at end of file