From 7fba5711d1341a042aae028a7c2636b4f10d1b15 Mon Sep 17 00:00:00 2001 From: ChomeNS <95471003+ChomeNS@users.noreply.github.com> Date: Thu, 5 Dec 2024 09:27:48 +0700 Subject: [PATCH] feat,refactor: migrate to jackson and some refactoring/optimizations --- build-number.txt | 2 +- build.gradle | 1 + .../chomens_bot/commands/FilterCommand.java | 53 +++---- .../chomens_bot/commands/FindAltsCommand.java | 18 +-- .../chomens_bot/commands/IPFilterCommand.java | 6 +- .../chomens_bot/commands/MailCommand.java | 132 ++++++++---------- .../chomens_bot/commands/SeenCommand.java | 22 +-- .../chomens_bot/data/FilteredPlayer.java | 10 +- .../me/chayapak1/chomens_bot/data/Mail.java | 26 ++-- .../chomens_bot/plugins/FilterPlugin.java | 36 +++-- .../chomens_bot/plugins/IPFilterPlugin.java | 15 +- .../chomens_bot/plugins/MailPlugin.java | 41 ++++-- .../plugins/PlayersPersistentDataPlugin.java | 67 +++++---- .../chomens_bot/plugins/TeamJoinerPlugin.java | 4 +- .../util/PersistentDataUtilities.java | 56 +++++--- 15 files changed, 269 insertions(+), 220 deletions(-) diff --git a/build-number.txt b/build-number.txt index 5a9264ff..1720e6f2 100644 --- a/build-number.txt +++ b/build-number.txt @@ -1 +1 @@ -1158 \ No newline at end of file +1173 \ No newline at end of file diff --git a/build.gradle b/build.gradle index 53b27bbe..b7aba9d7 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,7 @@ dependencies { implementation 'net.kyori:adventure-text-serializer-ansi:4.15.0' implementation 'com.google.code.gson:gson:2.11.0' implementation 'com.google.guava:guava:31.1-jre' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.2' implementation 'org.jline:jline:3.23.0' implementation 'ch.qos.logback:logback-classic:1.5.11' implementation 'com.github.pircbotx:pircbotx:2.3.1' diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/FilterCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/FilterCommand.java index 74bf2569..1f1d6c70 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/FilterCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/FilterCommand.java @@ -1,7 +1,8 @@ package me.chayapak1.chomens_bot.commands; -import com.google.gson.Gson; -import com.google.gson.JsonElement; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.command.Command; import me.chayapak1.chomens_bot.command.CommandContext; @@ -58,7 +59,7 @@ public class FilterCommand extends Command { } } - final Gson gson = new Gson(); + final ObjectMapper objectMapper = FilterPlugin.objectMapper; switch (action) { case "add" -> { @@ -98,32 +99,36 @@ public class FilterCommand extends Command { final List filtersComponents = new ArrayList<>(); int index = 0; - for (JsonElement playerElement : FilterPlugin.filteredPlayers) { - final FilteredPlayer player = gson.fromJson(playerElement, FilteredPlayer.class); + for (JsonNode playerElement : FilterPlugin.filteredPlayers.deepCopy()) { + try { + final FilteredPlayer player = objectMapper.treeToValue(playerElement, FilteredPlayer.class); - Component options = Component.empty().color(NamedTextColor.DARK_GRAY); + Component options = Component.empty().color(NamedTextColor.DARK_GRAY); - if (player.ignoreCase || player.regex) { - final List args = new ArrayList<>(); + if (player.ignoreCase || player.regex) { + final List args = new ArrayList<>(); - if (player.ignoreCase) args.add(Component.text("ignore case")); - if (player.regex) args.add(Component.text("regex")); + if (player.ignoreCase) args.add(Component.text("ignore case")); + if (player.regex) args.add(Component.text("regex")); - options = options.append(Component.text("(")); - options = options.append(Component.join(JoinConfiguration.commas(true), args).color(ColorUtilities.getColorByString(bot.config.colorPalette.string))); - options = options.append(Component.text(")")); + options = options.append(Component.text("(")); + options = options.append(Component.join(JoinConfiguration.commas(true), args).color(ColorUtilities.getColorByString(bot.config.colorPalette.string))); + options = options.append(Component.text(")")); + } + + filtersComponents.add( + Component.translatable( + "%s › %s %s", + Component.text(index).color(ColorUtilities.getColorByString(bot.config.colorPalette.number)), + Component.text(player.playerName).color(ColorUtilities.getColorByString(bot.config.colorPalette.username)), + options + ).color(NamedTextColor.DARK_GRAY) + ); + + index++; + } catch (JsonProcessingException e) { + e.printStackTrace(); } - - filtersComponents.add( - Component.translatable( - "%s › %s %s", - Component.text(index).color(ColorUtilities.getColorByString(bot.config.colorPalette.number)), - Component.text(player.playerName).color(ColorUtilities.getColorByString(bot.config.colorPalette.username)), - options - ).color(NamedTextColor.DARK_GRAY) - ); - - index++; } return Component.empty() diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/FindAltsCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/FindAltsCommand.java index 4ca3df61..599ea7f4 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/FindAltsCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/FindAltsCommand.java @@ -1,7 +1,7 @@ package me.chayapak1.chomens_bot.commands; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.command.Command; import me.chayapak1.chomens_bot.command.CommandContext; @@ -52,20 +52,20 @@ public class FindAltsCommand extends Command { } private Component handle (Bot bot, String targetIP, boolean argumentIsIP, String player) { - final Stream matches = PlayersPersistentDataPlugin.playersObject.deepCopy().entrySet() // is calling deepCopy necessary? + final Stream matches = PlayersPersistentDataPlugin.playersObject.deepCopy().properties() .stream() .filter( entry -> { - final JsonObject ipsObject = entry - .getValue().getAsJsonObject().getAsJsonObject("ips"); + final ObjectNode ipsObject = (ObjectNode) entry + .getValue().get("ips"); - if (ipsObject == null) return false; + if (ipsObject == null || ipsObject.isNull()) return false; - final JsonElement currentServerIP = ipsObject.get(bot.host + ":" + bot.port); + final JsonNode currentServerIP = ipsObject.get(bot.host + ":" + bot.port); - if (currentServerIP == null) return false; + if (currentServerIP == null || currentServerIP.isNull()) return false; - return currentServerIP.getAsString().equals(targetIP); + return currentServerIP.asText().equals(targetIP); } ) .map(Map.Entry::getKey); diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/IPFilterCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/IPFilterCommand.java index 823fe1d7..791ff606 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/IPFilterCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/IPFilterCommand.java @@ -1,6 +1,6 @@ package me.chayapak1.chomens_bot.commands; -import com.google.gson.JsonElement; +import com.fasterxml.jackson.databind.JsonNode; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.command.Command; import me.chayapak1.chomens_bot.command.CommandContext; @@ -77,12 +77,12 @@ public class IPFilterCommand extends Command { final List filtersComponents = new ArrayList<>(); int index = 0; - for (JsonElement playerElement : IPFilterPlugin.filteredIPs) { + for (JsonNode playerElement : IPFilterPlugin.filteredIPs.deepCopy()) { filtersComponents.add( Component.translatable( "%s › %s", Component.text(index).color(ColorUtilities.getColorByString(bot.config.colorPalette.number)), - Component.text(playerElement.getAsString()).color(ColorUtilities.getColorByString(bot.config.colorPalette.username)) + Component.text(playerElement.asText()).color(ColorUtilities.getColorByString(bot.config.colorPalette.username)) ).color(NamedTextColor.DARK_GRAY) ); diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/MailCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/MailCommand.java index e0757664..606564cc 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/MailCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/MailCommand.java @@ -1,7 +1,8 @@ package me.chayapak1.chomens_bot.commands; -import com.google.gson.Gson; -import com.google.gson.JsonElement; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.command.Command; import me.chayapak1.chomens_bot.command.CommandContext; @@ -21,7 +22,6 @@ import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import java.time.Instant; -import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -47,7 +47,7 @@ public class MailCommand extends Command { final PlayerEntry sender = context.sender; - final Gson gson = new Gson(); + final ObjectMapper objectMapper = MailPlugin.objectMapper; // kinda messy ngl @@ -55,20 +55,6 @@ public class MailCommand extends Command { switch (action) { case "send" -> { - int senderMailsSentTotal = 0; - for (JsonElement mailElement : MailPlugin.mails) { - final Mail mail = gson.fromJson(mailElement, Mail.class); - - if (mail.sentBy == null) continue; - - if (!mail.sentBy.equals(sender.profile.getName())) continue; - senderMailsSentTotal++; - } - - if (senderMailsSentTotal > 256) { - throw new CommandException(Component.text("You are sending too many mails!")); - } - bot.mail.send( new Mail( sender.profile.getName(), @@ -84,18 +70,6 @@ public class MailCommand extends Command { case "sendselecteditem" -> { context.checkOverloadArgs(2); - int senderMailsSentTotal = 0; - for (JsonElement mailElement : MailPlugin.mails) { - final Mail mail = gson.fromJson(mailElement, Mail.class); - - if (!mail.sentTo.equals(sender.profile.getName())) continue; - senderMailsSentTotal++; - } - - if (senderMailsSentTotal > 256) { - throw new CommandException(Component.text("You are sending too many mails!")); - } - final CompletableFuture future = bot.core.runTracked( "minecraft:data get entity " + UUIDUtilities.selector(sender.profile.getId()) + @@ -156,11 +130,15 @@ public class MailCommand extends Command { // TODO: use less for loops? int senderMailSize = 0; - for (JsonElement mailElement : MailPlugin.mails) { - final Mail mail = gson.fromJson(mailElement, Mail.class); + for (JsonNode mailElement : MailPlugin.mails.deepCopy()) { + try { + final Mail mail = objectMapper.treeToValue(mailElement, Mail.class); - if (!mail.sentTo.equals(sender.profile.getName())) continue; - senderMailSize++; + if (!mail.sentTo.equals(sender.profile.getName())) continue; + senderMailSize++; + } catch (JsonProcessingException e) { + e.printStackTrace(); + } } if (senderMailSize == 0) { @@ -169,48 +147,52 @@ public class MailCommand extends Command { final List mailsComponent = new ArrayList<>(); - int i = 1; - for (JsonElement mailElement : MailPlugin.mails) { - final Mail mail = gson.fromJson(mailElement, Mail.class); + int count = 1; + for (JsonNode mailElement : MailPlugin.mails.deepCopy()) { + try { + final Mail mail = objectMapper.treeToValue(mailElement, Mail.class); - if (!mail.sentTo.equals(sender.profile.getName())) continue; + if (!mail.sentTo.equals(sender.profile.getName())) continue; - final Instant instant = Instant.ofEpochMilli(mail.timeSent); - final ZoneId zoneId = ZoneId.systemDefault(); - final OffsetDateTime localDateTime = OffsetDateTime.ofInstant(instant, zoneId); + final Instant instant = Instant.ofEpochMilli(mail.timeSent); + final ZoneId zoneId = ZoneId.systemDefault(); + final OffsetDateTime localDateTime = OffsetDateTime.ofInstant(instant, zoneId); - final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy, hh:mm:ss a Z"); - final String formattedTime = localDateTime.format(formatter); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy, hh:mm:ss a Z"); + final String formattedTime = localDateTime.format(formatter); - mailsComponent.add( - Component.translatable( - """ - %s %s Sent by: %s %s - Contents: - %s""", - Component.text(i).color(ColorUtilities.getColorByString(bot.config.colorPalette.number)), - Component.text("-").color(NamedTextColor.DARK_GRAY), + mailsComponent.add( + Component.translatable( + """ + %s %s Sent by: %s %s + Contents: + %s""", + Component.text(count).color(ColorUtilities.getColorByString(bot.config.colorPalette.number)), + Component.text("-").color(NamedTextColor.DARK_GRAY), - Component.text(mail.sentBy).color(ColorUtilities.getColorByString(bot.config.colorPalette.username)), - Component - .text("[Hover here for more info]") - .color(NamedTextColor.GREEN) - .hoverEvent( - HoverEvent.showText( - Component.translatable( - """ - Time sent: %s - Server: %s""", - Component.text(formattedTime).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)), - Component.text(mail.server).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)) - ).color(NamedTextColor.GREEN) - ) - ), - Component.text(mail.contents).color(NamedTextColor.WHITE) - ).color(NamedTextColor.GREEN) - ); + Component.text(mail.sentBy).color(ColorUtilities.getColorByString(bot.config.colorPalette.username)), + Component + .text("[Hover here for more info]") + .color(NamedTextColor.GREEN) + .hoverEvent( + HoverEvent.showText( + Component.translatable( + """ + Time sent: %s + Server: %s""", + Component.text(formattedTime).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)), + Component.text(mail.server).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)) + ).color(NamedTextColor.GREEN) + ) + ), + Component.text(mail.contents).color(NamedTextColor.WHITE) + ).color(NamedTextColor.GREEN) + ); - i++; + count++; + } catch (JsonProcessingException e) { + e.printStackTrace(); + } } final Component component = Component.empty() @@ -230,10 +212,14 @@ public class MailCommand extends Command { context.sendOutput(component); } - for (JsonElement mailElement : MailPlugin.mails.deepCopy()) { - final Mail mail = gson.fromJson(mailElement, Mail.class); + for (JsonNode mailElement : MailPlugin.mails.deepCopy()) { + try { + final Mail mail = objectMapper.treeToValue(mailElement, Mail.class); - if (mail.sentTo.equals(sender.profile.getName())) MailPlugin.mails.remove(mailElement); + if (mail.sentTo.equals(sender.profile.getName())) bot.mail.remove(mailElement); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } } PersistentDataUtilities.put("mails", MailPlugin.mails); diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/SeenCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/SeenCommand.java index fad77a11..2609b99c 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/SeenCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/SeenCommand.java @@ -1,7 +1,7 @@ package me.chayapak1.chomens_bot.commands; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.command.Command; import me.chayapak1.chomens_bot.command.CommandContext; @@ -13,7 +13,9 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; import net.kyori.adventure.text.format.NamedTextColor; -import java.time.*; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; @@ -56,26 +58,26 @@ public class SeenCommand extends Command { if (online) return Component.join(JoinConfiguration.newlines(), onlineComponents); - final JsonElement playerElement = PlayersPersistentDataPlugin.playersObject.get(player); - if (playerElement == null) throw new CommandException(Component.translatable( + final JsonNode playerElement = PlayersPersistentDataPlugin.playersObject.get(player); + if (playerElement == null || playerElement.isNull()) throw new CommandException(Component.translatable( "%s was never seen", Component.text(player) )); - final JsonObject lastSeen = playerElement.getAsJsonObject().get("lastSeen").getAsJsonObject(); + final ObjectNode lastSeen = (ObjectNode) playerElement.get("lastSeen"); - final JsonElement time = lastSeen.get("time"); + final JsonNode time = lastSeen.get("time"); - if (time == null) throw new CommandException(Component.text("This player does not have the `lastSeen.time` entry in the database for some reason.")); + if (time == null || time.isNull()) throw new CommandException(Component.text("This player does not have the `lastSeen.time` entry in the database for some reason.")); - final Instant instant = Instant.ofEpochMilli(time.getAsLong()); + final Instant instant = Instant.ofEpochMilli(time.asLong()); final ZoneId zoneId = ZoneId.of("UTC"); // should i be doing this? final OffsetDateTime localDateTime = OffsetDateTime.ofInstant(instant, zoneId); final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE, MMMM d, yyyy, hh:mm:ss a Z"); final String formattedTime = localDateTime.format(formatter); - final String server = lastSeen.get("server").getAsString(); + final String server = lastSeen.get("server").asText(); return Component.translatable( "%s was last seen at %s on %s", diff --git a/src/main/java/me/chayapak1/chomens_bot/data/FilteredPlayer.java b/src/main/java/me/chayapak1/chomens_bot/data/FilteredPlayer.java index d3d54154..dedb867c 100644 --- a/src/main/java/me/chayapak1/chomens_bot/data/FilteredPlayer.java +++ b/src/main/java/me/chayapak1/chomens_bot/data/FilteredPlayer.java @@ -1,14 +1,18 @@ package me.chayapak1.chomens_bot.data; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + public class FilteredPlayer { public final String playerName; public final boolean regex; public final boolean ignoreCase; + @JsonCreator public FilteredPlayer ( - String playerName, - boolean regex, - boolean ignoreCase + @JsonProperty("playerName") String playerName, + @JsonProperty("regex") boolean regex, + @JsonProperty("ignoreCase") boolean ignoreCase ) { this.playerName = playerName; this.regex = regex; diff --git a/src/main/java/me/chayapak1/chomens_bot/data/Mail.java b/src/main/java/me/chayapak1/chomens_bot/data/Mail.java index ba3ab3d3..93b63b7e 100644 --- a/src/main/java/me/chayapak1/chomens_bot/data/Mail.java +++ b/src/main/java/me/chayapak1/chomens_bot/data/Mail.java @@ -1,18 +1,22 @@ package me.chayapak1.chomens_bot.data; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + public class Mail { - public final String sentBy; - public final String sentTo; - public final long timeSent; - public final String server; - public final String contents; - + public final String sentBy; + public final String sentTo; + public final long timeSent; + public final String server; + public final String contents; + + @JsonCreator public Mail ( - String sentBy, - String sentTo, - long timeSent, - String server, - String contents + @JsonProperty("sentBy") String sentBy, + @JsonProperty("sentTo") String sentTo, + @JsonProperty("timeSent") long timeSent, + @JsonProperty("server") String server, + @JsonProperty("contents") String contents ) { this.sentBy = sentBy; this.sentTo = sentTo; diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/FilterPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/FilterPlugin.java index f11bd2e6..7fc79ce7 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/FilterPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/FilterPlugin.java @@ -1,8 +1,10 @@ package me.chayapak1.chomens_bot.plugins; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.data.FilteredPlayer; import me.chayapak1.chomens_bot.data.PlayerEntry; @@ -18,11 +20,11 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; public class FilterPlugin extends PlayersPlugin.Listener { + public static final ObjectMapper objectMapper = new ObjectMapper(); + private final Bot bot; - public static JsonArray filteredPlayers = PersistentDataUtilities.getOrDefault("filters", new JsonArray()).getAsJsonArray(); - - private final Gson gson = new Gson(); + public static ArrayNode filteredPlayers = (ArrayNode) PersistentDataUtilities.getOrDefault("filters", JsonNodeFactory.instance.arrayNode()); public FilterPlugin (Bot bot) { this.bot = bot; @@ -49,11 +51,15 @@ public class FilterPlugin extends PlayersPlugin.Listener { } private FilteredPlayer getPlayer (String name) { - for (JsonElement filteredPlayerElement : filteredPlayers) { - final FilteredPlayer filteredPlayer = gson.fromJson(filteredPlayerElement, FilteredPlayer.class); + for (JsonNode filteredPlayerElement : filteredPlayers.deepCopy()) { + try { + final FilteredPlayer filteredPlayer = objectMapper.treeToValue(filteredPlayerElement, FilteredPlayer.class); - if (matchesPlayer(name, filteredPlayer)) { - return filteredPlayer; + if (matchesPlayer(name, filteredPlayer)) { + return filteredPlayer; + } + } catch (JsonProcessingException e) { + e.printStackTrace(); } } @@ -174,7 +180,7 @@ public class FilterPlugin extends PlayersPlugin.Listener { } public void add (String playerName, boolean regex, boolean ignoreCase) { - filteredPlayers.add(gson.fromJson(gson.toJson(new FilteredPlayer(playerName, regex, ignoreCase)), JsonElement.class)); + filteredPlayers.add(objectMapper.valueToTree(new FilteredPlayer(playerName, regex, ignoreCase))); PersistentDataUtilities.put("filters", filteredPlayers); @@ -186,11 +192,15 @@ public class FilterPlugin extends PlayersPlugin.Listener { } public FilteredPlayer remove (int index) { - final JsonElement element = filteredPlayers.remove(index); + final JsonNode element = filteredPlayers.remove(index); PersistentDataUtilities.put("filters", filteredPlayers); - return gson.fromJson(element, FilteredPlayer.class); + try { + return objectMapper.treeToValue(element, FilteredPlayer.class); + } catch (JsonProcessingException e) { + return null; + } } public void clear () { diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/IPFilterPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/IPFilterPlugin.java index 43fb04f8..55debb1e 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/IPFilterPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/IPFilterPlugin.java @@ -1,7 +1,8 @@ package me.chayapak1.chomens_bot.plugins; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.data.PlayerEntry; import me.chayapak1.chomens_bot.util.PersistentDataUtilities; @@ -12,7 +13,7 @@ import java.util.concurrent.TimeUnit; public class IPFilterPlugin extends PlayersPlugin.Listener { private final Bot bot; - public static JsonArray filteredIPs = PersistentDataUtilities.getOrDefault("ipFilters", new JsonArray()).getAsJsonArray(); + public static ArrayNode filteredIPs = (ArrayNode) PersistentDataUtilities.getOrDefault("ipFilters", JsonNodeFactory.instance.arrayNode()); public IPFilterPlugin (Bot bot) { this.bot = bot; @@ -60,11 +61,11 @@ public class IPFilterPlugin extends PlayersPlugin.Listener { } public String remove (int index) { - final JsonElement element = filteredIPs.remove(index); + final JsonNode element = filteredIPs.remove(index); PersistentDataUtilities.put("ipFilters", filteredIPs); - return element.getAsString(); + return element.asText(); } public void clear () { @@ -74,8 +75,8 @@ public class IPFilterPlugin extends PlayersPlugin.Listener { } private void handleIP (String ip, PlayerEntry entry) { - for (JsonElement element : filteredIPs) { - if (!element.getAsString().equals(ip)) continue; + for (JsonNode element : filteredIPs.deepCopy()) { + if (!element.asText().equals(ip)) continue; if (entry.profile.getId().equals(bot.profile.getId())) continue; diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/MailPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/MailPlugin.java index b47b4a70..79f41cd7 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/MailPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/MailPlugin.java @@ -1,8 +1,10 @@ package me.chayapak1.chomens_bot.plugins; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.data.Mail; import me.chayapak1.chomens_bot.data.PlayerEntry; @@ -12,11 +14,11 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; public class MailPlugin extends PlayersPlugin.Listener { + public static final ObjectMapper objectMapper = new ObjectMapper(); + private final Bot bot; - public static JsonArray mails = PersistentDataUtilities.getOrDefault("mails", new JsonArray()).getAsJsonArray(); - - private final Gson gson = new Gson(); + public static ArrayNode mails = (ArrayNode) PersistentDataUtilities.getOrDefault("mails", JsonNodeFactory.instance.arrayNode()); public MailPlugin (Bot bot) { this.bot = bot; @@ -31,14 +33,18 @@ public class MailPlugin extends PlayersPlugin.Listener { int sendToTargetSize = 0; boolean shouldSend = false; - for (JsonElement mailElement : mails) { - final Mail mail = gson.fromJson(mailElement, Mail.class); + for (JsonNode mailNode : mails.deepCopy()) { + try { + final Mail mail = objectMapper.treeToValue(mailNode, Mail.class); - if (!mail.sentTo.equals(name)) continue; + if (!mail.sentTo.equals(name)) continue; - shouldSend = true; + shouldSend = true; - sendToTargetSize++; + sendToTargetSize++; + } catch (JsonProcessingException e) { + e.printStackTrace(); + } } if (shouldSend) { @@ -56,8 +62,19 @@ public class MailPlugin extends PlayersPlugin.Listener { } public void send (Mail mail) { - mails.add(gson.fromJson(gson.toJson(mail), JsonElement.class)); // is this the best way? + mails.add(objectMapper.valueToTree(mail)); PersistentDataUtilities.put("mails", mails); } + + public void remove (JsonNode mail) { + for (int i = 0; i < mails.size(); i++) { + final JsonNode currentNode = mails.get(i); + + if (currentNode.equals(mail)) { + mails.remove(i); + break; + } + } + } } diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/PlayersPersistentDataPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/PlayersPersistentDataPlugin.java index f1238413..547d34f9 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/PlayersPersistentDataPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/PlayersPersistentDataPlugin.java @@ -1,7 +1,8 @@ package me.chayapak1.chomens_bot.plugins; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.data.PlayerEntry; import me.chayapak1.chomens_bot.util.PersistentDataUtilities; @@ -11,7 +12,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class PlayersPersistentDataPlugin extends PlayersPlugin.Listener { - public static JsonObject playersObject = PersistentDataUtilities.getOrDefault("players", new JsonObject()).getAsJsonObject(); + public static ObjectNode playersObject = (ObjectNode) PersistentDataUtilities.getOrDefault("players", JsonNodeFactory.instance.objectNode()); private final Bot bot; @@ -22,42 +23,46 @@ public class PlayersPersistentDataPlugin extends PlayersPlugin.Listener { } @Override - public void playerJoined(PlayerEntry target) { - final JsonElement originalElement = playersObject.get(target.profile.getName()); + public synchronized void playerJoined(PlayerEntry target) { + final JsonNode originalElement = playersObject.get(target.profile.getName()); - JsonObject object; + ObjectNode object; - if (originalElement == null) { - object = new JsonObject(); - object.addProperty("uuid", target.profile.getIdAsString()); - object.add("ips", new JsonObject()); + if (originalElement == null || originalElement.isNull()) { + object = JsonNodeFactory.instance.objectNode(); + object.put("uuid", target.profile.getIdAsString()); + object.set("ips", JsonNodeFactory.instance.objectNode()); + } else if (originalElement instanceof ObjectNode) { + object = (ObjectNode) originalElement; } else { - object = originalElement.getAsJsonObject(); - } - - final CompletableFuture future = bot.players.getPlayerIP(target); - - if (future == null) { - setPersistentEntry(target, object); return; } - future.completeOnTimeout(null, 5, TimeUnit.SECONDS); + bot.executorService.submit(() -> { + final CompletableFuture future = bot.players.getPlayerIP(target); - future.thenApplyAsync(output -> { - if (output != null) { - object.getAsJsonObject("ips").addProperty(bot.host + ":" + bot.port, output); + if (future == null) { + setPersistentEntry(target, object); + return; } - setPersistentEntry(target, object); + future.completeOnTimeout(null, 5, TimeUnit.SECONDS); - return output; + future.thenApplyAsync(output -> { + if (output != null) { + ((ObjectNode) object.get("ips")).put(bot.host + ":" + bot.port, output); + } + + setPersistentEntry(target, object); + + return output; + }); }); } // is this bad? - private void setPersistentEntry (PlayerEntry target, JsonObject object) { - playersObject.add(getName(target), object); + private synchronized void setPersistentEntry (PlayerEntry target, ObjectNode object) { + playersObject.set(getName(target), object); PersistentDataUtilities.put("players", playersObject); } @@ -67,16 +72,16 @@ public class PlayersPersistentDataPlugin extends PlayersPlugin.Listener { } @Override - public void playerLeft(PlayerEntry target) { + public synchronized void playerLeft(PlayerEntry target) { if (!playersObject.has(getName(target))) return; - final JsonObject player = playersObject.get(getName(target)).getAsJsonObject(); + final ObjectNode player = (ObjectNode) playersObject.get(getName(target)); - final JsonObject object = new JsonObject(); - object.addProperty("time", Instant.now().toEpochMilli()); - object.addProperty("server", bot.host + ":" + bot.port); + final ObjectNode object = JsonNodeFactory.instance.objectNode(); + object.put("time", Instant.now().toEpochMilli()); + object.put("server", bot.host + ":" + bot.port); - player.add("lastSeen", object); + player.set("lastSeen", object); PersistentDataUtilities.put("players", playersObject); } diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/TeamJoinerPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/TeamJoinerPlugin.java index 12e319f8..795ff0b6 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/TeamJoinerPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/TeamJoinerPlugin.java @@ -4,6 +4,8 @@ import me.chayapak1.chomens_bot.Bot; import me.chayapak1.chomens_bot.data.Team; import me.chayapak1.chomens_bot.util.UUIDUtilities; +import java.util.ArrayList; + // the name might sound confusing but it just adds the bot into its own team public class TeamJoinerPlugin extends TickPlugin.Listener { public final String teamName; @@ -28,7 +30,7 @@ public class TeamJoinerPlugin extends TickPlugin.Listener { if (!team.players.contains(bot.username)) joinTeam(); - for (String player : team.players) { + for (String player : new ArrayList<>(team.players)) { if (!player.equals(bot.username)) { excludeOthers(); break; diff --git a/src/main/java/me/chayapak1/chomens_bot/util/PersistentDataUtilities.java b/src/main/java/me/chayapak1/chomens_bot/util/PersistentDataUtilities.java index c5001bbb..a1ca9e67 100644 --- a/src/main/java/me/chayapak1/chomens_bot/util/PersistentDataUtilities.java +++ b/src/main/java/me/chayapak1/chomens_bot/util/PersistentDataUtilities.java @@ -1,9 +1,10 @@ package me.chayapak1.chomens_bot.util; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import me.chayapak1.chomens_bot.Main; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -11,17 +12,21 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class PersistentDataUtilities { private static final Path path = Path.of("persistent.json"); - private static final Gson gson = new Gson(); + private static final ObjectMapper objectMapper = new ObjectMapper(); - private static JsonObject jsonObject = new JsonObject(); + private static ObjectNode jsonObject = JsonNodeFactory.instance.objectNode(); private static final ReentrantLock lock = new ReentrantLock(); + private static ScheduledFuture writeFuture; + private static volatile boolean stopping = false; public static void init () { @@ -30,7 +35,7 @@ public class PersistentDataUtilities { try { if (Files.exists(path)) { try (BufferedReader reader = Files.newBufferedReader(path)) { - jsonObject = gson.fromJson(reader, JsonObject.class); + jsonObject = (ObjectNode) objectMapper.readTree(reader); } } else { Files.createFile(path); @@ -40,23 +45,29 @@ public class PersistentDataUtilities { } finally { lock.unlock(); } + + writeFuture = Main.executor.scheduleAtFixedRate(PersistentDataUtilities::writeToFile, 10, 30, TimeUnit.SECONDS); } private static synchronized void writeToFile () { writeToFile(false); } private static synchronized void writeToFile (boolean force) { if (stopping && !force) return; + ObjectNode safeCopy; + lock.lock(); - try (BufferedWriter writer = Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { - final JsonElement copy = jsonObject.deepCopy(); - - writer.write(gson.toJson(copy)); - } catch (Exception e) { - e.printStackTrace(); + try { + safeCopy = jsonObject.deepCopy(); } finally { lock.unlock(); } + + try (BufferedWriter writer = Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + writer.write(objectMapper.writeValueAsString(safeCopy)); + } catch (Exception e) { + e.printStackTrace(); + } } public static synchronized void stop () { @@ -64,6 +75,8 @@ public class PersistentDataUtilities { lock.lock(); + writeFuture.cancel(false); + try { writeToFile(true); } finally { @@ -75,38 +88,37 @@ public class PersistentDataUtilities { return jsonObject.has(property); } - public static synchronized JsonElement get (String property) { + public static synchronized JsonNode get (String property) { return jsonObject.get(property); } - public static synchronized JsonElement getOrDefault (String property, JsonElement defaultElement) { + public static synchronized JsonNode getOrDefault (String property, JsonNode defaultElement) { return has(property) ? get(property) : defaultElement; } - public static synchronized void put (String property, JsonElement value) { + public static synchronized void put (String property, JsonNode value) { lock.lock(); try { - jsonObject.add(property, value); - writeToFile(); + jsonObject.set(property, value); } finally { lock.unlock(); } } public static synchronized void put (String property, String value) { - put(property, new JsonPrimitive(value)); + put(property, JsonNodeFactory.instance.textNode(value)); } public static synchronized void put (String property, boolean value) { - put(property, new JsonPrimitive(value)); + put(property, JsonNodeFactory.instance.booleanNode(value)); } public static synchronized void put (String property, int value) { - put(property, new JsonPrimitive(value)); + put(property, JsonNodeFactory.instance.numberNode(value)); } public static synchronized void put (String property, char value) { - put(property, new JsonPrimitive(value)); + put(property, JsonNodeFactory.instance.textNode(String.valueOf(value))); } }