From 1ba1ee6a50772a0702cb6ba42ba6411828a44899 Mon Sep 17 00:00:00 2001 From: foxikle Date: Wed, 15 May 2024 19:41:04 -0400 Subject: [PATCH 01/55] Update javadocs --- src/main/java/net/cytonic/cytosis/Cytosis.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index ab87fd6b..7cd170b2 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -116,6 +116,12 @@ public static Set getOnlinePlayers() { return players; } + /** + * Gets the player if they are on THIS instance, by username + * + * @param username The username to fetch the player by + * @return The optional holding the player, if it exists. + */ public static Optional getPlayer(String username) { Player target = null; for (Player onlinePlayer : getOnlinePlayers()) @@ -123,6 +129,11 @@ public static Optional getPlayer(String username) { return Optional.ofNullable(target); } + /** + * Gets the player if they are on THIS instance, by UUID + * @param uuid The uuid to fetch the player by + * @return The optional holding the player if they exist + */ public static Optional getPlayer(UUID uuid) { Player target = null; for (Player onlinePlayer : getOnlinePlayers()) { From 1398f0a67b0b8482fe988050b7bbbe53da9175e8 Mon Sep 17 00:00:00 2001 From: foxikle Date: Thu, 16 May 2024 07:12:03 -0400 Subject: [PATCH 02/55] update method name --- src/main/java/net/cytonic/cytosis/Cytosis.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index 7cd170b2..6e647668 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -103,7 +103,7 @@ public static void main(String[] args) { if (CytosisSettings.SERVER_PROXY_MODE) { Logger.info("Enabling velocity!"); VelocityProxy.enable(CytosisSettings.SERVER_SECRET); - } else mojangAuth(); + } else setOnlineMode(); Logger.info("Completing nonessential startup tasks."); completeNonEssentialTasks(start); } @@ -150,7 +150,10 @@ public static void deopPlayer(Player player) { player.removePermission("*"); // remove every permission } - public static void mojangAuth() { + /** + * Initiailizes Mojang authentication, enabling online mode + */ + public static void setOnlineMode() { Logger.info("Initializing Mojang Authentication"); MojangAuth.init(); //VERY IMPORTANT! (This is online mode!) } From 98cca4ef7d27c5c54ca85eacea63436d0b3675cb Mon Sep 17 00:00:00 2001 From: foxikle Date: Mon, 27 May 2024 10:30:00 -0400 Subject: [PATCH 03/55] Delete duplicate class --- .../net/cytonic/cytosis/DatabaseManager.java | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/main/java/net/cytonic/cytosis/DatabaseManager.java diff --git a/src/main/java/net/cytonic/cytosis/DatabaseManager.java b/src/main/java/net/cytonic/cytosis/DatabaseManager.java deleted file mode 100644 index b9cc6a6c..00000000 --- a/src/main/java/net/cytonic/cytosis/DatabaseManager.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.cytonic.cytosis; - -import lombok.Getter; -import net.cytonic.cytosis.data.Database; - -@Getter -public class DatabaseManager { - - private Database database; - - public void shutdown() { - database.disconnect(); - } - - public void setupDatabase() { - database = new Database(); - database.connect(); - database.createTables(); - } -} \ No newline at end of file From eebd88dbdb43c3b060679dd6c2c4a865c721a2e4 Mon Sep 17 00:00:00 2001 From: foxikle Date: Mon, 27 May 2024 10:30:12 -0400 Subject: [PATCH 04/55] Fix access to methods --- src/main/java/net/cytonic/cytosis/logging/Logger.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/logging/Logger.java b/src/main/java/net/cytonic/cytosis/logging/Logger.java index ff8d8841..b7508765 100644 --- a/src/main/java/net/cytonic/cytosis/logging/Logger.java +++ b/src/main/java/net/cytonic/cytosis/logging/Logger.java @@ -13,7 +13,7 @@ static Logger logger() { /** * Debug log entries contain common debug information. */ - static Logger debug() { + private static Logger debug() { return logger().level(Level.DEBUG); } @@ -45,7 +45,7 @@ static Logger setup(Throwable throwable, Object... args) { /** * Info log entries contain important relevant information. */ - static Logger info() { + private static Logger info() { return logger().level(Level.INFO); } @@ -61,7 +61,7 @@ static Logger info(Throwable throwable, Object... args) { /** * Warn log entries contain technical warnings. Typically, warnings do not prevent the application from continuing. */ - static Logger warn() { + private static Logger warn() { return logger().level(Level.WARN); } @@ -77,7 +77,7 @@ static Logger warn(Throwable throwable, Object... args) { /** * Error log entries contain technical errors. Errors WILL stop the application from continuing. */ - static Logger error() { + private static Logger error() { return logger().level(Level.ERROR); } From e3091135ddd67b2b44ae8936510dc560be1cf679 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:48:09 -0400 Subject: [PATCH 05/55] Create command to ban players --- .../cytosis/commands/CommandHandler.java | 3 + .../commands/moderation/BanCommand.java | 101 ++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/commands/moderation/BanCommand.java diff --git a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java index f3b82273..d75e8976 100644 --- a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java +++ b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java @@ -1,6 +1,7 @@ package net.cytonic.cytosis.commands; import net.cytonic.cytosis.Cytosis; +import net.cytonic.cytosis.commands.moderation.BanCommand; import net.minestom.server.command.CommandManager; import net.minestom.server.entity.Player; @@ -23,8 +24,10 @@ public void registerCystosisCommands() { CommandManager cm = Cytosis.getCommandManager(); cm.register(new GamemodeCommand()); cm.register(new RankCommand()); + cm.register(new BanCommand()); } + @SuppressWarnings("UnstableApiUsage") public void recalculateCommands(Player player) { player.sendPacket(Cytosis.getCommandManager().createDeclareCommandsPacket(player)); } diff --git a/src/main/java/net/cytonic/cytosis/commands/moderation/BanCommand.java b/src/main/java/net/cytonic/cytosis/commands/moderation/BanCommand.java new file mode 100644 index 00000000..d5a0de85 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/commands/moderation/BanCommand.java @@ -0,0 +1,101 @@ +package net.cytonic.cytosis.commands.moderation; + +import net.cytonic.cytosis.Cytosis; +import net.cytonic.cytosis.auditlog.Category; +import net.cytonic.cytosis.auditlog.Entry; +import net.cytonic.cytosis.enums.BanReason; +import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.messaging.KickReason; +import net.cytonic.cytosis.utils.BanData; +import net.cytonic.cytosis.utils.DurationParser; +import net.cytonic.cytosis.utils.MessageUtils; +import net.cytonic.cytosis.utils.OfflinePlayer; +import net.minestom.server.command.builder.Command; +import net.minestom.server.command.builder.arguments.ArgumentEnum; +import net.minestom.server.command.builder.arguments.ArgumentType; +import net.minestom.server.command.builder.suggestion.SuggestionEntry; +import net.minestom.server.entity.Player; + +import java.time.Instant; + +import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; + +public class BanCommand extends Command { + public BanCommand() { + super("ban"); + setCondition((sender, _) -> sender.hasPermission("cytosis.commands.moderation.ban")); + + var playerArg = ArgumentType.Word("target"); + System.out.println(playerArg.getSuggestionCallback()); + playerArg.setSuggestionCallback((sender, context, suggestion) -> { + if (sender instanceof Player player) { + player.sendActionBar(MM."Fetching online players..."); + } + Cytosis.getDatabaseManager().getRedisDatabase().getOnlinePlayers().forEach(player -> + suggestion.addEntry(new SuggestionEntry(player))); + }); + var durationArg = ArgumentType.Word("duration"); + var reasonArg = ArgumentType.Enum("reason", BanReason.class).setFormat(ArgumentEnum.Format.LOWER_CASED); + + var group = ArgumentType.Group("ban-group", playerArg, durationArg, reasonArg); + + addSyntax((sender, context) -> { + if (sender instanceof Player actor) { + + if (!actor.hasPermission("cytosis.commands.moderation.ban")) { + actor.sendMessage(MM."You don't have permission to use this command!"); + } + + final String player = context/*.get(group)*/.get(playerArg); + final String reason = context/*.get(group)*/.get(reasonArg).getReason(); + final String rawDur = context/*.get(group)*/.get(durationArg); + final Instant dur = DurationParser.parse(rawDur); + + if (!Cytosis.getDatabaseManager().getRedisDatabase().getOnlinePlayers().contains(player)) { + sender.sendMessage(MM."The player \{context.get(group).getRaw("player")} doesn't exist!"); + return; + } + Cytosis.getDatabaseManager().getMysqlDatabase().findUUIDByName(player).whenComplete((uuid, throwable) -> { + if (throwable != null) { + sender.sendMessage(MM."An error occured whilst finding \{player}!"); + Logger.error("error; ", throwable); + return; + } + Cytosis.getDatabaseManager().getMysqlDatabase().isBanned(uuid).whenComplete((banned, throwable1) -> { + if (throwable1 != null) { + sender.sendMessage(MM."An error occured whilst finding if \{player} is banned!"); + Logger.error("error; ", throwable1); + return; + } + if (banned.isBanned()) { + sender.sendMessage(MM."\{player} is already banned!"); + return; + } + Cytosis.getDatabaseManager().getMysqlDatabase().getPlayerRank(uuid).whenComplete((playerRank, throwable2) -> { + if (throwable2 != null) { + sender.sendMessage(MM."An error occured whilst finding \{player}'s rank!"); + Logger.error("error; ", throwable2); + return; + } + OfflinePlayer op = new OfflinePlayer(player, uuid, playerRank); + if (op.hasPermission("cytosis.moderation.ban_immune")) { + sender.sendMessage(MM."\{player} cannot be banned!"); + return; + } + + Cytosis.getDatabaseManager().getMysqlDatabase().banPlayer(uuid, reason, dur).whenComplete((_, throwable3) -> { + if (throwable3 != null) { + actor.sendMessage(MM."An error occured whilst banning \{player}!"); + return; + } + Cytosis.getMessagingManager().getRabbitMQ().kickPlayer(op, KickReason.BANNED, MessageUtils.formatBanMessage(new BanData(reason, dur, true))); + actor.sendMessage(MM."\{player} was successfully banned for \{DurationParser.unparseFull(dur)}."); + Cytosis.getDatabaseManager().getMysqlDatabase().addAuditLogEntry(new Entry(uuid, actor.getUuid(), Category.BAN, reason)); + }); + }); + }); + }); + } + }, playerArg, durationArg, reasonArg); + } +} From 09fa9d29a9ab7e57eebeae99c27a6c7c1fc06c99 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:48:24 -0400 Subject: [PATCH 06/55] Add redis config options --- src/main/resources/config.toml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index 9859398a..f5fb7003 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -8,7 +8,12 @@ user = "" # Username to connect to the database password = "" # Password to connect to the database use_ssl = false # Whether to use SSL -# server stuff +[redis] +port = 6379 +host = "" +password = "" #No username :) + +# Networking stuff [server] proxy_mode = true secret = "hi i am the secret" # this can NOT be empty From 9b635c515d3fbba89c6da4f7f8fbcf8b846529f0 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:48:32 -0400 Subject: [PATCH 07/55] Delete file --- .../net/cytonic/cytosis/data/Database.java | 177 ------------------ 1 file changed, 177 deletions(-) delete mode 100644 src/main/java/net/cytonic/cytosis/data/Database.java diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java deleted file mode 100644 index f68b7377..00000000 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ /dev/null @@ -1,177 +0,0 @@ -package net.cytonic.cytosis.data; - -import net.cytonic.cytosis.config.CytosisSettings; -import net.cytonic.cytosis.logging.Logger; -import net.cytonic.cytosis.ranks.PlayerRank; -import net.minestom.server.MinecraftServer; -import org.jetbrains.annotations.NotNull; - -import java.sql.*; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class Database { - - private final ExecutorService worker; - private final String host; - private final int port; - private final String database; - private final String username; - private final String password; - private final boolean ssl; - private Connection connection; - - public Database() { - this.worker = Executors.newSingleThreadExecutor(Thread.ofVirtual().name("CytosisDatabaseWorker").uncaughtExceptionHandler((t, e) -> Logger.error(STR."An uncaught exception occoured on the thread: \{t.getName()}", e)).factory()); - this.host = CytosisSettings.DATABASE_HOST; - this.port = CytosisSettings.DATABASE_PORT; - this.database = CytosisSettings.DATABASE_NAME; - this.username = CytosisSettings.DATABASE_USER; - this.password = CytosisSettings.DATABASE_PASSWORD; - this.ssl = CytosisSettings.DATABASE_USE_SSL; - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException e) { - Logger.error("Failed to load database driver", e); - } - } - - public boolean isConnected() { - return (connection != null); - } - - public void connect() { - worker.submit(() -> { - if (!isConnected()) { - try { - connection = DriverManager.getConnection(STR."jdbc:mysql://\{host}:\{port}/\{database}?useSSL=\{ssl}&autoReconnect=true&allowPublicKeyRetrieval=true", username, password); - Logger.info("Successfully connected to the MySQL Database!"); - } catch (SQLException e) { - Logger.error("Invalid Database Credentials!", e); - MinecraftServer.stopCleanly(); - } - } - }); - - } - - public void disconnect() { - worker.submit(() -> { - if (isConnected()) { - try { - connection.close(); - Logger.info("Database connection closed!"); - } catch (SQLException e) { - Logger.error("An error occurred whilst disconnecting from the database. Please report the following stacktrace to Foxikle: ", e); - } - } - }); - } - - public void createTables() { - createRanksTable(); - createChatTable(); - } - - private Connection getConnection() { - return connection; - } - - private void createChatTable() { - worker.submit(() -> { - if (isConnected()) { - PreparedStatement ps; - try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonicchat (id INT NOT NULL AUTO_INCREMENT, timestamp TIMESTAMP, uuid VARCHAR(36), message TEXT, PRIMARY KEY(id))"); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occoured whilst fetching data from the database. Please report the following stacktrace to Foxikle:", e); - } - } - }); - } - - private void createRanksTable() { - worker.submit(() -> { - if (isConnected()) { - PreparedStatement ps; - try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_ranks (uuid VARCHAR(36), rank_id VARCHAR(16), PRIMARY KEY(uuid))"); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occoured whilst creating the `cytonic_ranks` table.", e); - } - } - }); - } - - /** - * Gets the player's rank. This returns {@link PlayerRank#DEFAULT} even if the player doesn't exist. - * - * @param uuid the player to fetch the id from - * @return The player's {@link PlayerRank} - * @throws IllegalStateException if the database isn't connected - */ - @NotNull - public CompletableFuture getPlayerRank(@NotNull final UUID uuid) { - CompletableFuture future = new CompletableFuture<>(); - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to fetch a player's rank!"); - worker.submit(() -> { - String id = "DEFAULT"; - try { - PreparedStatement ps = connection.prepareStatement("SELECT rank_id FROM cytonic_ranks WHERE uuid = ?"); - ps.setString(1, uuid.toString()); - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - id = rs.getString("rank_id"); - } - future.complete(PlayerRank.valueOf(id)); - } catch (SQLException e) { - Logger.error(STR."An error occurred whilst fetching the rank of '\{uuid}'"); - } - }); - return future; - } - - /** - * Sets the given player's rank to the specified rank. - * - * @param uuid The player's UUID - * @param rank The player's rank constant - * @throws IllegalStateException if the database isn't connected - */ - public CompletableFuture setPlayerRank(UUID uuid, PlayerRank rank) { - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to set a player's rank!"); - CompletableFuture future = new CompletableFuture<>(); - worker.submit(() -> { - try { - PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_ranks (uuid, rank_id) VALUES (?, ?) ON DUPLICATE KEY UPDATE rank_id = VALUES(rank_id)"); - ps.setString(1, uuid.toString()); - ps.setString(2, rank.name()); - ps.executeUpdate(); - future.complete(null); - } catch (SQLException e) { - Logger.error(STR."An error occurred whilst setting the rank of '\{uuid}'"); - } - }); - return future; - } - - public void addChat(UUID uuid, String message) { - worker.submit(() -> { - PreparedStatement ps; - try { - ps = connection.prepareStatement("INSERT INTO cytonicchat (timestamp, uuid, message) VALUES (CURRENT_TIMESTAMP,?,?)"); - ps.setString(1, uuid.toString()); - ps.setString(2, message); - ps.executeUpdate(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - }); - } -} \ No newline at end of file From fa168887bc894c6274052b5bc15173d1d798e74c Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:48:44 -0400 Subject: [PATCH 08/55] Create object holding data about a ban --- .../java/net/cytonic/cytosis/utils/BanData.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/utils/BanData.java diff --git a/src/main/java/net/cytonic/cytosis/utils/BanData.java b/src/main/java/net/cytonic/cytosis/utils/BanData.java new file mode 100644 index 00000000..8d738ae4 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/utils/BanData.java @@ -0,0 +1,13 @@ +package net.cytonic.cytosis.utils; + +import org.jetbrains.annotations.Nullable; + +import java.time.Instant; + +public record BanData(@Nullable String reason, @Nullable Instant expiry, boolean isBanned) { + public BanData(@Nullable String reason, @Nullable Instant expiry, boolean isBanned) { + this.reason = reason; + this.expiry = expiry; + this.isBanned = isBanned; + } +} From 5d55741562f7a9187ea7f9b01e9012567ea5411a Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:48:55 -0400 Subject: [PATCH 09/55] Create enum holding ban reasons --- .../net/cytonic/cytosis/enums/BanReason.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/enums/BanReason.java diff --git a/src/main/java/net/cytonic/cytosis/enums/BanReason.java b/src/main/java/net/cytonic/cytosis/enums/BanReason.java new file mode 100644 index 00000000..15554c40 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/enums/BanReason.java @@ -0,0 +1,21 @@ +package net.cytonic.cytosis.enums; + +import lombok.Getter; + +@Getter +public enum BanReason { + CHEATING("Cheating/Hacking"), + INAPROPRIATE_COSMETICS("Using a skin, cape, or other inappropriate cosmetics"), + INAPROPRIATE_BUILDING("Building a structure that violates our terms of service"), + SECURITY("This account is suspended due to security concerns"), + SEVERE_CHAT_INFRACTION("Severe chat infractions"), + EXPLOITING("Exploiting bugs or defects to your advantage"), + SCAMMING("Violating our terms of service by attempting to scam another player"), + ; + + private final String reason; + + BanReason(String reason) { + this.reason = reason; + } +} From 1c6e928f957fcd58b8c930ce104eea680a1f0955 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:49:07 -0400 Subject: [PATCH 10/55] Create audit logging --- .../java/net/cytonic/cytosis/auditlog/Category.java | 10 ++++++++++ src/main/java/net/cytonic/cytosis/auditlog/Entry.java | 6 ++++++ 2 files changed, 16 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/auditlog/Category.java create mode 100644 src/main/java/net/cytonic/cytosis/auditlog/Entry.java diff --git a/src/main/java/net/cytonic/cytosis/auditlog/Category.java b/src/main/java/net/cytonic/cytosis/auditlog/Category.java new file mode 100644 index 00000000..ddf18463 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/auditlog/Category.java @@ -0,0 +1,10 @@ +package net.cytonic.cytosis.auditlog; + +public enum Category { + BAN, + UNBAN, + MUTE, + UNMUTE, + IPBAN, + IPUNBAN +} diff --git a/src/main/java/net/cytonic/cytosis/auditlog/Entry.java b/src/main/java/net/cytonic/cytosis/auditlog/Entry.java new file mode 100644 index 00000000..7fa84615 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/auditlog/Entry.java @@ -0,0 +1,6 @@ +package net.cytonic.cytosis.auditlog; + +import java.util.UUID; + +public record Entry(UUID uuid, UUID actor, Category category, String reason) { +} From 119a3130478aff51721a0830c12a4f3da2405c73 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:49:26 -0400 Subject: [PATCH 11/55] Player caching --- .../net/cytonic/cytosis/CytonicNetwork.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/CytonicNetwork.java diff --git a/src/main/java/net/cytonic/cytosis/CytonicNetwork.java b/src/main/java/net/cytonic/cytosis/CytonicNetwork.java new file mode 100644 index 00000000..b424ef52 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/CytonicNetwork.java @@ -0,0 +1,34 @@ +package net.cytonic.cytosis; + +import lombok.Getter; +import net.cytonic.cytosis.data.RedisDatabase; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * A class that holds data about the status of the Cytonic network + */ +@Getter +public class CytonicNetwork { + private final Set networkPlayers = new HashSet<>(); + private final Set networkPlayerUUIDs = new HashSet<>(); + + public void importDataFromRedis(RedisDatabase redisDatabase) { + networkPlayers.clear(); + networkPlayerUUIDs.clear(); + networkPlayers.addAll(redisDatabase.getOnlinePlayers()); + networkPlayerUUIDs.addAll(redisDatabase.getOnlineUUIDs()); + } + + public void addPlayer(String name, UUID uuid) { + networkPlayers.add(name); + networkPlayerUUIDs.add(uuid); + } + + public void removePlayer(String name, UUID uuid) { + networkPlayers.remove(name); + networkPlayerUUIDs.remove(uuid); + } +} From b899d732587452157aeebb626e8fa463e0d36c91 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:49:53 -0400 Subject: [PATCH 12/55] Update listeners with new functionality --- .../cytosis/events/ServerEventListeners.java | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java index a8bff37d..3f48306b 100644 --- a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java +++ b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java @@ -3,6 +3,8 @@ import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.config.CytosisSettings; import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.messaging.KickReason; +import net.cytonic.cytosis.utils.MessageUtils; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; @@ -10,6 +12,8 @@ import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.event.player.PlayerSpawnEvent; +import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; + public class ServerEventListeners { public static void initServerEvents() { @@ -23,19 +27,33 @@ public static void initServerEvents() { Logger.info("Registering player spawn event."); Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-spawn", false, 1, PlayerSpawnEvent.class, (event -> { - final Player player = event.getPlayer(); - if (CytosisSettings.LOG_PLAYER_IPS) - Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); - else Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined."); + Cytosis.getDatabaseManager().getMysqlDatabase().isBanned(event.getPlayer().getUuid()).whenComplete((data, throwable) -> { + final Player player = event.getPlayer(); + if (throwable != null) { + Logger.error("An error occoured whilst checking if the player is banned!", throwable); + player.kick(MM."An error occured whilst initiating the login sequence!"); + return; + } + + if (data.isBanned()) { + Cytosis.getMessagingManager().getRabbitMQ().kickPlayer(player, KickReason.BANNED, MessageUtils.formatBanMessage(data)); + return; + } + + if (CytosisSettings.LOG_PLAYER_IPS) + Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); + else Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined."); + Cytosis.getDatabaseManager().getMysqlDatabase().addPlayer(player); - Cytosis.getRankManager().addPlayer(player); + Cytosis.getRankManager().addPlayer(player); + }); }))); Logger.info("Registering player chat event."); Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-chat", false, 1, PlayerChatEvent.class, event -> { final Player player = event.getPlayer(); if (CytosisSettings.LOG_PLAYER_CHAT) - Cytosis.getDatabaseManager().getDatabase().addChat(player.getUuid(), event.getMessage()); + Cytosis.getDatabaseManager().getMysqlDatabase().addChat(player.getUuid(), event.getMessage()); })); Logger.info("Registering player disconnect event."); From 06ba6d0691b407b80dc113173cb2bb85c0f40533 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:50:09 -0400 Subject: [PATCH 13/55] Rename to mysql database --- .../cytonic/cytosis/data/MysqlDatabase.java | 372 ++++++++++++++++++ .../cytonic/cytosis/ranks/RankManager.java | 2 +- 2 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/cytonic/cytosis/data/MysqlDatabase.java diff --git a/src/main/java/net/cytonic/cytosis/data/MysqlDatabase.java b/src/main/java/net/cytonic/cytosis/data/MysqlDatabase.java new file mode 100644 index 00000000..28aaac98 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/data/MysqlDatabase.java @@ -0,0 +1,372 @@ +package net.cytonic.cytosis.data; + +import net.cytonic.cytosis.auditlog.Category; +import net.cytonic.cytosis.auditlog.Entry; +import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.ranks.PlayerRank; +import net.cytonic.cytosis.utils.BanData; +import net.minestom.server.MinecraftServer; +import net.minestom.server.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.sql.*; +import java.time.Instant; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class MysqlDatabase { + + private final ExecutorService worker; + private final String host; + private final int port; + private final String database; + private final String username; + private final String password; + private final boolean ssl; + private Connection connection; + + public MysqlDatabase() { + this.worker = Executors.newSingleThreadExecutor(Thread.ofVirtual().name("CytosisDatabaseWorker").uncaughtExceptionHandler((t, e) -> Logger.error(STR."An uncaught exception occoured on the thread: \{t.getName()}", e)).factory()); + this.host = CytosisSettings.DATABASE_HOST; + this.port = CytosisSettings.DATABASE_PORT; + this.database = CytosisSettings.DATABASE_NAME; + this.username = CytosisSettings.DATABASE_USER; + this.password = CytosisSettings.DATABASE_PASSWORD; + this.ssl = CytosisSettings.DATABASE_USE_SSL; + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + Logger.error("Failed to load database driver", e); + } + } + + public boolean isConnected() { + return (connection != null); + } + + public void connect() { + worker.submit(() -> { + if (!isConnected()) { + try { + connection = DriverManager.getConnection(STR."jdbc:mysql://\{host}:\{port}/\{database}?useSSL=\{ssl}&autoReconnect=true&allowPublicKeyRetrieval=true", username, password); + Logger.info("Successfully connected to the MySQL Database!"); + } catch (SQLException e) { + Logger.error("Invalid Database Credentials!", e); + MinecraftServer.stopCleanly(); + } + } + }); + + } + + public void disconnect() { + worker.submit(() -> { + if (isConnected()) { + try { + connection.close(); + Logger.info("Database connection closed!"); + } catch (SQLException e) { + Logger.error("An error occurred whilst disconnecting from the database. Please report the following stacktrace to Foxikle: ", e); + } + } + }); + } + + public void createTables() { + createRanksTable(); + createChatTable(); + createBansTable(); + createAuditLogTable(); + createPlayersTable(); + } + + private Connection getConnection() { + return connection; + } + + private void createChatTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonicchat (id INT NOT NULL AUTO_INCREMENT, timestamp TIMESTAMP, uuid VARCHAR(36), message TEXT, PRIMARY KEY(id))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occoured whilst fetching data from the database. Please report the following stacktrace to Foxikle:", e); + } + } + }); + } + + private void createRanksTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_ranks (uuid VARCHAR(36), rank_id VARCHAR(16), PRIMARY KEY(uuid))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occoured whilst creating the `cytonic_ranks` table.", e); + } + } + }); + } + + private void createBansTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_bans (uuid VARCHAR(36), to_expire VARCHAR(100), reason TINYTEXT, PRIMARY KEY(uuid))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occoured whilst creating the `cytonic_bans` table.", e); + } + } + }); + } + + private void createPlayersTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_players (uuid VARCHAR(36), name VARCHAR(16), PRIMARY KEY(uuid))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occoured whilst creating the `cytonic_players` table.", e); + } + } + }); + } + + /** + * actor is staff

+ * category would be BAN, see {@link Category}

+ * uuid is the player

+ * id and timestamp are handled by mysql

+ */ + private void createAuditLogTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_audit_log (id INT NOT NULL AUTO_INCREMENT, timestamp TIMESTAMP, uuid VARCHAR(36), reason TINYTEXT, category VARCHAR(50), actor VARCHAR(36), PRIMARY KEY(id))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occoured whilst fetching data from the database. Please report the following stacktrace to Foxikle:", e); + } + } + }); + } + + /** + * Gets the player's rank. This returns {@link PlayerRank#DEFAULT} even if the player doesn't exist. + * + * @param uuid the player to fetch the id from + * @return The player's {@link PlayerRank} + * @throws IllegalStateException if the database isn't connected + */ + @NotNull + public CompletableFuture getPlayerRank(@NotNull final UUID uuid) { + CompletableFuture future = new CompletableFuture<>(); + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to fetch a player's rank!"); + worker.submit(() -> { + try { + PreparedStatement ps = connection.prepareStatement("SELECT rank_id FROM cytonic_ranks WHERE uuid = ?"); + ps.setString(1, uuid.toString()); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + future.complete(PlayerRank.valueOf(rs.getString("rank_id"))); + } else { + future.complete(PlayerRank.DEFAULT); + setPlayerRank(uuid, PlayerRank.DEFAULT); + } + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst fetching the rank of '\{uuid}'"); + } + }); + return future; + } + + /** + * Sets the given player's rank to the specified rank. + * + * @param uuid The player's UUID + * @param rank The player's rank constant + * @throws IllegalStateException if the database isn't connected + */ + public CompletableFuture setPlayerRank(UUID uuid, PlayerRank rank) { + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to set a player's rank!"); + CompletableFuture future = new CompletableFuture<>(); + worker.submit(() -> { + try { + PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_ranks (uuid, rank_id) VALUES (?, ?) ON DUPLICATE KEY UPDATE rank_id = VALUES(rank_id)"); + ps.setString(1, uuid.toString()); + ps.setString(2, rank.name()); + ps.executeUpdate(); + future.complete(null); + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst setting the rank of '\{uuid}'"); + } + }); + return future; + } + + public void addChat(UUID uuid, String message) { + worker.submit(() -> { + PreparedStatement ps; + try { + ps = connection.prepareStatement("INSERT INTO cytonicchat (timestamp, uuid, message) VALUES (CURRENT_TIMESTAMP,?,?)"); + ps.setString(1, uuid.toString()); + ps.setString(2, message); + ps.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + }); + } + + public CompletableFuture addAuditLogEntry(Entry entry) { + if (!isConnected()) throw new IllegalStateException("The database must be connected to add an auditlog entry."); + CompletableFuture future = new CompletableFuture<>(); + worker.submit(() -> { + PreparedStatement ps; + try { + ps = connection.prepareStatement("INSERT INTO cytonic_audit_log (timestamp, uuid, reason, category, actor) VALUES (CURRENT_TIMESTAMP,?,?,?,?)"); + ps.setString(1, entry.uuid().toString()); + ps.setString(2, entry.reason()); + ps.setString(3, entry.category().name()); + ps.setString(4, entry.actor().toString()); + ps.executeUpdate(); + future.complete(null); + } catch (SQLException e) { + Logger.error("An error occurred whilst adding an auditlog entry!", e); + future.completeExceptionally(e); + } + }); + return future; + } + + public CompletableFuture banPlayer(UUID uuid, String reason, Instant toExpire) { + CompletableFuture future = new CompletableFuture<>(); + + worker.submit(() -> { + if (!isConnected()) throw new IllegalStateException("The database must be connected to ban players."); + try { + PreparedStatement ps = getConnection().prepareStatement("INSERT IGNORE INTO cytonic_bans (uuid, to_expire, reason) VALUES (?,?,?)"); + ps.setString(1, uuid.toString()); + ps.setString(2, toExpire.toString()); + ps.setString(3, reason); + ps.executeUpdate(); + future.complete(null); + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst banning the player \{uuid}.", e); + future.completeExceptionally(e); + } + }); + + return future; + } + + /** + * The concurrent friendly way to fetch a player's ban status + * + * @param uuid THe player to check + * @return The CompletableFuture that holds the player's ban status + */ + public CompletableFuture isBanned(UUID uuid) { + if (!isConnected()) throw new IllegalStateException("The database must be connected."); + CompletableFuture future = new CompletableFuture<>(); + worker.submit(() -> { + try { + PreparedStatement ps = getConnection().prepareStatement("SELECT * FROM cytonic_bans WHERE uuid = ?"); + ps.setString(1, uuid.toString()); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + Instant expiry = Instant.parse(rs.getString("to_expire")); + if (expiry.isBefore(Instant.now())) { + future.complete(new BanData(null, null, false)); + unbanPlayer(uuid); + } else { + try { + BanData banData = new BanData(rs.getString("reason"), expiry, true); + future.complete(banData); + } catch (Exception e) { + Logger.error(STR."An error occurred whilst determining if the player \{uuid} is banned.", e); + future.complete(new BanData(null, null, true)); + } + } + } else { + future.complete(new BanData(null, null, false)); + } + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst determining if the player \{uuid} is banned.", e); + future.completeExceptionally(e); + } + }); + return future; + } + + public CompletableFuture findUUIDByName(String name) { + if (!isConnected()) throw new IllegalStateException("The database must be connected."); + CompletableFuture future = new CompletableFuture<>(); + worker.submit(() -> { + try { + PreparedStatement ps = getConnection().prepareStatement("SELECT * FROM cytonic_players WHERE name = ?"); + ps.setString(1, name); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + future.complete(UUID.fromString(rs.getString("uuid"))); + } else { + future.completeExceptionally(new IllegalArgumentException(STR."The player '\{name}' doesn't exist!")); + } + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst determining \{name}'s UUID.", e); + future.completeExceptionally(e); + } + }); + return future; + } + + public CompletableFuture addPlayer(Player player) { + if (!isConnected()) throw new IllegalStateException("The database must be connected."); + CompletableFuture future = new CompletableFuture<>(); + worker.submit(() -> { + try { + PreparedStatement ps = getConnection().prepareStatement("INSERT IGNORE INTO cytonic_players (name, uuid) VALUES (?,?) ON DUPLICATE KEY UPDATE name = ?"); + ps.setString(1, player.getUsername()); + ps.setString(2, player.getUuid().toString()); + ps.setString(3, player.getUsername()); + ps.executeUpdate(); + future.complete(null); + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst setting the name of \{player.getUuid().toString()}.", e); + future.completeExceptionally(e); + } + }); + return future; + } + + public CompletableFuture unbanPlayer(UUID uuid) { + if (!isConnected()) throw new IllegalStateException("The database must be connected."); + CompletableFuture future = new CompletableFuture<>(); + worker.submit(() -> { + try { + PreparedStatement ps = getConnection().prepareStatement("DELETE FROM cytonic_bans WHERE uuid = ?"); + ps.setString(1, uuid.toString()); + ps.executeUpdate(); + future.complete(null); + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst unbanning the player \{uuid}.", e); + future.completeExceptionally(e); + } + }); + return future; + } +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/ranks/RankManager.java b/src/main/java/net/cytonic/cytosis/ranks/RankManager.java index 6028c580..f40b6ca4 100644 --- a/src/main/java/net/cytonic/cytosis/ranks/RankManager.java +++ b/src/main/java/net/cytonic/cytosis/ranks/RankManager.java @@ -35,7 +35,7 @@ public void init() { public void addPlayer(Player player) { // cache the rank - Cytosis.getDatabaseManager().getDatabase().getPlayerRank(player.getUuid()).whenComplete((playerRank, throwable) -> { + Cytosis.getDatabaseManager().getMysqlDatabase().getPlayerRank(player.getUuid()).whenComplete((playerRank, throwable) -> { if (throwable != null) { Logger.error(STR."An error occured whilst fetching \{player.getUsername()}'s rank!", throwable); return; From 1dd34070132bec5005bfb1b97a4bbdfb27e16a71 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:50:30 -0400 Subject: [PATCH 14/55] create object with player data --- .../cytonic/cytosis/utils/OfflinePlayer.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/utils/OfflinePlayer.java diff --git a/src/main/java/net/cytonic/cytosis/utils/OfflinePlayer.java b/src/main/java/net/cytonic/cytosis/utils/OfflinePlayer.java new file mode 100644 index 00000000..ce4c24a5 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/utils/OfflinePlayer.java @@ -0,0 +1,21 @@ +package net.cytonic.cytosis.utils; + +import net.cytonic.cytosis.ranks.PlayerRank; +import net.minestom.server.permission.Permission; +import net.minestom.server.permission.PermissionHandler; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public record OfflinePlayer(String name, UUID uuid, PlayerRank rank) implements PermissionHandler { + + @Override + public @NotNull Set getAllPermissions() { + var strings = Set.of(rank.getPermissions()); + Set perms = new HashSet<>(); + strings.forEach(s -> perms.add(new Permission(s))); + return perms; + } +} From 0b004a6f7084c64549f902fc9281734ebf9213ae Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:51:03 -0400 Subject: [PATCH 15/55] Update methods to message more things --- .../cytonic/cytosis/messaging/RabbitMQ.java | 62 ++++++++++++++++++- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index 3f950dcc..32e2495f 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -3,8 +3,14 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.config.CytosisSettings; import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.utils.OfflinePlayer; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; +import net.minestom.server.entity.Player; + import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; @@ -14,6 +20,7 @@ public class RabbitMQ { public static final String SERVER_DECLARE_QUEUE = "server-declaration"; public static final String SHUTDOWN_QUEUE = "server-shutdown"; + public static final String PLAYER_KICK_QUEUE = "player-kick"; private Connection connection; private Channel channel; @@ -49,11 +56,15 @@ public void initializeQueues() { } catch (IOException e) { Logger.error("An error occoured whilst initializing the 'SHUTDOWN_QUEUE'.", e); } + try { + channel.queueDeclare(PLAYER_KICK_QUEUE, false, false, false, null); + } catch (IOException e) { + Logger.error("An error occoured whilst initializing the 'PLAYER_KICK_QUEUE'.", e); + } } public void sendServerDeclarationMessage() { //formatting: {server-name}|:|{server-ip}|:|{server-port} - String serverName = System.getenv("HOSTNAME"); String serverIP; try { serverIP = InetAddress.getLocalHost().getHostAddress(); @@ -61,8 +72,7 @@ public void sendServerDeclarationMessage() { Logger.error("An error occoured whilst fetching this server's IP address! Bailing out!", e); return; } - int port = 25565; - String message = STR."\{serverName}|:|\{serverIP}|:|\{port}"; + String message = STR."\{Cytosis.SERVER_ID}|:|\{serverIP}|:|\{CytosisSettings.SERVER_PORT}"; try { channel.basicPublish("", SERVER_DECLARE_QUEUE, null, message.getBytes()); } catch (IOException e) { @@ -70,4 +80,50 @@ public void sendServerDeclarationMessage() { } Logger.info(STR."Server Declaration message sent! '\{message}'."); } + + public void sendServerShutdownMessage() { + //formatting: {server-name}|:|{server-ip}|:|{server-port} + String serverIP; + try { + serverIP = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + Logger.error("An error occoured whilst fetching this server's IP address! Bailing out!", e); + return; + } + String message = STR."\{Cytosis.SERVER_ID}|:|\{serverIP}|:|\{CytosisSettings.SERVER_PORT}"; + try { + channel.basicPublish("", SHUTDOWN_QUEUE, null, message.getBytes()); + } catch (IOException e) { + Logger.error("An error occoured whilst attempting to send the server declaration message!", e); + } + Logger.info(STR."Server Declaration message sent! '\{message}'."); + } + + public void shutdown() { + try { + connection.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void kickPlayer(Player player, KickReason reason, Component message) { + // FORMAT: {uuid}|:|{reason}|:|{name}|:|{message}|:|{rescuable} + String rawMessage = STR."\{player.getUuid().toString()}|:|\{reason}|:|\{player.getUsername()}|:|\{JSONComponentSerializer.json().serialize(message)}|:|\{reason.isRescuable()}"; + try { + channel.basicPublish("", PLAYER_KICK_QUEUE, null, rawMessage.getBytes()); + } catch (IOException e) { + Logger.error(STR."An error occoured whilst attempting to kick the player \{player.getName()}.", e); + } + } + + public void kickPlayer(OfflinePlayer player, KickReason reason, Component message) { + // FORMAT: {uuid}|:|{reason}|:|{name}|:|{message}|:|{rescuable} + String rawMessage = STR."\{player.uuid().toString()}|:|\{reason}|:|\{player.name()}|:|\{JSONComponentSerializer.json().serialize(message)}|:|\{reason.isRescuable()}"; + try { + channel.basicPublish("", PLAYER_KICK_QUEUE, null, rawMessage.getBytes()); + } catch (IOException e) { + Logger.error(STR."An error occoured whilst attempting to kick the player \{player.name()}.", e); + } + } } \ No newline at end of file From bc646faa58db264975996d99c6bd81751f9542f9 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:51:25 -0400 Subject: [PATCH 16/55] Rename to mysql database --- src/main/java/net/cytonic/cytosis/commands/RankCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/commands/RankCommand.java b/src/main/java/net/cytonic/cytosis/commands/RankCommand.java index 906367f3..ff83961e 100644 --- a/src/main/java/net/cytonic/cytosis/commands/RankCommand.java +++ b/src/main/java/net/cytonic/cytosis/commands/RankCommand.java @@ -48,7 +48,7 @@ public RankCommand() { return; } - Cytosis.getDatabaseManager().getDatabase().getPlayerRank(player.getUuid()).whenComplete((rank, throwable) -> { + Cytosis.getDatabaseManager().getMysqlDatabase().getPlayerRank(player.getUuid()).whenComplete((rank, throwable) -> { if (throwable != null) { sender.sendMessage("An error occured whilst fetching the old rank!"); return; @@ -69,7 +69,7 @@ public RankCommand() { } private void setRank(Player player, PlayerRank rank, CommandSender sender) { - Cytosis.getDatabaseManager().getDatabase().setPlayerRank(player.getUuid(), rank).whenComplete((_, t) -> { + Cytosis.getDatabaseManager().getMysqlDatabase().setPlayerRank(player.getUuid(), rank).whenComplete((_, t) -> { if (t != null) { sender.sendMessage(MM."An error occurred whilst setting \{player.getUsername()}'s rank! Check the console for more details."); Logger.error(STR."An error occurred whilst setting \{player.getUsername()}'s rank! Check the console for more details.", t); From c1fa9539bcfc9210a4f147d0dba673dd9868e361 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:51:39 -0400 Subject: [PATCH 17/55] Add RedisDatabase --- .../cytonic/cytosis/data/DatabaseManager.java | 25 +++++-- .../cytonic/cytosis/data/RedisDatabase.java | 75 +++++++++++++++++++ 2 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 src/main/java/net/cytonic/cytosis/data/RedisDatabase.java diff --git a/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java b/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java index 5c52469d..8cbdb684 100644 --- a/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java +++ b/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java @@ -6,20 +6,31 @@ @Getter public class DatabaseManager { - private Database database; + private MysqlDatabase mysqlDatabase; + private RedisDatabase redisDatabase; public DatabaseManager() { } public void shutdown() { - database.disconnect(); - Logger.info("Good night!"); + mysqlDatabase.disconnect(); + redisDatabase.disconnect(); + Logger.info("Good night!"); } - public void setupDatabase() { - database = new Database(); - database.connect(); - database.createTables(); + public void setupDatabases() { + Logger.info("Connecting to MySQL Database."); + mysqlDatabase = new MysqlDatabase(); + mysqlDatabase.connect(); + mysqlDatabase.createTables(); + + Logger.info("Connecting to the Redis Database."); + try { + redisDatabase = new RedisDatabase(); // it handles itnitialization in the constructor + } catch (Exception ex) { + Logger.error("An error occured!", ex); + } + Logger.info("All databases connected."); } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/data/RedisDatabase.java b/src/main/java/net/cytonic/cytosis/data/RedisDatabase.java new file mode 100644 index 00000000..43b55772 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/data/RedisDatabase.java @@ -0,0 +1,75 @@ +package net.cytonic.cytosis.data; + +import lombok.Getter; +import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.logging.Logger; +import redis.clients.jedis.*; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * A class that holds the connection to the redis cache + */ +public class RedisDatabase extends JedisPubSub { + public static final String ONLINE_PLAYER_NAME_KEY = "online_player_names"; + public static final String ONLINE_PLAYER_UUID_KEY = "online_player_uuids"; + public static final String PLAYER_STATUS_CHANNEL = "player_status"; + public static final String SERVER_SHUTDOWN_KEY = "server_shutdown"; + private final Jedis jedis; + private final ExecutorService worker = Executors.newSingleThreadExecutor(Thread.ofVirtual().name("CytosisRedisWorker").factory()); + @Getter + private final Set onlinePlayers; + @Getter + private final Set onlineUUIDs; + + /** + * Initializes the connection to redis using the loaded settings and the Jedis client + */ + public RedisDatabase() { + HostAndPort hostAndPort = new HostAndPort(CytosisSettings.REDIS_HOST, CytosisSettings.REDIS_PORT); + JedisClientConfig config = DefaultJedisClientConfig.builder().password(CytosisSettings.REDIS_PASSWORD).build(); + this.jedis = new Jedis(hostAndPort, config); + this.jedis.auth(CytosisSettings.REDIS_PASSWORD); + + + onlinePlayers = jedis.smembers(ONLINE_PLAYER_NAME_KEY); + Set uuids = new HashSet<>(); + jedis.smembers(ONLINE_PLAYER_UUID_KEY).forEach(s -> uuids.add(UUID.fromString(s))); + this.onlineUUIDs = uuids; + Logger.info(STR."Loaded \{this.onlineUUIDs.size()} players."); + worker.submit(() -> jedis.subscribe(this, PLAYER_STATUS_CHANNEL)); + } + + public void sendShutdownMessage() { + jedis.set(SERVER_SHUTDOWN_KEY, ""); + } + + + /** + * Consumes messages on the redis pub/sub interface to determine the online players + * + * @param channel The channel that was messaged + * @param message The connent of the message + */ + @Override + public void onMessage(String channel, String message) { + if (!channel.equals(PLAYER_STATUS_CHANNEL)) return; + // |:||:| + String[] parts = message.split("\\|:\\|"); + if (parts[2].equalsIgnoreCase("JOIN")) { + onlinePlayers.add(parts[0]); + onlineUUIDs.add(UUID.fromString(parts[1])); + } else { + onlinePlayers.remove(parts[0]); + onlineUUIDs.remove(UUID.fromString(parts[1])); + } + } + + public void disconnect() { + jedis.disconnect(); + } +} From 8a0753f76efc7d6bc461e597f94f396ded72274a Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:51:56 -0400 Subject: [PATCH 18/55] Create a util class that parses durations and stuff --- .../cytonic/cytosis/utils/DurationParser.java | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/utils/DurationParser.java diff --git a/src/main/java/net/cytonic/cytosis/utils/DurationParser.java b/src/main/java/net/cytonic/cytosis/utils/DurationParser.java new file mode 100644 index 00000000..7d649022 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/utils/DurationParser.java @@ -0,0 +1,129 @@ +package net.cytonic.cytosis.utils; + +import org.jetbrains.annotations.Nullable; + +import java.time.Duration; +import java.time.Instant; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DurationParser { + private static final Pattern PATTERN = Pattern.compile("(\\d+)([ydhms])"); + + /** + * Parses a duration from a string akin to "1y5d6h23m12s" + * `-1` provides a null, representing a permanant value + * + * @param input The string to parse the value from + * @return null if the duration is permanant, returns {@link Instant#now()} if the input doesn't contain any parsable data, or an {@link Instant} with the specified duration from now. + */ + @Nullable + public static Instant parse(String input) { + if (input.equalsIgnoreCase("-1")) return null; + + Matcher matcher = PATTERN.matcher(input); + Duration duration = Duration.ZERO; + + while (matcher.find()) { + long amount = Long.parseLong(matcher.group(1)); + String unit = matcher.group(2); + + duration = switch (unit) { + case "y" -> duration.plusDays(amount * 365); + case "d" -> duration.plusDays(amount); + case "h" -> duration.plusHours(amount); + case "m" -> duration.plusMinutes(amount); + case "s" -> duration.plusSeconds(amount); + default -> duration; + }; + } + + return Instant.now().plus(duration); + } + + /** + * Converts an Instant to a duration string + * + * @param instant The instant to convert to duration string + * @param spacing The spacing between tokens; a spacing of " " would result a string similar to "1y 29d 4h 10m 3s" + * @return The duration string representing the duration from now to the given instant + */ + public static String unparse(@Nullable Instant instant, String spacing) { + if (instant == null) return null; + Duration duration = Duration.between(Instant.now(), instant); + + long years = duration.toDays() / 365; + long days = duration.toDays() % 365; + long hours = duration.toHours() % 24; + long minutes = duration.toMinutes() % 60; + long seconds = duration.getSeconds() % 60; + + StringBuilder builder = new StringBuilder(); + + if (years > 0) { + builder.append(years).append("y").append(spacing); + } + if (days > 0) { + builder.append(days).append("d").append(spacing); + } + if (hours > 0) { + builder.append(hours).append("h").append(spacing); + } + if (minutes > 0) { + builder.append(minutes).append("m").append(spacing); + } + if (seconds > 0) { + builder.append(seconds).append("s").append(spacing); + } + + return builder.toString(); + } + + /** + * Converts an Instant to a duration string with full timeunits written out + * + * @param instant The instant to convert to duration string + * @return The duration string representing the duration from now to the given instant + */ + public static String unparseFull(@Nullable Instant instant) { + if (instant == null) return null; + Duration duration = Duration.between(Instant.now(), instant); + + long years = duration.toDays() / 365; + long days = duration.toDays() % 365; + long hours = duration.toHours() % 24; + long minutes = duration.toMinutes() % 60; + long seconds = duration.getSeconds() % 60; + + StringBuilder builder = new StringBuilder(); + + if (years > 1) { + builder.append(years).append(" Years "); + } else if (years == 1) { + builder.append(years).append(" Year "); + } + if (days > 1) { + builder.append(days).append(" Days "); + } else if (days == 1) { + builder.append(days).append(" Day "); + } + if (hours > 1) { + builder.append(hours).append(" Hours "); + } else if (hours == 1) { + builder.append(hours).append(" Hour "); + } + if (minutes > 1) { + builder.append(minutes).append(" Minutes "); + } else if (minutes == 1) { + builder.append(minutes).append(" Minute "); + } + if (seconds > 1) { + builder.append(seconds).append(" Seconds"); + } else if (seconds == 1) { + builder.append(seconds).append(" Second"); + } + + + return builder.toString(); + } +} From f6cd50998a705c3719ef692334c235bf92f93516 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:52:12 -0400 Subject: [PATCH 19/55] Create kick reasons for use later --- .../cytonic/cytosis/messaging/KickReason.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/messaging/KickReason.java diff --git a/src/main/java/net/cytonic/cytosis/messaging/KickReason.java b/src/main/java/net/cytonic/cytosis/messaging/KickReason.java new file mode 100644 index 00000000..8efe1cbd --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/messaging/KickReason.java @@ -0,0 +1,18 @@ +package net.cytonic.cytosis.messaging; + +import lombok.Getter; + +@Getter +public enum KickReason { + BANNED(false), + INTERNAL_ERROR(true), + INVALID_WORLD(true), + ; + + private final boolean rescuable; + + KickReason(boolean rescuable) { + this.rescuable = rescuable; + } + +} \ No newline at end of file From cb06a7532528b33a3d43843faf47fc5d8954f7fe Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:52:26 -0400 Subject: [PATCH 20/55] Create a class that does message formatting --- .../net/cytonic/cytosis/utils/MessageUtils.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/net/cytonic/cytosis/utils/MessageUtils.java diff --git a/src/main/java/net/cytonic/cytosis/utils/MessageUtils.java b/src/main/java/net/cytonic/cytosis/utils/MessageUtils.java new file mode 100644 index 00000000..e9b1fcc7 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/utils/MessageUtils.java @@ -0,0 +1,17 @@ +package net.cytonic.cytosis.utils; + +import net.kyori.adventure.text.Component; + +public class MessageUtils { + + public static Component formatBanMessage(BanData banData) { + if (!banData.isBanned()) return Component.empty(); + Component finalComp = Component.empty() + .append(MiniMessageTemplate.MM."You are currently banned from the Cytonic Network!".appendNewline().appendNewline()) + .append(MiniMessageTemplate.MM."Reason: \{banData.reason()}".appendNewline()) + .append(MiniMessageTemplate.MM."Expires: \{DurationParser.unparse(banData.expiry(), " ")}".appendNewline().appendNewline()) + .append(MiniMessageTemplate.MM."Appeal at: https://cytonic.net".appendNewline()); + + return finalComp; + } +} From 28f6a208df5bc9c6035ffc0414ae275afce5f764 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:52:40 -0400 Subject: [PATCH 21/55] Publish cytosis to a repo --- build.gradle.kts | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a7529c84..97ed22c0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { + `maven-publish` id("java") id("com.github.johnrengelman.shadow") version "8.1.1" id("com.github.harbby.gradle.serviceloader") version ("1.1.8") @@ -18,7 +19,7 @@ repositories { } dependencies { - implementation("com.github.Minestom", "Minestom", "6b8a4e4cc9") // minstom itself + implementation("com.github.Minestom", "Minestom", "19bb74e") // minstom itself implementation("com.google.code.gson:gson:2.10.1") // serializing implementation("org.slf4j:slf4j-api:2.0.13") // logging implementation("net.kyori:adventure-text-minimessage:4.17.0")// better components @@ -27,6 +28,8 @@ dependencies { annotationProcessor("org.projectlombok:lombok:1.18.32") // lombok implementation("org.tomlj:tomlj:1.1.1") // Config lang implementation("com.rabbitmq:amqp-client:5.21.0") // Message broker + implementation("com.google.guava:guava:33.2.0-jre") // a lot of things, but mostly caching + implementation("redis.clients:jedis:3.7.0") // redis client } tasks.withType { @@ -49,6 +52,28 @@ tasks { } mergeServiceFiles() archiveFileName.set("cytosis.jar") - //destinationDirectory.set(file(providers.gradleProperty("server_dir").get())) + archiveClassifier.set("") + destinationDirectory.set(file("/home/foxikle/cytonicserver/")) + } +} + +publishing { + repositories { + maven { + name = "FoxikleCytonicRepository" + url = uri("https://repo.foxikle.dev/cytonic") + credentials(PasswordCredentials::class) + authentication { + create("basic") + } + } + } + publications { + create("maven") { + groupId = project.group.toString() + artifactId = project.name + version = project.version.toString() + artifact(tasks["shadowJar"]) + } } } \ No newline at end of file From 863a84d5b4c378b34500e9771226bd8f3ccc1573 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:53:21 -0400 Subject: [PATCH 22/55] Update stuff, generate server ids, reformatting --- .../java/net/cytonic/cytosis/Cytosis.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index 6e647668..a3bf331f 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -22,13 +22,14 @@ import net.minestom.server.instance.block.Block; import net.minestom.server.network.ConnectionManager; import net.minestom.server.permission.Permission; +import org.jetbrains.annotations.Nullable; import java.util.*; @Getter public class Cytosis { - + public static final String SERVER_ID = generateID(); // manager stuff @Getter private static MinecraftServer minecraftServer; @@ -54,6 +55,9 @@ public class Cytosis { private static ConsoleSender consoleSender; @Getter private static RankManager rankManager; + @Nullable + @Getter + private static CytonicNetwork cytonicNetwork; private static List FLAGS; @@ -131,6 +135,7 @@ public static Optional getPlayer(String username) { /** * Gets the player if they are on THIS instance, by UUID + * * @param uuid The uuid to fetch the player by * @return The optional holding the player if they exist */ @@ -172,9 +177,12 @@ public static void completeNonEssentialTasks(long start) { ServerEventListeners.initServerEvents(); Logger.info("Initializing database"); - databaseManager.setupDatabase(); + databaseManager.setupDatabases(); - MinecraftServer.getSchedulerManager().buildShutdownTask(() -> databaseManager.shutdown()); + MinecraftServer.getSchedulerManager().buildShutdownTask(() -> { + databaseManager.shutdown(); + messagingManager.shutdown(); + }); Logger.info("Initializing server commands"); commandHandler = new CommandHandler(); @@ -194,10 +202,17 @@ public static void completeNonEssentialTasks(long start) { rankManager = new RankManager(); rankManager.init(); + if (CytosisSettings.SERVER_PROXY_MODE) { + Logger.info("Loading network setup!"); + cytonicNetwork = new CytonicNetwork(); + cytonicNetwork.importDataFromRedis(databaseManager.getRedisDatabase()); + } + + // Start the server Logger.info(STR."Server started on port \{CytosisSettings.SERVER_PORT}"); minecraftServer.start("0.0.0.0", CytosisSettings.SERVER_PORT); - + long end = System.currentTimeMillis(); Logger.info(STR."Server started in \{end - start}ms!"); @@ -206,4 +221,16 @@ public static void completeNonEssentialTasks(long start) { MinecraftServer.stopCleanly(); } } + + private static String generateID() { + //todo: make a check for existing server ids + StringBuilder id = new StringBuilder("Cytosis-"); + Random random = new Random(); + id.append((char) (random.nextInt(26) + 'a')); + for (int i = 0; i < 4; i++) { + id.append(random.nextInt(10)); + } + id.append((char) (random.nextInt(26) + 'a')); + return id.toString(); + } } \ No newline at end of file From 57138c82e55528a60a03bab34b53578a2dca56ea Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:53:34 -0400 Subject: [PATCH 23/55] Add shutdown methods --- .../cytonic/cytosis/messaging/MessagingManager.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java b/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java index 02d60258..1363575c 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java +++ b/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java @@ -1,12 +1,15 @@ package net.cytonic.cytosis.messaging; +import lombok.Getter; import net.cytonic.cytosis.config.CytosisSettings; + import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MessagingManager { + @Getter private final RabbitMQ rabbitMQ; private final ExecutorService worker; @@ -28,4 +31,12 @@ public CompletableFuture initialize() { }); return future; } + + public void shutdown() { + if (rabbitMQ != null) { + rabbitMQ.sendServerShutdownMessage(); + rabbitMQ.shutdown(); + } + worker.shutdown(); + } } \ No newline at end of file From a6a44f7c2b8241d466421166d5c6fd44c1b5b240 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:53:41 -0400 Subject: [PATCH 24/55] Update settings --- .../cytosis/config/CytosisSettings.java | 127 ++++++++++++------ 1 file changed, 88 insertions(+), 39 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java index e2af524b..c7629c59 100644 --- a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java +++ b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java @@ -1,6 +1,7 @@ package net.cytonic.cytosis.config; import net.cytonic.cytosis.logging.Logger; + import java.util.Map; /** @@ -13,6 +14,7 @@ public class CytosisSettings { public static boolean LOG_PLAYER_QUITS = true; public static boolean LOG_PLAYER_COMMANDS = true; public static boolean LOG_PLAYER_CHAT = true; + // Database public static boolean DATABASE_ENABLED = true; public static String DATABASE_USER = ""; @@ -21,10 +23,12 @@ public class CytosisSettings { public static int DATABASE_PORT = 3306; public static String DATABASE_NAME = ""; public static boolean DATABASE_USE_SSL = false; + // server public static boolean SERVER_PROXY_MODE = false; public static String SERVER_SECRET = ""; public static int SERVER_PORT = 25565; + // RabbitMQ public static boolean RABBITMQ_ENABLED = false; public static String RABBITMQ_HOST = ""; @@ -32,6 +36,11 @@ public class CytosisSettings { public static String RABBITMQ_USERNAME = ""; public static int RABBITMQ_PORT = 5672; + //Redis + public static int REDIS_PORT = 6379; + public static String REDIS_HOST = ""; + public static String REDIS_PASSWORD = ""; + public static void inportConfig(Map config) { Logger.info("Importing config!"); config.forEach((key, value) -> { @@ -65,6 +74,11 @@ public static void inportConfig(Map config) { case "rabbitmq.port" -> RABBITMQ_PORT = toInt(value); case "rabbitmq.enabled" -> RABBITMQ_ENABLED = (boolean) value; + // Redis + case "redis.port" -> REDIS_PORT = toInt(value); + case "redis.host" -> REDIS_HOST = (String) value; + case "redis.password" -> REDIS_PASSWORD = (String) value; + default -> { /*Do nothing*/ } } } catch (ClassCastException e) { @@ -81,55 +95,90 @@ private static int toInt(Object key) { public static void loadEnvironmentVariables() { Logger.info("Loading environment variables!"); // logging - if (!(System.getenv("LOG_PLAYER_IPS") == null)) CytosisSettings.LOG_PLAYER_IPS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_IPS")); - if (!(System.getenv("LOG_PLAYER_JOINS") == null)) CytosisSettings.LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_JOINS")); - if (!(System.getenv("LOG_PLAYER_QUITS") == null)) CytosisSettings.LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_QUITS")); - if (!(System.getenv("LOG_PLAYER_COMMANDS") == null)) CytosisSettings.LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_COMMANDS")); - if (!(System.getenv("LOG_PLAYER_CHAT") == null)) CytosisSettings.LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getenv("LOG_PLAYER_CHAT")); + if (!(System.getenv("LOG_PLAYER_IPS") == null)) + LOG_PLAYER_IPS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_IPS")); + if (!(System.getenv("LOG_PLAYER_JOINS") == null)) + LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_JOINS")); + if (!(System.getenv("LOG_PLAYER_QUITS") == null)) + LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_QUITS")); + if (!(System.getenv("LOG_PLAYER_COMMANDS") == null)) + LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_COMMANDS")); + if (!(System.getenv("LOG_PLAYER_CHAT") == null)) + LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getenv("LOG_PLAYER_CHAT")); // database - if (!(System.getenv("DATABASE_ENABLED") == null)) CytosisSettings.DATABASE_ENABLED = Boolean.parseBoolean(System.getenv("DATABASE_ENABLED")); - if (!(System.getenv("DATABASE_USER") == null)) CytosisSettings.DATABASE_USER = System.getenv("DATABASE_USER"); - if (!(System.getenv("DATABASE_PASSWORD") == null)) CytosisSettings.DATABASE_PASSWORD = System.getenv("DATABASE_PASSWORD"); - if (!(System.getenv("DATABASE_HOST") == null)) CytosisSettings.DATABASE_HOST = System.getenv("DATABASE_HOST"); - if (!(System.getenv("DATABASE_PORT") == null)) CytosisSettings.DATABASE_PORT = Integer.parseInt((System.getenv("DATABASE_PORT"))); - if (!(System.getenv("DATABASE_NAME") == null)) CytosisSettings.DATABASE_NAME = System.getenv("DATABASE_NAME"); - if (!(System.getenv("DATABASE_USE_SSL") == null)) CytosisSettings.DATABASE_USE_SSL = Boolean.parseBoolean(System.getenv("DATABASE_USE_SSL")); + if (!(System.getenv("DATABASE_ENABLED") == null)) + DATABASE_ENABLED = Boolean.parseBoolean(System.getenv("DATABASE_ENABLED")); + if (!(System.getenv("DATABASE_USER") == null)) DATABASE_USER = System.getenv("DATABASE_USER"); + if (!(System.getenv("DATABASE_PASSWORD") == null)) DATABASE_PASSWORD = System.getenv("DATABASE_PASSWORD"); + if (!(System.getenv("DATABASE_HOST") == null)) DATABASE_HOST = System.getenv("DATABASE_HOST"); + if (!(System.getenv("DATABASE_PORT") == null)) + DATABASE_PORT = Integer.parseInt((System.getenv("DATABASE_PORT"))); + if (!(System.getenv("DATABASE_NAME") == null)) DATABASE_NAME = System.getenv("DATABASE_NAME"); + if (!(System.getenv("DATABASE_USE_SSL") == null)) + DATABASE_USE_SSL = Boolean.parseBoolean(System.getenv("DATABASE_USE_SSL")); //server - if (!(System.getenv("SERVER_PROXY_MODE") == null)) CytosisSettings.SERVER_PROXY_MODE = Boolean.parseBoolean(System.getenv("SERVER_PROXY_MODE")); - if (!(System.getenv("SERVER_SECRET") == null)) CytosisSettings.SERVER_SECRET = System.getenv("SERVER_SECRET"); - if (!(System.getenv("SERVER_PORT") == null)) CytosisSettings.SERVER_PORT = Integer.parseInt(System.getenv("SERVER_PORT")); + if (!(System.getenv("SERVER_PROXY_MODE") == null)) + SERVER_PROXY_MODE = Boolean.parseBoolean(System.getenv("SERVER_PROXY_MODE")); + if (!(System.getenv("SERVER_SECRET") == null)) SERVER_SECRET = System.getenv("SERVER_SECRET"); + if (!(System.getenv("SERVER_PORT") == null)) SERVER_PORT = Integer.parseInt(System.getenv("SERVER_PORT")); // RabbitMQ - if (!(System.getenv("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getenv("RABBITMQ_ENABLED")); - if (!(System.getenv("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getenv("RABBITMQ_HOST"); - if (!(System.getenv("RABBITMQ_PASSWORD") == null)) CytosisSettings.RABBITMQ_PASSWORD = System.getenv("RABBITMQ_PASSWORD"); - if (!(System.getenv("RABBITMQ_USERNAME") == null)) CytosisSettings.RABBITMQ_USERNAME = System.getenv("RABBITMQ_USERNAME"); - if (!(System.getenv("RABBITMQ_PORT") == null)) CytosisSettings.RABBITMQ_PORT = Integer.parseInt(System.getenv("RABBITMQ_PORT")); + if (!(System.getenv("RABBITMQ_ENABLED") == null)) + RABBITMQ_ENABLED = Boolean.parseBoolean(System.getenv("RABBITMQ_ENABLED")); + if (!(System.getenv("RABBITMQ_HOST") == null)) RABBITMQ_HOST = System.getenv("RABBITMQ_HOST"); + if (!(System.getenv("RABBITMQ_PASSWORD") == null)) RABBITMQ_PASSWORD = System.getenv("RABBITMQ_PASSWORD"); + if (!(System.getenv("RABBITMQ_USERNAME") == null)) RABBITMQ_USERNAME = System.getenv("RABBITMQ_USERNAME"); + if (!(System.getenv("RABBITMQ_PORT") == null)) RABBITMQ_PORT = Integer.parseInt(System.getenv("RABBITMQ_PORT")); + + // redis + if (!(System.getenv("REDIS_HOST") == null)) REDIS_HOST = System.getenv("REDIS_HOST"); + if (!(System.getenv("REDIS_PORT") == null)) REDIS_PORT = Integer.parseInt(System.getenv("REDIS_PORT")); + if (!(System.getenv("REDIS_PASSWORD") == null)) REDIS_PASSWORD = System.getenv("REDIS_PASSWORD"); } public static void loadCommandArgs() { Logger.info("Loading command args!"); // logging - if (!(System.getProperty("LOG_PLAYER_IPS") == null)) CytosisSettings.LOG_PLAYER_IPS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_IPS")); - if (!(System.getProperty("LOG_PLAYER_JOINS") == null)) CytosisSettings.LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_JOINS")); - if (!(System.getProperty("LOG_PLAYER_QUITS") == null)) CytosisSettings.LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_QUITS")); - if (!(System.getProperty("LOG_PLAYER_COMMANDS") == null)) CytosisSettings.LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_COMMANDS")); - if (!(System.getProperty("LOG_PLAYER_CHAT") == null)) CytosisSettings.LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_CHAT")); + if (!(System.getProperty("LOG_PLAYER_IPS") == null)) + LOG_PLAYER_IPS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_IPS")); + if (!(System.getProperty("LOG_PLAYER_JOINS") == null)) + LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_JOINS")); + if (!(System.getProperty("LOG_PLAYER_QUITS") == null)) + LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_QUITS")); + if (!(System.getProperty("LOG_PLAYER_COMMANDS") == null)) + LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_COMMANDS")); + if (!(System.getProperty("LOG_PLAYER_CHAT") == null)) + LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_CHAT")); // database - if (!(System.getProperty("DATABASE_USER") == null)) CytosisSettings.DATABASE_USER = System.getProperty("DATABASE_USER"); - if (!(System.getProperty("DATABASE_PASSWORD") == null)) CytosisSettings.DATABASE_PASSWORD = System.getProperty("DATABASE_PASSWORD"); - if (!(System.getProperty("DATABASE_HOST") == null)) CytosisSettings.DATABASE_HOST = System.getProperty("DATABASE_HOST"); - if (!(System.getProperty("DATABASE_PORT") == null)) CytosisSettings.DATABASE_PORT = Integer.parseInt((System.getProperty("DATABASE_PORT"))); - if (!(System.getProperty("DATABASE_NAME") == null)) CytosisSettings.DATABASE_NAME = System.getProperty("DATABASE_NAME"); - if (!(System.getProperty("DATABASE_USE_SSL") == null)) CytosisSettings.DATABASE_USE_SSL = Boolean.parseBoolean(System.getProperty("DATABASE_USE_SSL")); + if (!(System.getProperty("DATABASE_USER") == null)) DATABASE_USER = System.getProperty("DATABASE_USER"); + if (!(System.getProperty("DATABASE_PASSWORD") == null)) + DATABASE_PASSWORD = System.getProperty("DATABASE_PASSWORD"); + if (!(System.getProperty("DATABASE_HOST") == null)) DATABASE_HOST = System.getProperty("DATABASE_HOST"); + if (!(System.getProperty("DATABASE_PORT") == null)) + DATABASE_PORT = Integer.parseInt((System.getProperty("DATABASE_PORT"))); + if (!(System.getProperty("DATABASE_NAME") == null)) DATABASE_NAME = System.getProperty("DATABASE_NAME"); + if (!(System.getProperty("DATABASE_USE_SSL") == null)) + DATABASE_USE_SSL = Boolean.parseBoolean(System.getProperty("DATABASE_USE_SSL")); //server - if (!(System.getProperty("SERVER_PROXY_MODE") == null)) CytosisSettings.SERVER_PROXY_MODE = Boolean.parseBoolean(System.getProperty("SERVER_PROXY_MODE")); - if (!(System.getProperty("SERVER_SECRET") == null)) CytosisSettings.SERVER_SECRET = System.getProperty("SERVER_SECRET"); - if (!(System.getProperty("SERVER_PORT") == null)) CytosisSettings.SERVER_PORT = Integer.parseInt(System.getProperty("SERVER_PORT")); + if (!(System.getProperty("SERVER_PROXY_MODE") == null)) + SERVER_PROXY_MODE = Boolean.parseBoolean(System.getProperty("SERVER_PROXY_MODE")); + if (!(System.getProperty("SERVER_SECRET") == null)) SERVER_SECRET = System.getProperty("SERVER_SECRET"); + if (!(System.getProperty("SERVER_PORT") == null)) + SERVER_PORT = Integer.parseInt(System.getProperty("SERVER_PORT")); // RabbitMQ - if (!(System.getProperty("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getProperty("RABBITMQ_ENABLED")); - if (!(System.getProperty("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getProperty("RABBITMQ_HOST"); - if (!(System.getProperty("RABBITMQ_PASSWORD") == null)) CytosisSettings.RABBITMQ_PASSWORD = System.getProperty("RABBITMQ_PASSWORD"); - if (!(System.getProperty("RABBITMQ_USERNAME") == null)) CytosisSettings.RABBITMQ_USERNAME = System.getProperty("RABBITMQ_USERNAME"); - if (!(System.getProperty("RABBITMQ_PORT") == null)) CytosisSettings.RABBITMQ_PORT = Integer.parseInt(System.getProperty("RABBITMQ_PORT")); + if (!(System.getProperty("RABBITMQ_ENABLED") == null)) + RABBITMQ_ENABLED = Boolean.parseBoolean(System.getProperty("RABBITMQ_ENABLED")); + if (!(System.getProperty("RABBITMQ_HOST") == null)) RABBITMQ_HOST = System.getProperty("RABBITMQ_HOST"); + if (!(System.getProperty("RABBITMQ_PASSWORD") == null)) + RABBITMQ_PASSWORD = System.getProperty("RABBITMQ_PASSWORD"); + if (!(System.getProperty("RABBITMQ_USERNAME") == null)) + RABBITMQ_USERNAME = System.getProperty("RABBITMQ_USERNAME"); + if (!(System.getProperty("RABBITMQ_PORT") == null)) + RABBITMQ_PORT = Integer.parseInt(System.getProperty("RABBITMQ_PORT")); + + // redis + if (!(System.getProperty("REDIS_HOST") == null)) REDIS_HOST = System.getProperty("REDIS_HOST"); + if (!(System.getProperty("REDIS_PORT") == null)) + REDIS_PORT = Integer.parseInt(System.getProperty("REDIS_PORT")); + if (!(System.getProperty("REDIS_PASSWORD") == null)) REDIS_PASSWORD = System.getProperty("REDIS_PASSWORD"); } } \ No newline at end of file From 8878116de2473fe8957d3aa12aa17b2ae996b8c7 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Fri, 10 May 2024 13:20:52 -0500 Subject: [PATCH 25/55] Delete duplicated file and remove lines --- src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java b/src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java index 15783d63..606cf646 100644 --- a/src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java +++ b/src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java @@ -3,7 +3,6 @@ import lombok.Getter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; - import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; /** From b8fa826aee5c4a2ecd0510330c8a3ac593ceb785 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Mon, 13 May 2024 14:05:09 -0500 Subject: [PATCH 26/55] Polar --- build.gradle.kts | 30 +- .../java/net/cytonic/cytosis/Cytosis.java | 85 ++---- .../cytosis/config/CytosisSettings.java | 133 +++------ .../net/cytonic/cytosis/data/Database.java | 259 ++++++++++++++++++ .../cytonic/cytosis/data/DatabaseManager.java | 26 +- .../cytosis/events/ServerEventListeners.java | 35 +-- src/main/resources/config.toml | 1 + 7 files changed, 350 insertions(+), 219 deletions(-) create mode 100644 src/main/java/net/cytonic/cytosis/data/Database.java diff --git a/build.gradle.kts b/build.gradle.kts index 97ed22c0..d00cb870 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - `maven-publish` id("java") id("com.github.johnrengelman.shadow") version "8.1.1" id("com.github.harbby.gradle.serviceloader") version ("1.1.8") @@ -19,7 +18,7 @@ repositories { } dependencies { - implementation("com.github.Minestom", "Minestom", "19bb74e") // minstom itself + implementation("com.github.Minestom", "Minestom", "6b8a4e4cc9") // minstom itself implementation("com.google.code.gson:gson:2.10.1") // serializing implementation("org.slf4j:slf4j-api:2.0.13") // logging implementation("net.kyori:adventure-text-minimessage:4.17.0")// better components @@ -28,8 +27,7 @@ dependencies { annotationProcessor("org.projectlombok:lombok:1.18.32") // lombok implementation("org.tomlj:tomlj:1.1.1") // Config lang implementation("com.rabbitmq:amqp-client:5.21.0") // Message broker - implementation("com.google.guava:guava:33.2.0-jre") // a lot of things, but mostly caching - implementation("redis.clients:jedis:3.7.0") // redis client + implementation("dev.hollowcube:polar:1.8.1") // Polar } tasks.withType { @@ -52,28 +50,6 @@ tasks { } mergeServiceFiles() archiveFileName.set("cytosis.jar") - archiveClassifier.set("") - destinationDirectory.set(file("/home/foxikle/cytonicserver/")) - } -} - -publishing { - repositories { - maven { - name = "FoxikleCytonicRepository" - url = uri("https://repo.foxikle.dev/cytonic") - credentials(PasswordCredentials::class) - authentication { - create("basic") - } - } - } - publications { - create("maven") { - groupId = project.group.toString() - artifactId = project.name - version = project.version.toString() - artifact(tasks["shadowJar"]) - } + //destinationDirectory.set(file(providers.gradleProperty("server_dir").get())) } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index a3bf331f..e87649c5 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -10,6 +10,7 @@ import net.cytonic.cytosis.logging.Logger; import net.cytonic.cytosis.messaging.MessagingManager; import net.cytonic.cytosis.ranks.RankManager; +import net.hollowcube.polar.PolarLoader; import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandManager; import net.minestom.server.command.ConsoleSender; @@ -22,14 +23,11 @@ import net.minestom.server.instance.block.Block; import net.minestom.server.network.ConnectionManager; import net.minestom.server.permission.Permission; -import org.jetbrains.annotations.Nullable; - import java.util.*; - @Getter public class Cytosis { - public static final String SERVER_ID = generateID(); + // manager stuff @Getter private static MinecraftServer minecraftServer; @@ -55,9 +53,6 @@ public class Cytosis { private static ConsoleSender consoleSender; @Getter private static RankManager rankManager; - @Nullable - @Getter - private static CytonicNetwork cytonicNetwork; private static List FLAGS; @@ -76,10 +71,6 @@ public static void main(String[] args) { Logger.info("Starting connection manager."); connectionManager = MinecraftServer.getConnectionManager(); - - Logger.info("Starting manager."); - databaseManager = new DatabaseManager(); - // Commands Logger.info("Starting command manager."); commandManager = MinecraftServer.getCommandManager(); @@ -107,7 +98,7 @@ public static void main(String[] args) { if (CytosisSettings.SERVER_PROXY_MODE) { Logger.info("Enabling velocity!"); VelocityProxy.enable(CytosisSettings.SERVER_SECRET); - } else setOnlineMode(); + } else mojangAuth(); Logger.info("Completing nonessential startup tasks."); completeNonEssentialTasks(start); } @@ -120,12 +111,6 @@ public static Set getOnlinePlayers() { return players; } - /** - * Gets the player if they are on THIS instance, by username - * - * @param username The username to fetch the player by - * @return The optional holding the player, if it exists. - */ public static Optional getPlayer(String username) { Player target = null; for (Player onlinePlayer : getOnlinePlayers()) @@ -133,12 +118,6 @@ public static Optional getPlayer(String username) { return Optional.ofNullable(target); } - /** - * Gets the player if they are on THIS instance, by UUID - * - * @param uuid The uuid to fetch the player by - * @return The optional holding the player if they exist - */ public static Optional getPlayer(UUID uuid) { Player target = null; for (Player onlinePlayer : getOnlinePlayers()) { @@ -155,20 +134,36 @@ public static void deopPlayer(Player player) { player.removePermission("*"); // remove every permission } - /** - * Initiailizes Mojang authentication, enabling online mode - */ - public static void setOnlineMode() { + public static void mojangAuth() { Logger.info("Initializing Mojang Authentication"); MojangAuth.init(); //VERY IMPORTANT! (This is online mode!) } - public static void completeNonEssentialTasks(long start) { - // basic world generator - Logger.info("Generating basic world"); - defaultInstance.setGenerator(unit -> unit.modifier().fillHeight(0, 1, Block.WHITE_STAINED_GLASS)); - defaultInstance.setChunkSupplier(LightingChunk::new); + public static void loadWorld() { + if (CytosisSettings.SERVER_WORLD_NAME.isEmpty()) { + Logger.info("Generating basic world"); + defaultInstance.setGenerator(unit -> unit.modifier().fillHeight(0, 1, Block.WHITE_STAINED_GLASS)); + defaultInstance.setChunkSupplier(LightingChunk::new); + Logger.info("Basic world loaded!"); + return; + } + Logger.info(STR."Loading world '\{CytosisSettings.SERVER_WORLD_NAME}'"); + databaseManager.getDatabase().getWorld(CytosisSettings.SERVER_WORLD_NAME).whenComplete((polarWorld, throwable) -> { + if (throwable != null) { + Logger.error("An error occurred whilst initializing the world!", throwable); + } else { + defaultInstance.setChunkLoader(new PolarLoader(polarWorld)); + defaultInstance.setChunkSupplier(LightingChunk::new); + Logger.info("World loaded!"); + } + }); + } + public static void completeNonEssentialTasks(long start) { + Logger.info("Initializing database"); + databaseManager = new DatabaseManager(); + databaseManager.setupDatabase(); + Logger.info("Database initialized!"); Logger.info("Setting up event handlers"); eventHandler = new EventHandler(MinecraftServer.getGlobalEventHandler()); eventHandler.init(); @@ -176,12 +171,9 @@ public static void completeNonEssentialTasks(long start) { Logger.info("Initializing server events"); ServerEventListeners.initServerEvents(); - Logger.info("Initializing database"); - databaseManager.setupDatabases(); - MinecraftServer.getSchedulerManager().buildShutdownTask(() -> { databaseManager.shutdown(); - messagingManager.shutdown(); + Logger.info("Good night!"); }); Logger.info("Initializing server commands"); @@ -202,13 +194,6 @@ public static void completeNonEssentialTasks(long start) { rankManager = new RankManager(); rankManager.init(); - if (CytosisSettings.SERVER_PROXY_MODE) { - Logger.info("Loading network setup!"); - cytonicNetwork = new CytonicNetwork(); - cytonicNetwork.importDataFromRedis(databaseManager.getRedisDatabase()); - } - - // Start the server Logger.info(STR."Server started on port \{CytosisSettings.SERVER_PORT}"); minecraftServer.start("0.0.0.0", CytosisSettings.SERVER_PORT); @@ -221,16 +206,4 @@ public static void completeNonEssentialTasks(long start) { MinecraftServer.stopCleanly(); } } - - private static String generateID() { - //todo: make a check for existing server ids - StringBuilder id = new StringBuilder("Cytosis-"); - Random random = new Random(); - id.append((char) (random.nextInt(26) + 'a')); - for (int i = 0; i < 4; i++) { - id.append(random.nextInt(10)); - } - id.append((char) (random.nextInt(26) + 'a')); - return id.toString(); - } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java index c7629c59..31e01da0 100644 --- a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java +++ b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java @@ -1,7 +1,7 @@ package net.cytonic.cytosis.config; import net.cytonic.cytosis.logging.Logger; - +import net.minestom.server.coordinate.Pos; import java.util.Map; /** @@ -14,7 +14,6 @@ public class CytosisSettings { public static boolean LOG_PLAYER_QUITS = true; public static boolean LOG_PLAYER_COMMANDS = true; public static boolean LOG_PLAYER_CHAT = true; - // Database public static boolean DATABASE_ENABLED = true; public static String DATABASE_USER = ""; @@ -23,12 +22,12 @@ public class CytosisSettings { public static int DATABASE_PORT = 3306; public static String DATABASE_NAME = ""; public static boolean DATABASE_USE_SSL = false; - // server public static boolean SERVER_PROXY_MODE = false; public static String SERVER_SECRET = ""; public static int SERVER_PORT = 25565; - + public static String SERVER_WORLD_NAME = ""; + public static Pos SERVER_SPAWN_POS = new Pos(0,1,0); // RabbitMQ public static boolean RABBITMQ_ENABLED = false; public static String RABBITMQ_HOST = ""; @@ -36,11 +35,6 @@ public class CytosisSettings { public static String RABBITMQ_USERNAME = ""; public static int RABBITMQ_PORT = 5672; - //Redis - public static int REDIS_PORT = 6379; - public static String REDIS_HOST = ""; - public static String REDIS_PASSWORD = ""; - public static void inportConfig(Map config) { Logger.info("Importing config!"); config.forEach((key, value) -> { @@ -66,6 +60,7 @@ public static void inportConfig(Map config) { case "server.proxy_mode" -> SERVER_PROXY_MODE = (boolean) value; case "server.secret" -> SERVER_SECRET = (String) value; case "server.port" -> SERVER_PORT = toInt(value); + case "server.world_name" -> SERVER_WORLD_NAME = (String) value; // RabbitMQ case "rabbitmq.host" -> RABBITMQ_HOST = (String) value; @@ -74,11 +69,6 @@ public static void inportConfig(Map config) { case "rabbitmq.port" -> RABBITMQ_PORT = toInt(value); case "rabbitmq.enabled" -> RABBITMQ_ENABLED = (boolean) value; - // Redis - case "redis.port" -> REDIS_PORT = toInt(value); - case "redis.host" -> REDIS_HOST = (String) value; - case "redis.password" -> REDIS_PASSWORD = (String) value; - default -> { /*Do nothing*/ } } } catch (ClassCastException e) { @@ -95,90 +85,57 @@ private static int toInt(Object key) { public static void loadEnvironmentVariables() { Logger.info("Loading environment variables!"); // logging - if (!(System.getenv("LOG_PLAYER_IPS") == null)) - LOG_PLAYER_IPS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_IPS")); - if (!(System.getenv("LOG_PLAYER_JOINS") == null)) - LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_JOINS")); - if (!(System.getenv("LOG_PLAYER_QUITS") == null)) - LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_QUITS")); - if (!(System.getenv("LOG_PLAYER_COMMANDS") == null)) - LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_COMMANDS")); - if (!(System.getenv("LOG_PLAYER_CHAT") == null)) - LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getenv("LOG_PLAYER_CHAT")); + if (!(System.getenv("LOG_PLAYER_IPS") == null)) CytosisSettings.LOG_PLAYER_IPS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_IPS")); + if (!(System.getenv("LOG_PLAYER_JOINS") == null)) CytosisSettings.LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_JOINS")); + if (!(System.getenv("LOG_PLAYER_QUITS") == null)) CytosisSettings.LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_QUITS")); + if (!(System.getenv("LOG_PLAYER_COMMANDS") == null)) CytosisSettings.LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_COMMANDS")); + if (!(System.getenv("LOG_PLAYER_CHAT") == null)) CytosisSettings.LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getenv("LOG_PLAYER_CHAT")); // database - if (!(System.getenv("DATABASE_ENABLED") == null)) - DATABASE_ENABLED = Boolean.parseBoolean(System.getenv("DATABASE_ENABLED")); - if (!(System.getenv("DATABASE_USER") == null)) DATABASE_USER = System.getenv("DATABASE_USER"); - if (!(System.getenv("DATABASE_PASSWORD") == null)) DATABASE_PASSWORD = System.getenv("DATABASE_PASSWORD"); - if (!(System.getenv("DATABASE_HOST") == null)) DATABASE_HOST = System.getenv("DATABASE_HOST"); - if (!(System.getenv("DATABASE_PORT") == null)) - DATABASE_PORT = Integer.parseInt((System.getenv("DATABASE_PORT"))); - if (!(System.getenv("DATABASE_NAME") == null)) DATABASE_NAME = System.getenv("DATABASE_NAME"); - if (!(System.getenv("DATABASE_USE_SSL") == null)) - DATABASE_USE_SSL = Boolean.parseBoolean(System.getenv("DATABASE_USE_SSL")); + if (!(System.getenv("DATABASE_ENABLED") == null)) CytosisSettings.DATABASE_ENABLED = Boolean.parseBoolean(System.getenv("DATABASE_ENABLED")); + if (!(System.getenv("DATABASE_USER") == null)) CytosisSettings.DATABASE_USER = System.getenv("DATABASE_USER"); + if (!(System.getenv("DATABASE_PASSWORD") == null)) CytosisSettings.DATABASE_PASSWORD = System.getenv("DATABASE_PASSWORD"); + if (!(System.getenv("DATABASE_HOST") == null)) CytosisSettings.DATABASE_HOST = System.getenv("DATABASE_HOST"); + if (!(System.getenv("DATABASE_PORT") == null)) CytosisSettings.DATABASE_PORT = Integer.parseInt((System.getenv("DATABASE_PORT"))); + if (!(System.getenv("DATABASE_NAME") == null)) CytosisSettings.DATABASE_NAME = System.getenv("DATABASE_NAME"); + if (!(System.getenv("DATABASE_USE_SSL") == null)) CytosisSettings.DATABASE_USE_SSL = Boolean.parseBoolean(System.getenv("DATABASE_USE_SSL")); //server - if (!(System.getenv("SERVER_PROXY_MODE") == null)) - SERVER_PROXY_MODE = Boolean.parseBoolean(System.getenv("SERVER_PROXY_MODE")); - if (!(System.getenv("SERVER_SECRET") == null)) SERVER_SECRET = System.getenv("SERVER_SECRET"); - if (!(System.getenv("SERVER_PORT") == null)) SERVER_PORT = Integer.parseInt(System.getenv("SERVER_PORT")); + if (!(System.getenv("SERVER_PROXY_MODE") == null)) CytosisSettings.SERVER_PROXY_MODE = Boolean.parseBoolean(System.getenv("SERVER_PROXY_MODE")); + if (!(System.getenv("SERVER_SECRET") == null)) CytosisSettings.SERVER_SECRET = System.getenv("SERVER_SECRET"); + if (!(System.getenv("SERVER_PORT") == null)) CytosisSettings.SERVER_PORT = Integer.parseInt(System.getenv("SERVER_PORT")); + if (!(System.getenv("SERVER_WORLD_NAME") == null)) CytosisSettings.SERVER_WORLD_NAME = System.getenv("SERVER_WORLD_NAME"); // RabbitMQ - if (!(System.getenv("RABBITMQ_ENABLED") == null)) - RABBITMQ_ENABLED = Boolean.parseBoolean(System.getenv("RABBITMQ_ENABLED")); - if (!(System.getenv("RABBITMQ_HOST") == null)) RABBITMQ_HOST = System.getenv("RABBITMQ_HOST"); - if (!(System.getenv("RABBITMQ_PASSWORD") == null)) RABBITMQ_PASSWORD = System.getenv("RABBITMQ_PASSWORD"); - if (!(System.getenv("RABBITMQ_USERNAME") == null)) RABBITMQ_USERNAME = System.getenv("RABBITMQ_USERNAME"); - if (!(System.getenv("RABBITMQ_PORT") == null)) RABBITMQ_PORT = Integer.parseInt(System.getenv("RABBITMQ_PORT")); - - // redis - if (!(System.getenv("REDIS_HOST") == null)) REDIS_HOST = System.getenv("REDIS_HOST"); - if (!(System.getenv("REDIS_PORT") == null)) REDIS_PORT = Integer.parseInt(System.getenv("REDIS_PORT")); - if (!(System.getenv("REDIS_PASSWORD") == null)) REDIS_PASSWORD = System.getenv("REDIS_PASSWORD"); + if (!(System.getenv("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getenv("RABBITMQ_ENABLED")); + if (!(System.getenv("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getenv("RABBITMQ_HOST"); + if (!(System.getenv("RABBITMQ_PASSWORD") == null)) CytosisSettings.RABBITMQ_PASSWORD = System.getenv("RABBITMQ_PASSWORD"); + if (!(System.getenv("RABBITMQ_USERNAME") == null)) CytosisSettings.RABBITMQ_USERNAME = System.getenv("RABBITMQ_USERNAME"); + if (!(System.getenv("RABBITMQ_PORT") == null)) CytosisSettings.RABBITMQ_PORT = Integer.parseInt(System.getenv("RABBITMQ_PORT")); } public static void loadCommandArgs() { Logger.info("Loading command args!"); // logging - if (!(System.getProperty("LOG_PLAYER_IPS") == null)) - LOG_PLAYER_IPS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_IPS")); - if (!(System.getProperty("LOG_PLAYER_JOINS") == null)) - LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_JOINS")); - if (!(System.getProperty("LOG_PLAYER_QUITS") == null)) - LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_QUITS")); - if (!(System.getProperty("LOG_PLAYER_COMMANDS") == null)) - LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_COMMANDS")); - if (!(System.getProperty("LOG_PLAYER_CHAT") == null)) - LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_CHAT")); + if (!(System.getProperty("LOG_PLAYER_IPS") == null)) CytosisSettings.LOG_PLAYER_IPS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_IPS")); + if (!(System.getProperty("LOG_PLAYER_JOINS") == null)) CytosisSettings.LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_JOINS")); + if (!(System.getProperty("LOG_PLAYER_QUITS") == null)) CytosisSettings.LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_QUITS")); + if (!(System.getProperty("LOG_PLAYER_COMMANDS") == null)) CytosisSettings.LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_COMMANDS")); + if (!(System.getProperty("LOG_PLAYER_CHAT") == null)) CytosisSettings.LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_CHAT")); // database - if (!(System.getProperty("DATABASE_USER") == null)) DATABASE_USER = System.getProperty("DATABASE_USER"); - if (!(System.getProperty("DATABASE_PASSWORD") == null)) - DATABASE_PASSWORD = System.getProperty("DATABASE_PASSWORD"); - if (!(System.getProperty("DATABASE_HOST") == null)) DATABASE_HOST = System.getProperty("DATABASE_HOST"); - if (!(System.getProperty("DATABASE_PORT") == null)) - DATABASE_PORT = Integer.parseInt((System.getProperty("DATABASE_PORT"))); - if (!(System.getProperty("DATABASE_NAME") == null)) DATABASE_NAME = System.getProperty("DATABASE_NAME"); - if (!(System.getProperty("DATABASE_USE_SSL") == null)) - DATABASE_USE_SSL = Boolean.parseBoolean(System.getProperty("DATABASE_USE_SSL")); + if (!(System.getProperty("DATABASE_USER") == null)) CytosisSettings.DATABASE_USER = System.getProperty("DATABASE_USER"); + if (!(System.getProperty("DATABASE_PASSWORD") == null)) CytosisSettings.DATABASE_PASSWORD = System.getProperty("DATABASE_PASSWORD"); + if (!(System.getProperty("DATABASE_HOST") == null)) CytosisSettings.DATABASE_HOST = System.getProperty("DATABASE_HOST"); + if (!(System.getProperty("DATABASE_PORT") == null)) CytosisSettings.DATABASE_PORT = Integer.parseInt((System.getProperty("DATABASE_PORT"))); + if (!(System.getProperty("DATABASE_NAME") == null)) CytosisSettings.DATABASE_NAME = System.getProperty("DATABASE_NAME"); + if (!(System.getProperty("DATABASE_USE_SSL") == null)) CytosisSettings.DATABASE_USE_SSL = Boolean.parseBoolean(System.getProperty("DATABASE_USE_SSL")); //server - if (!(System.getProperty("SERVER_PROXY_MODE") == null)) - SERVER_PROXY_MODE = Boolean.parseBoolean(System.getProperty("SERVER_PROXY_MODE")); - if (!(System.getProperty("SERVER_SECRET") == null)) SERVER_SECRET = System.getProperty("SERVER_SECRET"); - if (!(System.getProperty("SERVER_PORT") == null)) - SERVER_PORT = Integer.parseInt(System.getProperty("SERVER_PORT")); + if (!(System.getProperty("SERVER_PROXY_MODE") == null)) CytosisSettings.SERVER_PROXY_MODE = Boolean.parseBoolean(System.getProperty("SERVER_PROXY_MODE")); + if (!(System.getProperty("SERVER_SECRET") == null)) CytosisSettings.SERVER_SECRET = System.getProperty("SERVER_SECRET"); + if (!(System.getProperty("SERVER_PORT") == null)) CytosisSettings.SERVER_PORT = Integer.parseInt(System.getProperty("SERVER_PORT")); + if (!(System.getProperty("SERVER_WORLD_NAME") == null)) CytosisSettings.SERVER_WORLD_NAME = System.getProperty("SERVER_WORLD_NAME"); // RabbitMQ - if (!(System.getProperty("RABBITMQ_ENABLED") == null)) - RABBITMQ_ENABLED = Boolean.parseBoolean(System.getProperty("RABBITMQ_ENABLED")); - if (!(System.getProperty("RABBITMQ_HOST") == null)) RABBITMQ_HOST = System.getProperty("RABBITMQ_HOST"); - if (!(System.getProperty("RABBITMQ_PASSWORD") == null)) - RABBITMQ_PASSWORD = System.getProperty("RABBITMQ_PASSWORD"); - if (!(System.getProperty("RABBITMQ_USERNAME") == null)) - RABBITMQ_USERNAME = System.getProperty("RABBITMQ_USERNAME"); - if (!(System.getProperty("RABBITMQ_PORT") == null)) - RABBITMQ_PORT = Integer.parseInt(System.getProperty("RABBITMQ_PORT")); - - // redis - if (!(System.getProperty("REDIS_HOST") == null)) REDIS_HOST = System.getProperty("REDIS_HOST"); - if (!(System.getProperty("REDIS_PORT") == null)) - REDIS_PORT = Integer.parseInt(System.getProperty("REDIS_PORT")); - if (!(System.getProperty("REDIS_PASSWORD") == null)) REDIS_PASSWORD = System.getProperty("REDIS_PASSWORD"); + if (!(System.getProperty("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getProperty("RABBITMQ_ENABLED")); + if (!(System.getProperty("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getProperty("RABBITMQ_HOST"); + if (!(System.getProperty("RABBITMQ_PASSWORD") == null)) CytosisSettings.RABBITMQ_PASSWORD = System.getProperty("RABBITMQ_PASSWORD"); + if (!(System.getProperty("RABBITMQ_USERNAME") == null)) CytosisSettings.RABBITMQ_USERNAME = System.getProperty("RABBITMQ_USERNAME"); + if (!(System.getProperty("RABBITMQ_PORT") == null)) CytosisSettings.RABBITMQ_PORT = Integer.parseInt(System.getProperty("RABBITMQ_PORT")); } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java new file mode 100644 index 00000000..eb73616a --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -0,0 +1,259 @@ +package net.cytonic.cytosis.data; + +import net.cytonic.cytosis.Cytosis; +import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.ranks.PlayerRank; +import net.hollowcube.polar.PolarReader; +import net.hollowcube.polar.PolarWorld; +import net.hollowcube.polar.PolarWriter; +import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; +import org.jetbrains.annotations.NotNull; +import java.sql.*; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class Database { + + private final ExecutorService worker; + private final String host; + private final int port; + private final String database; + private final String username; + private final String password; + private final boolean ssl; + private Connection connection; + + public Database() { + this.worker = Executors.newSingleThreadExecutor(Thread.ofVirtual().name("CytosisDatabaseWorker").uncaughtExceptionHandler((t, e) -> Logger.error(STR."An uncaught exception occoured on the thread: \{t.getName()}", e)).factory()); + this.host = CytosisSettings.DATABASE_HOST; + this.port = CytosisSettings.DATABASE_PORT; + this.database = CytosisSettings.DATABASE_NAME; + this.username = CytosisSettings.DATABASE_USER; + this.password = CytosisSettings.DATABASE_PASSWORD; + this.ssl = CytosisSettings.DATABASE_USE_SSL; + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + Logger.error("Failed to load database driver", e); + } + } + + public boolean isConnected() { + return (connection != null); + } + + public void connect() { + worker.submit(() -> { + if (!isConnected()) { + try { + connection = DriverManager.getConnection(STR."jdbc:mysql://\{host}:\{port}/\{database}?useSSL=\{ssl}&autoReconnect=true&allowPublicKeyRetrieval=true", username, password); + Logger.info("Successfully connected to the MySQL Database!"); + Cytosis.loadWorld(); + } catch (SQLException e) { + Logger.error("Invalid Database Credentials!", e); + MinecraftServer.stopCleanly(); + } + } + }); + + } + + public void disconnect() { + worker.submit(() -> { + if (isConnected()) { + try { + connection.close(); + Logger.info("Database connection closed!"); + } catch (SQLException e) { + Logger.error("An error occurred whilst disconnecting from the database. Please report the following stacktrace to Foxikle: ", e); + } + } + }); + } + + public void createTables() { + createRanksTable(); + createChatTable(); + createWorldTable(); + } + + private Connection getConnection() { + return connection; + } + + private void createChatTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat (id INT NOT NULL AUTO_INCREMENT, timestamp TIMESTAMP, uuid VARCHAR(36), message TEXT, PRIMARY KEY(id))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_chat` table.", e); + } + } + }); + } + + private void createRanksTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_ranks (uuid VARCHAR(36), rank_id VARCHAR(16), PRIMARY KEY(uuid))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_ranks` table.", e); + } + } + }); + } + + public void createWorldTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_worlds (world_name TEXT, world_type TEXT, last_modified TIMESTAMP, world_data MEDIUMBLOB, x DOUBLE, y DOUBLE, z DOUBLE, yaw FLOAT, pitch FLOAT, extra_data varchar(100))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_worlds` table.", e); + } + } + }); + } + + /** + * Gets the player's rank. This returns {@link PlayerRank#DEFAULT} even if the player doesn't exist. + * + * @param uuid the player to fetch the id from + * @return The player's {@link PlayerRank} + * @throws IllegalStateException if the database isn't connected + */ + @NotNull + public CompletableFuture getPlayerRank(@NotNull final UUID uuid) { + CompletableFuture future = new CompletableFuture<>(); + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to fetch a player's rank!"); + worker.submit(() -> { + String id = "DEFAULT"; + try { + PreparedStatement ps = connection.prepareStatement("SELECT rank_id FROM cytonic_ranks WHERE uuid = ?"); + ps.setString(1, uuid.toString()); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + id = rs.getString("rank_id"); + } + future.complete(PlayerRank.valueOf(id)); + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst fetching the rank of '\{uuid}'"); + } + }); + return future; + } + + /** + * Sets the given player's rank to the specified rank. + * + * @param uuid The player's UUID + * @param rank The player's rank constant + * @throws IllegalStateException if the database isn't connected + */ + public CompletableFuture setPlayerRank(UUID uuid, PlayerRank rank) { + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to set a player's rank!"); + CompletableFuture future = new CompletableFuture<>(); + worker.submit(() -> { + try { + PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_ranks (uuid, rank_id) VALUES (?, ?) ON DUPLICATE KEY UPDATE rank_id = VALUES(rank_id)"); + ps.setString(1, uuid.toString()); + ps.setString(2, rank.name()); + ps.executeUpdate(); + future.complete(null); + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst setting the rank of '\{uuid}'"); + future.completeExceptionally(e); + } + }); + return future; + } + + /** + * Adds a players chat message to the database + * + * @param uuid The player's UUID + * @param message The player's message + * @throws IllegalStateException if the database isn't connected + */ + public void addChat(UUID uuid, String message) { + worker.submit(() -> { + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to add a player's chat!"); + PreparedStatement ps; + try { + ps = connection.prepareStatement("INSERT INTO cytonic_chat (timestamp, uuid, message) VALUES (CURRENT_TIMESTAMP,?,?)"); + ps.setString(1, uuid.toString()); + ps.setString(2, message); + ps.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + }); + } + + public CompletableFuture addWorld(String worldName, String worldType, PolarWorld world, Pos spawnPoint) { + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to add a world!"); + CompletableFuture future = new CompletableFuture<>(); + worker.submit(() -> { + try { + PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_worlds (world_name, world_type, last_modified, world_data, x, y, z, yaw, pitch) VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?, ?, ?, ?)"); + ps.setString(1, worldName); + ps.setString(2, worldType); + ps.setBytes(3, PolarWriter.write(world)); + ps.setDouble(4, spawnPoint.x()); + ps.setDouble(5, spawnPoint.y()); + ps.setDouble(6, spawnPoint.z()); + ps.setFloat(7, spawnPoint.yaw()); + ps.setFloat(8, spawnPoint.pitch()); + ps.executeUpdate(); + future.complete(null); + } catch (SQLException e) { + Logger.error("An error occurred whilst adding a world!",e); + future.completeExceptionally(e); + } + }); + return future; + } + + /** + * Gets a world + * + * @param worldName the world to fetch + * @return The player's {@link PolarWorld} + * @throws IllegalStateException if the database isn't connected + */ + public CompletableFuture getWorld(String worldName) { + CompletableFuture future = new CompletableFuture<>(); + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to fetch a world!"); + worker.submit(() -> { + try { + PreparedStatement ps = connection.prepareStatement("SELECT * FROM cytonic_worlds WHERE world_name = ?"); + ps.setString(1, worldName); + ResultSet rs = ps.executeQuery(); + if (rs.next()) future.complete(PolarReader.read(rs.getBytes("world_data"))); + else Logger.error("The result set is empty!"); + CytosisSettings.SERVER_SPAWN_POS = new Pos(rs.getDouble("x"),rs.getDouble("y"),rs.getDouble("z"), (float) rs.getDouble("yaw"), (float) rs.getDouble("pitch")); + } catch (Exception e) { + Logger.error("An error occurred whilst fetching a world!", e); + future.completeExceptionally(e); + } + }); + return future; + } +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java b/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java index 8cbdb684..60fbfaa8 100644 --- a/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java +++ b/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java @@ -1,36 +1,22 @@ package net.cytonic.cytosis.data; import lombok.Getter; -import net.cytonic.cytosis.logging.Logger; @Getter public class DatabaseManager { - private MysqlDatabase mysqlDatabase; - private RedisDatabase redisDatabase; + private Database database; public DatabaseManager() { } public void shutdown() { - mysqlDatabase.disconnect(); - redisDatabase.disconnect(); - Logger.info("Good night!"); + database.disconnect(); } - public void setupDatabases() { - Logger.info("Connecting to MySQL Database."); - mysqlDatabase = new MysqlDatabase(); - mysqlDatabase.connect(); - mysqlDatabase.createTables(); - - Logger.info("Connecting to the Redis Database."); - try { - redisDatabase = new RedisDatabase(); // it handles itnitialization in the constructor - } catch (Exception ex) { - Logger.error("An error occured!", ex); - } - Logger.info("All databases connected."); + public void setupDatabase() { + database = new Database(); + database.connect(); + database.createTables(); } - } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java index 3f48306b..98258b84 100644 --- a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java +++ b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java @@ -3,57 +3,36 @@ import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.config.CytosisSettings; import net.cytonic.cytosis.logging.Logger; -import net.cytonic.cytosis.messaging.KickReason; -import net.cytonic.cytosis.utils.MessageUtils; -import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.PlayerChatEvent; import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.event.player.PlayerSpawnEvent; -import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; - public class ServerEventListeners { public static void initServerEvents() { - Logger.info("Registering player configuration event."); Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-configuration", true, 1, AsyncPlayerConfigurationEvent.class, (event -> { final Player player = event.getPlayer(); event.setSpawningInstance(Cytosis.getDefaultInstance()); - player.setRespawnPoint(new Pos(0, 45, 0)); + player.setRespawnPoint(CytosisSettings.SERVER_SPAWN_POS); }))); Logger.info("Registering player spawn event."); Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-spawn", false, 1, PlayerSpawnEvent.class, (event -> { - Cytosis.getDatabaseManager().getMysqlDatabase().isBanned(event.getPlayer().getUuid()).whenComplete((data, throwable) -> { - final Player player = event.getPlayer(); - if (throwable != null) { - Logger.error("An error occoured whilst checking if the player is banned!", throwable); - player.kick(MM."An error occured whilst initiating the login sequence!"); - return; - } - - if (data.isBanned()) { - Cytosis.getMessagingManager().getRabbitMQ().kickPlayer(player, KickReason.BANNED, MessageUtils.formatBanMessage(data)); - return; - } - - if (CytosisSettings.LOG_PLAYER_IPS) - Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); - else Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined."); - Cytosis.getDatabaseManager().getMysqlDatabase().addPlayer(player); - - Cytosis.getRankManager().addPlayer(player); - }); + final Player player = event.getPlayer(); + if (CytosisSettings.LOG_PLAYER_IPS) + Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); + else Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined."); + Cytosis.getRankManager().addPlayer(player); }))); Logger.info("Registering player chat event."); Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-chat", false, 1, PlayerChatEvent.class, event -> { final Player player = event.getPlayer(); if (CytosisSettings.LOG_PLAYER_CHAT) - Cytosis.getDatabaseManager().getMysqlDatabase().addChat(player.getUuid(), event.getMessage()); + Cytosis.getDatabaseManager().getDatabase().addChat(player.getUuid(), event.getMessage()); })); Logger.info("Registering player disconnect event."); diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index f5fb7003..e1def0e3 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -18,6 +18,7 @@ password = "" #No username :) proxy_mode = true secret = "hi i am the secret" # this can NOT be empty port = 25565 +world_name = "" # Logging Configuration # Enable/disable logging for various player activities From 4a01dfb074aa8c64a6518e3c7fa72bcdb0cfdd64 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Wed, 15 May 2024 09:27:54 -0500 Subject: [PATCH 27/55] Polar --- .../cytosis/commands/CommandHandler.java | 1 - .../cytonic/cytosis/commands/RankCommand.java | 6 +- .../cytosis/config/CytosisSettings.java | 4 + .../net/cytonic/cytosis/data/Database.java | 76 +++++++++++++------ .../cytonic/cytosis/utils/PosSerializer.java | 39 ++++++++++ src/main/resources/config.toml | 1 + 6 files changed, 97 insertions(+), 30 deletions(-) create mode 100644 src/main/java/net/cytonic/cytosis/utils/PosSerializer.java diff --git a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java index d75e8976..b226608b 100644 --- a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java +++ b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java @@ -4,7 +4,6 @@ import net.cytonic.cytosis.commands.moderation.BanCommand; import net.minestom.server.command.CommandManager; import net.minestom.server.entity.Player; - import java.util.Scanner; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; diff --git a/src/main/java/net/cytonic/cytosis/commands/RankCommand.java b/src/main/java/net/cytonic/cytosis/commands/RankCommand.java index ff83961e..4b67c464 100644 --- a/src/main/java/net/cytonic/cytosis/commands/RankCommand.java +++ b/src/main/java/net/cytonic/cytosis/commands/RankCommand.java @@ -9,9 +9,7 @@ import net.minestom.server.command.builder.arguments.ArgumentType; import net.minestom.server.command.builder.suggestion.SuggestionEntry; import net.minestom.server.entity.Player; - import java.util.Locale; - import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; public class RankCommand extends Command { @@ -19,7 +17,7 @@ public class RankCommand extends Command { public RankCommand() { super("rank"); setCondition((sender, _) -> sender.hasPermission("cytosis.commands.rank")); - setDefaultExecutor((sender, _) -> sender.sendMessage(MM."You must specify a valid rank and player!")); + setDefaultExecutor((sender, _) -> sender.sendMessage(MM."You must specify a valid player and rank!")); var rankArg = ArgumentType.Enum("rank", PlayerRank.class).setFormat(ArgumentEnum.Format.LOWER_CASED); rankArg.setCallback((sender, exception) -> sender.sendMessage(STR."The rank \{exception.getInput()} is invalid!")); @@ -50,7 +48,7 @@ public RankCommand() { Cytosis.getDatabaseManager().getMysqlDatabase().getPlayerRank(player.getUuid()).whenComplete((rank, throwable) -> { if (throwable != null) { - sender.sendMessage("An error occured whilst fetching the old rank!"); + sender.sendMessage("An error occurred whilst fetching the old rank!"); return; } diff --git a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java index 31e01da0..9a4aad45 100644 --- a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java +++ b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java @@ -1,6 +1,7 @@ package net.cytonic.cytosis.config; import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.utils.PosSerializer; import net.minestom.server.coordinate.Pos; import java.util.Map; @@ -61,6 +62,7 @@ public static void inportConfig(Map config) { case "server.secret" -> SERVER_SECRET = (String) value; case "server.port" -> SERVER_PORT = toInt(value); case "server.world_name" -> SERVER_WORLD_NAME = (String) value; + case "server.spawn_point" -> SERVER_SPAWN_POS = PosSerializer.deserialize((String) value); // RabbitMQ case "rabbitmq.host" -> RABBITMQ_HOST = (String) value; @@ -103,6 +105,7 @@ public static void loadEnvironmentVariables() { if (!(System.getenv("SERVER_SECRET") == null)) CytosisSettings.SERVER_SECRET = System.getenv("SERVER_SECRET"); if (!(System.getenv("SERVER_PORT") == null)) CytosisSettings.SERVER_PORT = Integer.parseInt(System.getenv("SERVER_PORT")); if (!(System.getenv("SERVER_WORLD_NAME") == null)) CytosisSettings.SERVER_WORLD_NAME = System.getenv("SERVER_WORLD_NAME"); + if (!(System.getenv("SERVER_SPAWN_POINT") == null)) CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(System.getenv("SERVER_SPAWN_POINT")); // RabbitMQ if (!(System.getenv("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getenv("RABBITMQ_ENABLED")); if (!(System.getenv("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getenv("RABBITMQ_HOST"); @@ -131,6 +134,7 @@ public static void loadCommandArgs() { if (!(System.getProperty("SERVER_SECRET") == null)) CytosisSettings.SERVER_SECRET = System.getProperty("SERVER_SECRET"); if (!(System.getProperty("SERVER_PORT") == null)) CytosisSettings.SERVER_PORT = Integer.parseInt(System.getProperty("SERVER_PORT")); if (!(System.getProperty("SERVER_WORLD_NAME") == null)) CytosisSettings.SERVER_WORLD_NAME = System.getProperty("SERVER_WORLD_NAME"); + if (!(System.getProperty("SERVER_SPAWN_POINT") == null)) CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(System.getProperty("SERVER_SPAWN_POINT")); // RabbitMQ if (!(System.getProperty("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getProperty("RABBITMQ_ENABLED")); if (!(System.getProperty("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getProperty("RABBITMQ_HOST"); diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index eb73616a..ae3d9198 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -4,6 +4,7 @@ import net.cytonic.cytosis.config.CytosisSettings; import net.cytonic.cytosis.logging.Logger; import net.cytonic.cytosis.ranks.PlayerRank; +import net.cytonic.cytosis.utils.PosSerializer; import net.hollowcube.polar.PolarReader; import net.hollowcube.polar.PolarWorld; import net.hollowcube.polar.PolarWriter; @@ -85,6 +86,12 @@ private Connection getConnection() { return connection; } + /** + * Creates the 'cytonic_chat' table in the database if it doesn't exist. + * The table contains information about player chat messages. + * + * @throws IllegalStateException if the database connection is not open. + */ private void createChatTable() { worker.submit(() -> { if (isConnected()) { @@ -99,6 +106,12 @@ private void createChatTable() { }); } + /** + * Creates the 'cytonic_ranks' table in the database if it doesn't exist. + * The table contains information about player ranks. + * + * @throws IllegalStateException if the database connection is not open. + */ private void createRanksTable() { worker.submit(() -> { if (isConnected()) { @@ -113,12 +126,18 @@ private void createRanksTable() { }); } + /** + * Creates the 'cytonic_worlds' table in the database if it doesn't exist. + * The table contains information about the worlds stored in the database. + * + * @throws IllegalStateException if the database connection is not open. + */ public void createWorldTable() { worker.submit(() -> { if (isConnected()) { PreparedStatement ps; try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_worlds (world_name TEXT, world_type TEXT, last_modified TIMESTAMP, world_data MEDIUMBLOB, x DOUBLE, y DOUBLE, z DOUBLE, yaw FLOAT, pitch FLOAT, extra_data varchar(100))"); + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_worlds (world_name TEXT, world_type TEXT, last_modified TIMESTAMP, world_data MEDIUMBLOB, spawn_point TEXT, extra_data varchar(100))"); ps.executeUpdate(); } catch (SQLException e) { Logger.error("An error occurred whilst creating the `cytonic_worlds` table.", e); @@ -183,11 +202,11 @@ public CompletableFuture setPlayerRank(UUID uuid, PlayerRank rank) { } /** - * Adds a players chat message to the database + * Adds a players chat message to the database. * - * @param uuid The player's UUID - * @param message The player's message - * @throws IllegalStateException if the database isn't connected + * @param uuid The player's UUID. + * @param message The player's message. + * @throws IllegalStateException if the database isn't connected. */ public void addChat(UUID uuid, String message) { worker.submit(() -> { @@ -205,53 +224,60 @@ public void addChat(UUID uuid, String message) { }); } - public CompletableFuture addWorld(String worldName, String worldType, PolarWorld world, Pos spawnPoint) { + /** + * Adds a new world to the database. + * + * @param worldName The name of the world to be added. + * @param worldType The type of the world. + * @param world The PolarWorld object representing the world. + * @param spawnPoint The spawn point of the world. + * @throws IllegalStateException If the database connection is not open. + */ + public void addWorld(String worldName, String worldType, PolarWorld world, Pos spawnPoint) { if (!isConnected()) throw new IllegalStateException("The database must have an open connection to add a world!"); - CompletableFuture future = new CompletableFuture<>(); worker.submit(() -> { try { - PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_worlds (world_name, world_type, last_modified, world_data, x, y, z, yaw, pitch) VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?, ?, ?, ?)"); + PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_worlds (world_name, world_type, last_modified, world_data, spawn_point) VALUES (?,?, CURRENT_TIMESTAMP,?,?)"); ps.setString(1, worldName); ps.setString(2, worldType); ps.setBytes(3, PolarWriter.write(world)); - ps.setDouble(4, spawnPoint.x()); - ps.setDouble(5, spawnPoint.y()); - ps.setDouble(6, spawnPoint.z()); - ps.setFloat(7, spawnPoint.yaw()); - ps.setFloat(8, spawnPoint.pitch()); + ps.setString(4, PosSerializer.serialize(spawnPoint)); ps.executeUpdate(); - future.complete(null); } catch (SQLException e) { Logger.error("An error occurred whilst adding a world!",e); - future.completeExceptionally(e); } }); - return future; } /** - * Gets a world + * Retrieves a world from the database. * - * @param worldName the world to fetch - * @return The player's {@link PolarWorld} - * @throws IllegalStateException if the database isn't connected + * @param worldName The name of the world to fetch. + * @return A {@link CompletableFuture} that completes with the fetched {@link PolarWorld}. + * If the world does not exist in the database, the future will complete exceptionally with a {@link RuntimeException}. + * @throws IllegalStateException If the database connection is not open. */ public CompletableFuture getWorld(String worldName) { CompletableFuture future = new CompletableFuture<>(); if (!isConnected()) throw new IllegalStateException("The database must have an open connection to fetch a world!"); worker.submit(() -> { - try { - PreparedStatement ps = connection.prepareStatement("SELECT * FROM cytonic_worlds WHERE world_name = ?"); + try (PreparedStatement ps = connection.prepareStatement("SELECT * FROM cytonic_worlds WHERE world_name = ?")) { ps.setString(1, worldName); ResultSet rs = ps.executeQuery(); - if (rs.next()) future.complete(PolarReader.read(rs.getBytes("world_data"))); - else Logger.error("The result set is empty!"); - CytosisSettings.SERVER_SPAWN_POS = new Pos(rs.getDouble("x"),rs.getDouble("y"),rs.getDouble("z"), (float) rs.getDouble("yaw"), (float) rs.getDouble("pitch")); + if (rs.next()) { + PolarWorld world = PolarReader.read(rs.getBytes("world_data")); + CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(rs.getString("spawn_point")); + future.complete(world); + } else { + Logger.error("The result set is empty!"); + throw new RuntimeException(STR."World not found: \{worldName}"); + } } catch (Exception e) { Logger.error("An error occurred whilst fetching a world!", e); future.completeExceptionally(e); + throw new RuntimeException(e); } }); return future; diff --git a/src/main/java/net/cytonic/cytosis/utils/PosSerializer.java b/src/main/java/net/cytonic/cytosis/utils/PosSerializer.java new file mode 100644 index 00000000..324279e4 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/utils/PosSerializer.java @@ -0,0 +1,39 @@ +package net.cytonic.cytosis.utils; + +import net.minestom.server.coordinate.Pos; + +public class PosSerializer { + + /** + * Serializes a {@link Pos} object into a human-readable string format. + * + * @param pos The position to be serialized. + * @return A string representation of the position in the format: "Pos{x=%.2f, y=%.2f, z=%.2f, yaw=%.2f, pitch=%.2f}" + */ + public static String serialize(Pos pos) { + return String.format("Pos{x=%.2f, y=%.2f, z=%.2f, yaw=%.2f, pitch=%.2f}", pos.x(), pos.y(), pos.z(), pos.yaw(), pos.pitch()); + } + + /** + * Deserializes a human-readable string format into a {@link Pos} object. + * + * @param serializedPos The string representation of the position to be deserialized. + * The string should be in the format: "Pos{x=%.2f, y=%.2f, z=%.2f, yaw=%.2f, pitch=%.2f}" + * @return A {@link Pos} object representing the deserialized position. + * If the input string is empty, a new {@link Pos} object with all coordinates set to 0 is returned. + */ + public static Pos deserialize(String serializedPos) { + if (!serializedPos.isEmpty()) { + serializedPos = serializedPos.replace("}", ""); + String[] parts = serializedPos.split("[=,\\s]+"); + double x = Double.parseDouble(parts[1]); + double y = Double.parseDouble(parts[3]); + double z = Double.parseDouble(parts[5]); + float yaw = Float.parseFloat(parts[7]); + float pitch = Float.parseFloat(parts[9]); + return new Pos(x, y, z, yaw, pitch); + } else { + return new Pos(0, 0, 0, 180, 0); + } + } +} \ No newline at end of file diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index e1def0e3..a59fc72a 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -19,6 +19,7 @@ proxy_mode = true secret = "hi i am the secret" # this can NOT be empty port = 25565 world_name = "" +spawn_point = "" # Logging Configuration # Enable/disable logging for various player activities From 747a9c987ce8be7586ad8c58e58640e1b8137e33 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 18:55:34 +0000 Subject: [PATCH 28/55] Update dependency dev.hollowcube:polar to v1.9.3 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index d00cb870..80bb3a84 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,7 +27,7 @@ dependencies { annotationProcessor("org.projectlombok:lombok:1.18.32") // lombok implementation("org.tomlj:tomlj:1.1.1") // Config lang implementation("com.rabbitmq:amqp-client:5.21.0") // Message broker - implementation("dev.hollowcube:polar:1.8.1") // Polar + implementation("dev.hollowcube:polar:1.9.3") // Polar } tasks.withType { From 044c181971bc5587376ac42db8a03e31a1be1f66 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Thu, 16 May 2024 11:22:07 -0500 Subject: [PATCH 29/55] Add player logging --- .../cytosis/config/CytosisSettings.java | 4 -- .../net/cytonic/cytosis/data/Database.java | 48 +++++++++++++++++-- .../cytosis/events/ServerEventListeners.java | 5 +- src/main/resources/config.toml | 1 - 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java index 9a4aad45..7ea6435f 100644 --- a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java +++ b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java @@ -10,7 +10,6 @@ */ public class CytosisSettings { // Logging - public static boolean LOG_PLAYER_IPS = true; public static boolean LOG_PLAYER_JOINS = true; public static boolean LOG_PLAYER_QUITS = true; public static boolean LOG_PLAYER_COMMANDS = true; @@ -42,7 +41,6 @@ public static void inportConfig(Map config) { try { switch (key.replace("\"", "")) { // logging - case "logging.player_ip" -> LOG_PLAYER_IPS = (boolean) value; case "logging.player_join" -> LOG_PLAYER_JOINS = (boolean) value; case "logging.player_quit" -> LOG_PLAYER_QUITS = (boolean) value; case "logging.player_command" -> LOG_PLAYER_COMMANDS = (boolean) value; @@ -87,7 +85,6 @@ private static int toInt(Object key) { public static void loadEnvironmentVariables() { Logger.info("Loading environment variables!"); // logging - if (!(System.getenv("LOG_PLAYER_IPS") == null)) CytosisSettings.LOG_PLAYER_IPS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_IPS")); if (!(System.getenv("LOG_PLAYER_JOINS") == null)) CytosisSettings.LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_JOINS")); if (!(System.getenv("LOG_PLAYER_QUITS") == null)) CytosisSettings.LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_QUITS")); if (!(System.getenv("LOG_PLAYER_COMMANDS") == null)) CytosisSettings.LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_COMMANDS")); @@ -117,7 +114,6 @@ public static void loadEnvironmentVariables() { public static void loadCommandArgs() { Logger.info("Loading command args!"); // logging - if (!(System.getProperty("LOG_PLAYER_IPS") == null)) CytosisSettings.LOG_PLAYER_IPS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_IPS")); if (!(System.getProperty("LOG_PLAYER_JOINS") == null)) CytosisSettings.LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_JOINS")); if (!(System.getProperty("LOG_PLAYER_QUITS") == null)) CytosisSettings.LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_QUITS")); if (!(System.getProperty("LOG_PLAYER_COMMANDS") == null)) CytosisSettings.LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_COMMANDS")); diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index ae3d9198..6a6df857 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -11,6 +11,7 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; import org.jetbrains.annotations.NotNull; +import java.net.SocketAddress; import java.sql.*; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -80,6 +81,7 @@ public void createTables() { createRanksTable(); createChatTable(); createWorldTable(); + createPlayersTable(); } private Connection getConnection() { @@ -100,7 +102,7 @@ private void createChatTable() { ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat (id INT NOT NULL AUTO_INCREMENT, timestamp TIMESTAMP, uuid VARCHAR(36), message TEXT, PRIMARY KEY(id))"); ps.executeUpdate(); } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_chat` table.", e); + Logger.error("An error occurred whilst fetching data from the database. Please report the following stacktrace to Foxikle:", e); } } }); @@ -140,7 +142,19 @@ public void createWorldTable() { ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_worlds (world_name TEXT, world_type TEXT, last_modified TIMESTAMP, world_data MEDIUMBLOB, spawn_point TEXT, extra_data varchar(100))"); ps.executeUpdate(); } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_worlds` table.", e); + Logger.error("An error occurred whilst creating the `cytonic_ranks` table.", e); + } + } + }); + } + + private void createPlayersTable() { + worker.submit(() -> { + if (isConnected()) { + try (PreparedStatement ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_players (joined TIMESTAMP, uuid VARCHAR(36), ip TEXT)")) { + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_players` table.", e); } } }); @@ -245,7 +259,7 @@ public void addWorld(String worldName, String worldType, PolarWorld world, Pos s ps.setString(4, PosSerializer.serialize(spawnPoint)); ps.executeUpdate(); } catch (SQLException e) { - Logger.error("An error occurred whilst adding a world!",e); + Logger.error("An error occurred whilst adding a world!", e); } }); } @@ -255,7 +269,7 @@ public void addWorld(String worldName, String worldType, PolarWorld world, Pos s * * @param worldName The name of the world to fetch. * @return A {@link CompletableFuture} that completes with the fetched {@link PolarWorld}. - * If the world does not exist in the database, the future will complete exceptionally with a {@link RuntimeException}. + * If the world does not exist in the database, the future will complete exceptionally with a {@link RuntimeException}. * @throws IllegalStateException If the database connection is not open. */ public CompletableFuture getWorld(String worldName) { @@ -269,7 +283,7 @@ public CompletableFuture getWorld(String worldName) { if (rs.next()) { PolarWorld world = PolarReader.read(rs.getBytes("world_data")); CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(rs.getString("spawn_point")); - future.complete(world); + future.complete(world); } else { Logger.error("The result set is empty!"); throw new RuntimeException(STR."World not found: \{worldName}"); @@ -282,4 +296,28 @@ public CompletableFuture getWorld(String worldName) { }); return future; } + + /** + * Logs a player's join event to the database. + * + * @param uuid The unique identifier of the player. + * @param ip The IP address of the player. + *

+ * This method uses a worker thread to execute the database operation. + * It prepares a SQL statement to insert a new record into the 'cytonic_players' table. + * The 'joined' column is set to the current timestamp, the 'uuid' column is set to the provided UUID, + * and the 'ip' column is set to the provided IP address. + * If an error occurs during the database operation, it is logged using the Logger. + */ +public void playerJoin(UUID uuid, SocketAddress ip) { + worker.submit(() -> { + try (PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_players (joined, uuid, ip) VALUES (CURRENT_TIMESTAMP,?,?)")) { + ps.setString(1, uuid.toString()); + ps.setString(2, ip.toString()); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("Failed to add a player to the database!", e); + } + }); +} } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java index 98258b84..5c26ed87 100644 --- a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java +++ b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java @@ -22,9 +22,8 @@ public static void initServerEvents() { Logger.info("Registering player spawn event."); Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-spawn", false, 1, PlayerSpawnEvent.class, (event -> { final Player player = event.getPlayer(); - if (CytosisSettings.LOG_PLAYER_IPS) - Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); - else Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined."); + Logger.info(STR."\{player.getUsername()} (\{player.getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); + Cytosis.getDatabaseManager().getDatabase().playerJoin(player.getUuid(), player.getPlayerConnection().getRemoteAddress()); Cytosis.getRankManager().addPlayer(player); }))); diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index a59fc72a..aed1bcfe 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -26,7 +26,6 @@ spawn_point = "" [logging] player_join = true # Log when players join the server player_quit = true # Log when players leave the server -player_ip = true # Log player IP addresses player_chat = true # Log player chat messages player_command = true # Log commands issued by players From 0e7b32789c74c2af83fe93e10b10b9c469c5ae1d Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Thu, 16 May 2024 11:24:38 -0500 Subject: [PATCH 30/55] Fix typo --- src/main/java/net/cytonic/cytosis/data/Database.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index 6a6df857..b03e4035 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -142,7 +142,7 @@ public void createWorldTable() { ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_worlds (world_name TEXT, world_type TEXT, last_modified TIMESTAMP, world_data MEDIUMBLOB, spawn_point TEXT, extra_data varchar(100))"); ps.executeUpdate(); } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_ranks` table.", e); + Logger.error("An error occurred whilst creating the `cytonic_worlds` table.", e); } } }); From 0e01e2dc1f8404588b36b49f45d0f407551f74c3 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Thu, 16 May 2024 11:28:48 -0500 Subject: [PATCH 31/55] Change error messages --- src/main/java/net/cytonic/cytosis/data/Database.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index b03e4035..45e9e88f 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -71,7 +71,7 @@ public void disconnect() { connection.close(); Logger.info("Database connection closed!"); } catch (SQLException e) { - Logger.error("An error occurred whilst disconnecting from the database. Please report the following stacktrace to Foxikle: ", e); + Logger.error("An error occurred whilst disconnecting from the database.", e); } } }); @@ -102,7 +102,7 @@ private void createChatTable() { ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat (id INT NOT NULL AUTO_INCREMENT, timestamp TIMESTAMP, uuid VARCHAR(36), message TEXT, PRIMARY KEY(id))"); ps.executeUpdate(); } catch (SQLException e) { - Logger.error("An error occurred whilst fetching data from the database. Please report the following stacktrace to Foxikle:", e); + Logger.error("An error occurred whilst creating the `cytonic_chat` table.", e); } } }); @@ -233,7 +233,7 @@ public void addChat(UUID uuid, String message) { ps.setString(2, message); ps.executeUpdate(); } catch (SQLException e) { - throw new RuntimeException(e); + Logger.error("An error occurred whilst adding a chat message.",e); } }); } From 8829cbfc1979f95506eebcb400f6059c5e64960f Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Thu, 16 May 2024 11:38:27 -0500 Subject: [PATCH 32/55] Rename cytonic_player_joins table --- src/main/java/net/cytonic/cytosis/data/Database.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index 45e9e88f..8845f5d2 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -81,7 +81,7 @@ public void createTables() { createRanksTable(); createChatTable(); createWorldTable(); - createPlayersTable(); + createPlayerJoinsTable(); } private Connection getConnection() { @@ -148,13 +148,13 @@ public void createWorldTable() { }); } - private void createPlayersTable() { + private void createPlayerJoinsTable() { worker.submit(() -> { if (isConnected()) { - try (PreparedStatement ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_players (joined TIMESTAMP, uuid VARCHAR(36), ip TEXT)")) { + try (PreparedStatement ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_player_joins (joined TIMESTAMP, uuid VARCHAR(36), ip TEXT)")) { ps.executeUpdate(); } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_players` table.", e); + Logger.error("An error occurred whilst creating the `cytonic_player_joins` table.", e); } } }); @@ -304,14 +304,14 @@ public CompletableFuture getWorld(String worldName) { * @param ip The IP address of the player. *

* This method uses a worker thread to execute the database operation. - * It prepares a SQL statement to insert a new record into the 'cytonic_players' table. + * It prepares a SQL statement to insert a new record into the 'cytonic_player_joins' table. * The 'joined' column is set to the current timestamp, the 'uuid' column is set to the provided UUID, * and the 'ip' column is set to the provided IP address. * If an error occurs during the database operation, it is logged using the Logger. */ public void playerJoin(UUID uuid, SocketAddress ip) { worker.submit(() -> { - try (PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_players (joined, uuid, ip) VALUES (CURRENT_TIMESTAMP,?,?)")) { + try (PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_player_joins (joined, uuid, ip) VALUES (CURRENT_TIMESTAMP,?,?)")) { ps.setString(1, uuid.toString()); ps.setString(2, ip.toString()); ps.executeUpdate(); From 77da3dd2052561da340e2d3e2fc0a905b035f3a9 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Thu, 16 May 2024 12:25:46 -0500 Subject: [PATCH 33/55] Rename playerJoin to logPlayerJoin --- src/main/java/net/cytonic/cytosis/data/Database.java | 2 +- .../java/net/cytonic/cytosis/events/ServerEventListeners.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index 8845f5d2..038b0aa5 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -309,7 +309,7 @@ public CompletableFuture getWorld(String worldName) { * and the 'ip' column is set to the provided IP address. * If an error occurs during the database operation, it is logged using the Logger. */ -public void playerJoin(UUID uuid, SocketAddress ip) { +public void logPlayerJoin(UUID uuid, SocketAddress ip) { worker.submit(() -> { try (PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_player_joins (joined, uuid, ip) VALUES (CURRENT_TIMESTAMP,?,?)")) { ps.setString(1, uuid.toString()); diff --git a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java index 5c26ed87..bcdb6a5a 100644 --- a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java +++ b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java @@ -23,7 +23,7 @@ public static void initServerEvents() { Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-spawn", false, 1, PlayerSpawnEvent.class, (event -> { final Player player = event.getPlayer(); Logger.info(STR."\{player.getUsername()} (\{player.getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); - Cytosis.getDatabaseManager().getDatabase().playerJoin(player.getUuid(), player.getPlayerConnection().getRemoteAddress()); + Cytosis.getDatabaseManager().getDatabase().logPlayerJoin(player.getUuid(), player.getPlayerConnection().getRemoteAddress()); Cytosis.getRankManager().addPlayer(player); }))); From b246388559879ac27865d2eda11702b851b61b2a Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Wed, 22 May 2024 15:22:03 +0000 Subject: [PATCH 34/55] Changing back to intellij --- .../java/net/cytonic/cytosis/Cytosis.java | 14 +- .../cytosis/commands/ChatChannelCommand.java | 160 ++++++++++++++++++ .../cytosis/commands/CommandHandler.java | 1 + .../net/cytonic/cytosis/data/Database.java | 79 ++++++++- .../cytosis/data/enums/ChatChannel.java | 19 +++ .../cytonic/cytosis/data/objects/Request.java | 66 ++++++++ .../cytosis/events/ServerEventListeners.java | 40 +++++ .../cytonic/cytosis/managers/ChatManager.java | 42 +++++ .../cytosis/messaging/MessagingManager.java | 7 + .../cytonic/cytosis/messaging/RabbitMQ.java | 82 ++++++++- 10 files changed, 496 insertions(+), 14 deletions(-) create mode 100644 src/main/java/net/cytonic/cytosis/commands/ChatChannelCommand.java create mode 100644 src/main/java/net/cytonic/cytosis/data/enums/ChatChannel.java create mode 100644 src/main/java/net/cytonic/cytosis/data/objects/Request.java create mode 100644 src/main/java/net/cytonic/cytosis/managers/ChatManager.java diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index e87649c5..fe8d83f0 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -1,5 +1,11 @@ package net.cytonic.cytosis; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + import lombok.Getter; import net.cytonic.cytosis.commands.CommandHandler; import net.cytonic.cytosis.config.CytosisSettings; @@ -8,6 +14,7 @@ import net.cytonic.cytosis.events.ServerEventListeners; import net.cytonic.cytosis.files.FileManager; import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.managers.ChatManager; import net.cytonic.cytosis.messaging.MessagingManager; import net.cytonic.cytosis.ranks.RankManager; import net.hollowcube.polar.PolarLoader; @@ -23,7 +30,6 @@ import net.minestom.server.instance.block.Block; import net.minestom.server.network.ConnectionManager; import net.minestom.server.permission.Permission; -import java.util.*; @Getter public class Cytosis { @@ -53,6 +59,8 @@ public class Cytosis { private static ConsoleSender consoleSender; @Getter private static RankManager rankManager; + @Getter + private static ChatManager chatManager; private static List FLAGS; @@ -79,6 +87,10 @@ public static void main(String[] args) { consoleSender = commandManager.getConsoleSender(); consoleSender.addPermission(new Permission("*")); + //chat manager + Logger.info("Starting chat manager."); + chatManager = new ChatManager(); + // instances Logger.info("Creating instance container"); defaultInstance = instanceManager.createInstanceContainer(); diff --git a/src/main/java/net/cytonic/cytosis/commands/ChatChannelCommand.java b/src/main/java/net/cytonic/cytosis/commands/ChatChannelCommand.java new file mode 100644 index 00000000..863f7bbc --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/commands/ChatChannelCommand.java @@ -0,0 +1,160 @@ +package net.cytonic.cytosis.commands; + +import net.cytonic.cytosis.Cytosis; +import net.cytonic.cytosis.data.enums.ChatChannel; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.command.builder.Command; +import net.minestom.server.command.builder.arguments.ArgumentEnum; +import net.minestom.server.command.builder.arguments.ArgumentType; +import net.minestom.server.command.builder.suggestion.SuggestionEntry; +import net.minestom.server.entity.Player; + +public class ChatChannelCommand extends Command { + + public ChatChannelCommand() { + super("chat"); + setDefaultExecutor(((sender, commandContext) -> sender.sendMessage(Component.text("You must specify a channel!", NamedTextColor.RED)))); + + var chatChannelArgument = ArgumentType.Enum("channel", ChatChannel.class).setFormat(ArgumentEnum.Format.LOWER_CASED); + chatChannelArgument.setCallback((sender, exception) -> sender.sendMessage(STR."The channel \{exception.getInput()} is invalid!")); + + var shorthand = ArgumentType.Word("shorthand").from("a"); + shorthand.setSuggestionCallback((sender, commandContext, suggestion) -> { + Player player = (Player) sender; + if (player.hasPermission("cytonic.chat.mod")) + suggestion.addEntry(new SuggestionEntry("m", Component.text("Represents the Mod channel"))); + if (player.hasPermission("cytonic.chat.staff")) + suggestion.addEntry(new SuggestionEntry("s", Component.text("Represents the Staff channel"))); + if (player.hasPermission("cytonic.chat.admin")) + suggestion.addEntry(new SuggestionEntry("ad", Component.text("Represents the Admin channel"))); + //parties + suggestion.addEntry(new SuggestionEntry("a",Component.text("Represents the All channel"))); + }); + shorthand.setCallback((sender, exception) -> sender.sendMessage(Component.text(STR."The shorthand '\{exception.getInput()}' is invalid!", NamedTextColor.RED))); + + addSyntax((sender, context) -> { + if (sender instanceof final Player player) { + final ChatChannel channel = context.get(chatChannelArgument); + switch (channel) { + case ALL -> { + Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.ALL); + player.sendMessage( + Component.text("You are now in the ", NamedTextColor.GREEN) + .append(Component.text("ALL", NamedTextColor.GOLD)) + .append(Component.text(" channel.", NamedTextColor.GREEN)) + ); + } + case ADMIN -> { + if (player.hasPermission("cytonic.chat.admin")) { + Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.ADMIN); + player.sendMessage( + Component.text("You are now in the ", NamedTextColor.GREEN) + .append(Component.text("ADMIN", NamedTextColor.GOLD)) + .append(Component.text(" channel.", NamedTextColor.GREEN)) + ); + } else { + player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); + } + } + case MOD -> { + if (player.hasPermission("cytonic.chat.mod")) { + Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.MOD); + player.sendMessage( + Component.text("You are now in the ", NamedTextColor.GREEN) + .append(Component.text("MOD", NamedTextColor.GOLD)) + .append(Component.text(" channel.", NamedTextColor.GREEN)) + ); + } else { + player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); + } + } + case STAFF -> { + if (player.hasPermission("cytonic.chat.staff")) { + Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.STAFF); + player.sendMessage( + Component.text("You are now in the ", NamedTextColor.GREEN) + .append(Component.text("STAFF", NamedTextColor.GOLD)) + .append(Component.text(" channel.", NamedTextColor.GREEN)) + ); + } else { + player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); + } + } + case PARTY -> { + player.sendMessage("party"); + } + case LEAGUE -> { + player.sendMessage("league"); + } + case PRIVATE_MESSAGE -> { + player.sendMessage("private message"); + } + } + } else { + sender.sendMessage(Component.text("Hey! You can't do this.", NamedTextColor.RED)); + } + }, chatChannelArgument); + + addSyntax((sender, context) -> { + if (sender instanceof final Player player) { + final String channel = context.get(shorthand); + switch (channel.toLowerCase()) { + case "a" -> { + Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.ALL); + player.sendMessage( + Component.text("You are now in the ", NamedTextColor.GREEN) + .append(Component.text("ALL", NamedTextColor.GOLD)) + .append(Component.text(" channel.", NamedTextColor.GREEN)) + ); + } + case "ad" -> { + if (player.hasPermission("cytonic.chat.admin")) { + Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.ADMIN); + player.sendMessage( + Component.text("You are now in the ", NamedTextColor.GREEN) + .append(Component.text("ADMIN", NamedTextColor.GOLD)) + .append(Component.text(" channel.", NamedTextColor.GREEN)) + ); + } else { + player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); + } + } + case "m" -> { + if (player.hasPermission("cytonic.chat.mod")) { + Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.MOD); + player.sendMessage( + Component.text("You are now in the ", NamedTextColor.GREEN) + .append(Component.text("MOD", NamedTextColor.GOLD)) + .append(Component.text(" channel.", NamedTextColor.GREEN)) + ); + } else { + player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); + } + } + case "s" -> { + if (player.hasPermission("cytonic.chat.staff")) { + Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.STAFF); + player.sendMessage( + Component.text("You are now in the ", NamedTextColor.GREEN) + .append(Component.text("STAFF", NamedTextColor.GOLD)) + .append(Component.text(" channel.", NamedTextColor.GREEN)) + ); + } else { + player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); + } + } + case "p" -> { + player.sendMessage("party"); + } + case "l" -> { + player.sendMessage("league"); + } + default -> player.sendMessage(Component.text(STR."The shorthand '\{channel}' is invalid!", NamedTextColor.RED)); + } + } else { + sender.sendMessage(Component.text("Hey! You can't do this.", NamedTextColor.RED)); + } + }, shorthand); +} +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java index b226608b..5c5db340 100644 --- a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java +++ b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java @@ -23,6 +23,7 @@ public void registerCystosisCommands() { CommandManager cm = Cytosis.getCommandManager(); cm.register(new GamemodeCommand()); cm.register(new RankCommand()); + cm.register(new ChatChannelCommand()); cm.register(new BanCommand()); } diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index 038b0aa5..0478a111 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -1,5 +1,18 @@ package net.cytonic.cytosis.data; +import java.net.SocketAddress; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.jetbrains.annotations.NotNull; + import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.config.CytosisSettings; import net.cytonic.cytosis.logging.Logger; @@ -10,13 +23,6 @@ import net.hollowcube.polar.PolarWriter; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; -import org.jetbrains.annotations.NotNull; -import java.net.SocketAddress; -import java.sql.*; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; public class Database { @@ -82,6 +88,7 @@ public void createTables() { createChatTable(); createWorldTable(); createPlayerJoinsTable(); + createChatChannelsTable(); } private Connection getConnection() { @@ -128,6 +135,16 @@ private void createRanksTable() { }); } + public void createNameTable() { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonicnames (uuid VARCHAR(36), name VARCHAR(16), PRIMARY KEY(uuid))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_names` table.", e); + } + } + /** * Creates the 'cytonic_worlds' table in the database if it doesn't exist. * The table contains information about the worlds stored in the database. @@ -148,6 +165,20 @@ public void createWorldTable() { }); } + private void createChatChannelsTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat_channels (player_uuid VARCHAR(36), chat_channel TEXT, PRIMARY KEY(player_uuid))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_chat_channels` table.", e); + } + } + }); + } + private void createPlayerJoinsTable() { worker.submit(() -> { if (isConnected()) { @@ -238,6 +269,40 @@ public void addChat(UUID uuid, String message) { }); } + public String getName(UUID uuid) { + PreparedStatement ps; + try { + ps = connection.prepareStatement("SELECT name FROM cytonicnames WHERE uuid = ?"); + ps.setString(1, uuid.toString()); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + return rs.getString("name"); + } + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst fetching the name of '\{uuid}'"); + } + return "ERROR!"; + } + + public UUID getUUID(String name) { + PreparedStatement ps; + try { + ps = connection.prepareStatement("SELECT uuid FROM cytonicnames WHERE name = ?"); + ps.setString(1, name); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + try { + return UUID.fromString(rs.getString("uuid")); + } catch (IllegalArgumentException ex) { + return null; + } + } + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst fetching the uuid of '\{name}'"); + } + return null; + } + /** * Adds a new world to the database. * diff --git a/src/main/java/net/cytonic/cytosis/data/enums/ChatChannel.java b/src/main/java/net/cytonic/cytosis/data/enums/ChatChannel.java new file mode 100644 index 00000000..ba6378fb --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/data/enums/ChatChannel.java @@ -0,0 +1,19 @@ +package net.cytonic.cytosis.data.enums; + +import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; + +@Getter +public enum ChatChannel { + ALL(Component.empty()), + PRIVATE_MESSAGE(Component.empty()), + PARTY(Component.text("Party > ", NamedTextColor.GOLD)), + LEAGUE(Component.text("League > ", NamedTextColor.DARK_PURPLE)), + MOD(Component.text("Mod > ", NamedTextColor.DARK_GREEN)), + ADMIN(Component.text("Admin > ", NamedTextColor.DARK_RED)), + STAFF(Component.text("Staff > ", NamedTextColor.LIGHT_PURPLE)); + + private final Component prefix; + ChatChannel(Component prefix) {this.prefix = prefix;} +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/data/objects/Request.java b/src/main/java/net/cytonic/cytosis/data/objects/Request.java new file mode 100644 index 00000000..0278e3e8 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/data/objects/Request.java @@ -0,0 +1,66 @@ +package net.cytonic.cytosis.data.objects; + +import java.time.Instant; +import java.util.UUID; + +public class Request { + private final Instant expiry; + private final UUID author; + private final UUID target; + private final RequestType type; + private final Instant issuedAt; + private boolean accepted; + private boolean declined; + + public Request(Instant expiry, UUID author, UUID target, RequestType type) { + this.expiry = expiry; + this.author = author; + this.target = target; + this.type = type; + issuedAt = Instant.now(); + accepted = false; + declined = false; + } + + public Instant getExpiry() { + return expiry; + } + + public RequestType getType() { + return type; + } + + public Instant getIssuedAt() { + return issuedAt; + } + + public UUID getAuthor() { + return author; + } + + public UUID getTarget() { + return target; + } + + public boolean isAccepted() { + return accepted; + } + + public boolean isDeclined() { + return declined; + } + + public void setAccepted(boolean accepted) { + this.accepted = accepted; + } + + public void setDeclined(boolean declined) { + this.declined = declined; + } + + public enum RequestType { + FRIEND, + LEAGUE, + PARTY + } +} diff --git a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java index bcdb6a5a..60f541a4 100644 --- a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java +++ b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java @@ -2,7 +2,10 @@ import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.data.enums.ChatChannel; import net.cytonic.cytosis.logging.Logger; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.entity.Player; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.PlayerChatEvent; @@ -32,6 +35,25 @@ public static void initServerEvents() { final Player player = event.getPlayer(); if (CytosisSettings.LOG_PLAYER_CHAT) Cytosis.getDatabaseManager().getDatabase().addChat(player.getUuid(), event.getMessage()); + event.setCancelled(true); + String originalMessage = event.getMessage(); + if(Cytosis.getChatManager().getChannel(player.getUuid()) != ChatChannel.ALL) { + ChatChannel channel = Cytosis.getChatManager().getChannel(player.getUuid()); + Component message = Component.text("") + .append(channel.getPrefix()) + .append(Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getPrefix()) + .append(Component.text(player.getUsername(), (Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor()))) + .appendSpace() + .append(Component.text(originalMessage, NamedTextColor.WHITE)); + Cytosis.getChatManager().sendMessageToChannel(message, Cytosis.getChatManager().getChannel(player.getUuid())); + } else { + Component message = Component.text("") + .append(Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getPrefix()) + .append(Component.text(player.getUsername(), (Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor()))) + .appendSpace() + .append(Component.text(originalMessage, NamedTextColor.WHITE)); + Cytosis.getOnlinePlayers().forEach((p) -> {p.sendMessage(message);}); + } })); Logger.info("Registering player disconnect event."); @@ -40,4 +62,22 @@ public static void initServerEvents() { Cytosis.getRankManager().removePlayer(player); })); } + + public static void chatEvent(PlayerChatEvent event) { + Player player = event.getPlayer(); + if(Cytosis.getChatManager().getChannel(player.getUuid()) != ChatChannel.ALL) { + ChatChannel channel = Cytosis.getChatManager().getChannel(player.getUuid()); + event.setCancelled(true); + String originalMessage = event.getMessage(); + Component message = Component.text("") + .append(channel.getPrefix()) + .append(Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getPrefix()) + .append(Component.text(player.getUsername(), (Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor()))) + .appendSpace() + .append(Component.text(originalMessage, NamedTextColor.WHITE)); + Cytosis.getChatManager().sendMessageToChannel(message, Cytosis.getChatManager().getChannel(player.getUuid())); + } else { + event.setCancelled(false); + } + } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/managers/ChatManager.java b/src/main/java/net/cytonic/cytosis/managers/ChatManager.java new file mode 100644 index 00000000..dca764c9 --- /dev/null +++ b/src/main/java/net/cytonic/cytosis/managers/ChatManager.java @@ -0,0 +1,42 @@ +package net.cytonic.cytosis.managers; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import net.cytonic.cytosis.Cytosis; +import net.cytonic.cytosis.data.enums.ChatChannel; +import net.kyori.adventure.text.Component; + +public class ChatManager { + + private final Map channels = new HashMap<>(); + public void removeChannel(UUID uuid) { + channels.remove(uuid); + } + public void setChannel(UUID uuid, ChatChannel channel) { + channels.put(uuid, channel); + } + + public ChatChannel getChannel(UUID uuid) { + return channels.getOrDefault(uuid, ChatChannel.ALL); + } + + public void sendMessageToChannel(Component component, ChatChannel chatChannel) { + switch (chatChannel) { + case ADMIN,MOD,STAFF -> // send a message to all servers + Cytosis.getMessagingManager().getRabbitMQ().sendChatMessage(component, chatChannel); + case PARTY -> { + // parties.. + } + case LEAGUE -> { + // leagues.. + } + case PRIVATE_MESSAGE -> { + // private messages + } + case ALL -> throw new UnsupportedOperationException("Unimplemented case: " + chatChannel); + default -> throw new IllegalArgumentException("Unexpected value: " + chatChannel); + } + } +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java b/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java index 1363575c..52f1c379 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java +++ b/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java @@ -7,6 +7,11 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import lombok.Getter; +import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.data.enums.ChatChannel; +import net.kyori.adventure.text.Component; + public class MessagingManager { @Getter @@ -26,6 +31,8 @@ public CompletableFuture initialize() { rabbitMQ.initializeConnection(); rabbitMQ.initializeQueues(); rabbitMQ.sendServerDeclarationMessage(); + rabbitMQ.receiveChatMessages(); + rabbitMQ.sendChatMessage(Component.text("hello world!"), ChatChannel.ADMIN); } future.complete(null); }); diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index 32e2495f..43be151d 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -1,11 +1,22 @@ package net.cytonic.cytosis.messaging; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.concurrent.TimeoutException; + import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DeliverCallback; + +import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.data.enums.ChatChannel; import net.cytonic.cytosis.logging.Logger; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; import net.cytonic.cytosis.utils.OfflinePlayer; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; @@ -20,6 +31,7 @@ public class RabbitMQ { public static final String SERVER_DECLARE_QUEUE = "server-declaration"; public static final String SHUTDOWN_QUEUE = "server-shutdown"; + public static final String CHAT_CHANNEL_QUEUE = "chat-channel"; public static final String PLAYER_KICK_QUEUE = "player-kick"; private Connection connection; private Channel channel; @@ -33,14 +45,14 @@ public void initializeConnection() { try { connection = factory.newConnection(); } catch (IOException | TimeoutException e) { - Logger.error("An error occoured whilst connecting to RabbitMQ!", e); + Logger.error("An error occurred whilst connecting to RabbitMQ!", e); } Logger.info("Connected to RabbitMQ!"); try { channel = connection.createChannel(); connection = factory.newConnection(); } catch (IOException | TimeoutException e) { - Logger.error("An error occoured whilst connecting to RabbitMQ!", e); + Logger.error("An error occurred whilst connecting to RabbitMQ!", e); } } @@ -49,12 +61,19 @@ public void initializeQueues() { try { channel.queueDeclare(SERVER_DECLARE_QUEUE, false, false, false, null); } catch (IOException e) { - Logger.error("An error occoured whilst initializing the 'SERVER_DECLARE_QUEUE'.", e); + Logger.error("An error occurred whilst initializing the 'SERVER_DECLARE_QUEUE'.", e); } try { channel.queueDeclare(SHUTDOWN_QUEUE, false, false, false, null); } catch (IOException e) { - Logger.error("An error occoured whilst initializing the 'SHUTDOWN_QUEUE'.", e); + Logger.error("An error occurred whilst initializing the 'SHUTDOWN_QUEUE'.", e); + } + try { + channel.queueDeclare(CHAT_CHANNEL_QUEUE, false, false, false, null); + channel.exchangeDeclare("chat-messages", "fanout"); + channel.queueBind(CHAT_CHANNEL_QUEUE, "chat-messages", ""); + } catch (IOException e) { + Logger.error("An error occurred whilst initializing the 'CHAT_CHANNEL_QUEUE'.", e); } try { channel.queueDeclare(PLAYER_KICK_QUEUE, false, false, false, null); @@ -69,14 +88,14 @@ public void sendServerDeclarationMessage() { try { serverIP = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { - Logger.error("An error occoured whilst fetching this server's IP address! Bailing out!", e); + Logger.error("An error occurred whilst fetching this server's IP address! Bailing out!", e); return; } String message = STR."\{Cytosis.SERVER_ID}|:|\{serverIP}|:|\{CytosisSettings.SERVER_PORT}"; try { channel.basicPublish("", SERVER_DECLARE_QUEUE, null, message.getBytes()); } catch (IOException e) { - Logger.error("An error occoured whilst attempting to send the server declaration message!", e); + Logger.error("An error occurred whilst attempting to send the server declaration message!", e); } Logger.info(STR."Server Declaration message sent! '\{message}'."); } @@ -126,4 +145,55 @@ public void kickPlayer(OfflinePlayer player, KickReason reason, Component messag Logger.error(STR."An error occoured whilst attempting to kick the player \{player.name()}.", e); } } + + public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { + //formatting: {chat-message}|{chat-channel} + String message = STR."\{JSONComponentSerializer.json().serialize(chatMessage)}|\{chatChannel.name()}"; + try { + channel.basicPublish("chat-messages", CHAT_CHANNEL_QUEUE, null, message.getBytes()); + } catch (IOException e) { + Logger.error("An error occurred whilst attempting to send a chat message!", e); + } + } + + public void receiveChatMessages() { + try { + DeliverCallback deliverCallback = (consumerTag, delivery) -> { + String[] thing = new String(delivery.getBody(), "UTF-8").split("\\|"); + Component chatMessage = JSONComponentSerializer.json().deserialize(thing[0]); + ChatChannel chatChannel = ChatChannel.valueOf(thing[1]); + switch (chatChannel) { + case MOD -> // send a message to all players with cytonic.chat.mod permission + Cytosis.getOnlinePlayers().forEach(player -> { + if (player.hasPermission("cytonic.chat.mod")) { + player.sendMessage(chatMessage); + } + }); + + case STAFF -> // send a message to all players with cytonic.chat.staff permission + Cytosis.getOnlinePlayers().forEach(player -> { + if (player.hasPermission("cytonic.chat.staff")) { + player.sendMessage(chatMessage); + } + }); + case ADMIN -> // send a message to all players with cytonic.chat.admin permission + Cytosis.getOnlinePlayers().forEach(player -> { + if (player.hasPermission("cytonic.chat.admin")) { + player.sendMessage(chatMessage); + } + }); + case LEAGUE -> { + // leagues.. + } + + case PARTY -> { + // parties.. + } + } + }; + channel.basicConsume(CHAT_CHANNEL_QUEUE, true, deliverCallback, consumerTag -> { }); +} catch (IOException e) { + Logger.error("error", e); +} +} } \ No newline at end of file From cef6023f189b614302b47a4309bea34ef95d0481 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Fri, 24 May 2024 11:23:09 -0500 Subject: [PATCH 35/55] Fix typo --- src/main/java/net/cytonic/cytosis/commands/CommandHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java index 5c5db340..58e3eb12 100644 --- a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java +++ b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java @@ -19,7 +19,7 @@ public CommandHandler() { this.worker = Executors.newSingleThreadScheduledExecutor(Thread.ofVirtual().name("CytosisConsoleWorker").factory()); } - public void registerCystosisCommands() { + public void registerCytosisCommands() { CommandManager cm = Cytosis.getCommandManager(); cm.register(new GamemodeCommand()); cm.register(new RankCommand()); From a764e9c454ad066e91c15c19c6cb2eb96850c589 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Sat, 25 May 2024 13:50:16 -0500 Subject: [PATCH 36/55] Update minestom --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 80bb3a84..607149b8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation("com.github.Minestom", "Minestom", "6b8a4e4cc9") // minstom itself + implementation("com.github.Minestom", "Minestom", "85942b6b27") // minestom itself implementation("com.google.code.gson:gson:2.10.1") // serializing implementation("org.slf4j:slf4j-api:2.0.13") // logging implementation("net.kyori:adventure-text-minimessage:4.17.0")// better components From 4c710a271d01e4e4c0e891ae79ecfb8bb705c2c2 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Sat, 25 May 2024 13:52:24 -0500 Subject: [PATCH 37/55] Chat Channels and formatting --- .idea/misc.xml | 2 +- .../java/net/cytonic/cytosis/Cytosis.java | 5 +- .../cytosis/commands/ChatChannelCommand.java | 126 ++++++--------- .../cytonic/cytosis/commands/RankCommand.java | 2 +- .../cytosis/config/CytosisSettings.java | 9 +- .../net/cytonic/cytosis/data/Database.java | 147 +++++++++--------- .../cytonic/cytosis/data/objects/Request.java | 66 -------- .../cytonic/cytosis/events/EventHandler.java | 4 +- .../cytosis/events/ServerEventListeners.java | 57 +++---- .../cytosis/events/ranks/RankChangeEvent.java | 2 +- .../cytosis/events/ranks/RankSetupEvent.java | 2 +- .../cytonic/cytosis/files/FileManager.java | 5 +- .../cytonic/cytosis/managers/ChatManager.java | 10 +- .../cytosis/messaging/MessagingManager.java | 4 - .../cytonic/cytosis/messaging/RabbitMQ.java | 84 ++++++---- .../net/cytonic/cytosis/ranks/PlayerRank.java | 4 +- .../cytonic/cytosis/ranks/RankManager.java | 4 +- src/main/resources/config.toml | 1 + 18 files changed, 224 insertions(+), 310 deletions(-) delete mode 100644 src/main/java/net/cytonic/cytosis/data/objects/Request.java diff --git a/.idea/misc.xml b/.idea/misc.xml index 0738616b..2758df87 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index fe8d83f0..e22386e9 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -5,7 +5,6 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; - import lombok.Getter; import net.cytonic.cytosis.commands.CommandHandler; import net.cytonic.cytosis.config.CytosisSettings; @@ -89,7 +88,7 @@ public static void main(String[] args) { //chat manager Logger.info("Starting chat manager."); - chatManager = new ChatManager(); + chatManager = new ChatManager(); // instances Logger.info("Creating instance container"); @@ -191,7 +190,7 @@ public static void completeNonEssentialTasks(long start) { Logger.info("Initializing server commands"); commandHandler = new CommandHandler(); commandHandler.setupConsole(); - commandHandler.registerCystosisCommands(); + commandHandler.registerCytosisCommands(); messagingManager = new MessagingManager(); messagingManager.initialize().whenComplete((_, throwable) -> { diff --git a/src/main/java/net/cytonic/cytosis/commands/ChatChannelCommand.java b/src/main/java/net/cytonic/cytosis/commands/ChatChannelCommand.java index 863f7bbc..9581b3ec 100644 --- a/src/main/java/net/cytonic/cytosis/commands/ChatChannelCommand.java +++ b/src/main/java/net/cytonic/cytosis/commands/ChatChannelCommand.java @@ -5,7 +5,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.command.builder.Command; -import net.minestom.server.command.builder.arguments.ArgumentEnum; import net.minestom.server.command.builder.arguments.ArgumentType; import net.minestom.server.command.builder.suggestion.SuggestionEntry; import net.minestom.server.entity.Player; @@ -14,82 +13,72 @@ public class ChatChannelCommand extends Command { public ChatChannelCommand() { super("chat"); - setDefaultExecutor(((sender, commandContext) -> sender.sendMessage(Component.text("You must specify a channel!", NamedTextColor.RED)))); + setDefaultExecutor((sender, _) -> sender.sendMessage(Component.text("You must specify a channel!", NamedTextColor.RED))); - var chatChannelArgument = ArgumentType.Enum("channel", ChatChannel.class).setFormat(ArgumentEnum.Format.LOWER_CASED); - chatChannelArgument.setCallback((sender, exception) -> sender.sendMessage(STR."The channel \{exception.getInput()} is invalid!")); + var chatChannelArgument = ArgumentType.Word("channel").from("mod", "admin", "staff", "all", "party", "league", "private_message"); + chatChannelArgument.setCallback((sender, exception) -> sender.sendMessage(STR."The channel \{exception.getInput()} is invalid!")); + chatChannelArgument.setSuggestionCallback((sender, _, suggestion) -> { + if (sender.hasPermission("cytonic.chat.mod")) + suggestion.addEntry(new SuggestionEntry("mod")); + if (sender.hasPermission("cytonic.chat.admin")) + suggestion.addEntry(new SuggestionEntry("admin")); + if (sender.hasPermission("cytonic.chat.staff")) + suggestion.addEntry(new SuggestionEntry("staff")); + suggestion.addEntry(new SuggestionEntry("all")); + suggestion.addEntry(new SuggestionEntry("party")); + suggestion.addEntry(new SuggestionEntry("league")); + suggestion.addEntry(new SuggestionEntry("private_message")); + }); - var shorthand = ArgumentType.Word("shorthand").from("a"); - shorthand.setSuggestionCallback((sender, commandContext, suggestion) -> { - Player player = (Player) sender; - if (player.hasPermission("cytonic.chat.mod")) - suggestion.addEntry(new SuggestionEntry("m", Component.text("Represents the Mod channel"))); - if (player.hasPermission("cytonic.chat.staff")) - suggestion.addEntry(new SuggestionEntry("s", Component.text("Represents the Staff channel"))); - if (player.hasPermission("cytonic.chat.admin")) - suggestion.addEntry(new SuggestionEntry("ad", Component.text("Represents the Admin channel"))); - //parties - suggestion.addEntry(new SuggestionEntry("a",Component.text("Represents the All channel"))); + var shorthand = ArgumentType.Word("shorthand").from("m", "ad", "s", "a"); + shorthand.setCallback((sender, exception) -> sender.sendMessage(STR."The shorthand \{exception.getInput()} is invalid!")); + shorthand.setSuggestionCallback((sender, _, suggestion) -> { + if (sender.hasPermission("cytonic.chat.mod")) + suggestion.addEntry(new SuggestionEntry("m")); + if (sender.hasPermission("cytonic.chat.admin")) + suggestion.addEntry(new SuggestionEntry("ad")); + if (sender.hasPermission("cytonic.chat.staff")) + suggestion.addEntry(new SuggestionEntry("s")); + suggestion.addEntry(new SuggestionEntry("a")); }); shorthand.setCallback((sender, exception) -> sender.sendMessage(Component.text(STR."The shorthand '\{exception.getInput()}' is invalid!", NamedTextColor.RED))); - + addSyntax((sender, context) -> { if (sender instanceof final Player player) { - final ChatChannel channel = context.get(chatChannelArgument); + final String channel = context.get(chatChannelArgument); switch (channel) { - case ALL -> { + case "all" -> { Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.ALL); - player.sendMessage( - Component.text("You are now in the ", NamedTextColor.GREEN) - .append(Component.text("ALL", NamedTextColor.GOLD)) - .append(Component.text(" channel.", NamedTextColor.GREEN)) - ); + player.sendMessage(Component.text("You are now in the ", NamedTextColor.GREEN).append(Component.text("ALL", NamedTextColor.GOLD)).append(Component.text(" channel.", NamedTextColor.GREEN))); + player.getAllPermissions().forEach((permission -> player.sendMessage(permission.getPermissionName()))); } - case ADMIN -> { + case "admin" -> { if (player.hasPermission("cytonic.chat.admin")) { Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.ADMIN); - player.sendMessage( - Component.text("You are now in the ", NamedTextColor.GREEN) - .append(Component.text("ADMIN", NamedTextColor.GOLD)) - .append(Component.text(" channel.", NamedTextColor.GREEN)) - ); + player.sendMessage(Component.text("You are now in the ", NamedTextColor.GREEN).append(Component.text("ADMIN", NamedTextColor.GOLD)).append(Component.text(" channel.", NamedTextColor.GREEN))); } else { player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); } } - case MOD -> { + case "mod" -> { if (player.hasPermission("cytonic.chat.mod")) { Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.MOD); - player.sendMessage( - Component.text("You are now in the ", NamedTextColor.GREEN) - .append(Component.text("MOD", NamedTextColor.GOLD)) - .append(Component.text(" channel.", NamedTextColor.GREEN)) - ); + player.sendMessage(Component.text("You are now in the ", NamedTextColor.GREEN).append(Component.text("MOD", NamedTextColor.GOLD)).append(Component.text(" channel.", NamedTextColor.GREEN))); } else { player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); } } - case STAFF -> { + case "staff" -> { if (player.hasPermission("cytonic.chat.staff")) { Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.STAFF); - player.sendMessage( - Component.text("You are now in the ", NamedTextColor.GREEN) - .append(Component.text("STAFF", NamedTextColor.GOLD)) - .append(Component.text(" channel.", NamedTextColor.GREEN)) - ); + player.sendMessage(Component.text("You are now in the ", NamedTextColor.GREEN).append(Component.text("STAFF", NamedTextColor.GOLD)).append(Component.text(" channel.", NamedTextColor.GREEN))); } else { player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); } } - case PARTY -> { - player.sendMessage("party"); - } - case LEAGUE -> { - player.sendMessage("league"); - } - case PRIVATE_MESSAGE -> { - player.sendMessage("private message"); - } + case "party" -> player.sendMessage("party"); + case "league" -> player.sendMessage("league"); + case "private message" -> player.sendMessage("private message"); } } else { sender.sendMessage(Component.text("Hey! You can't do this.", NamedTextColor.RED)); @@ -102,20 +91,12 @@ public ChatChannelCommand() { switch (channel.toLowerCase()) { case "a" -> { Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.ALL); - player.sendMessage( - Component.text("You are now in the ", NamedTextColor.GREEN) - .append(Component.text("ALL", NamedTextColor.GOLD)) - .append(Component.text(" channel.", NamedTextColor.GREEN)) - ); + player.sendMessage(Component.text("You are now in the ", NamedTextColor.GREEN).append(Component.text("ALL", NamedTextColor.GOLD)).append(Component.text(" channel.", NamedTextColor.GREEN))); } case "ad" -> { if (player.hasPermission("cytonic.chat.admin")) { Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.ADMIN); - player.sendMessage( - Component.text("You are now in the ", NamedTextColor.GREEN) - .append(Component.text("ADMIN", NamedTextColor.GOLD)) - .append(Component.text(" channel.", NamedTextColor.GREEN)) - ); + player.sendMessage(Component.text("You are now in the ", NamedTextColor.GREEN).append(Component.text("ADMIN", NamedTextColor.GOLD)).append(Component.text(" channel.", NamedTextColor.GREEN))); } else { player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); } @@ -123,11 +104,7 @@ public ChatChannelCommand() { case "m" -> { if (player.hasPermission("cytonic.chat.mod")) { Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.MOD); - player.sendMessage( - Component.text("You are now in the ", NamedTextColor.GREEN) - .append(Component.text("MOD", NamedTextColor.GOLD)) - .append(Component.text(" channel.", NamedTextColor.GREEN)) - ); + player.sendMessage(Component.text("You are now in the ", NamedTextColor.GREEN).append(Component.text("MOD", NamedTextColor.GOLD)).append(Component.text(" channel.", NamedTextColor.GREEN))); } else { player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); } @@ -135,26 +112,19 @@ public ChatChannelCommand() { case "s" -> { if (player.hasPermission("cytonic.chat.staff")) { Cytosis.getChatManager().setChannel(player.getUuid(), ChatChannel.STAFF); - player.sendMessage( - Component.text("You are now in the ", NamedTextColor.GREEN) - .append(Component.text("STAFF", NamedTextColor.GOLD)) - .append(Component.text(" channel.", NamedTextColor.GREEN)) - ); + player.sendMessage(Component.text("You are now in the ", NamedTextColor.GREEN).append(Component.text("STAFF", NamedTextColor.GOLD)).append(Component.text(" channel.", NamedTextColor.GREEN))); } else { player.sendMessage(Component.text("You do not have access to this channel.", NamedTextColor.RED)); } } - case "p" -> { - player.sendMessage("party"); - } - case "l" -> { - player.sendMessage("league"); - } - default -> player.sendMessage(Component.text(STR."The shorthand '\{channel}' is invalid!", NamedTextColor.RED)); + case "p" -> player.sendMessage("party"); + case "l" -> player.sendMessage("league"); + default -> + player.sendMessage(Component.text(STR."The shorthand '\{channel}' is invalid!", NamedTextColor.RED)); } } else { sender.sendMessage(Component.text("Hey! You can't do this.", NamedTextColor.RED)); } }, shorthand); -} + } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/commands/RankCommand.java b/src/main/java/net/cytonic/cytosis/commands/RankCommand.java index 4b67c464..74c5c121 100644 --- a/src/main/java/net/cytonic/cytosis/commands/RankCommand.java +++ b/src/main/java/net/cytonic/cytosis/commands/RankCommand.java @@ -77,4 +77,4 @@ private void setRank(Player player, PlayerRank rank, CommandSender sender) { sender.sendMessage(MM."Successfully updated \{player.getUsername()}'s rank!"); }); } -} +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java index 7ea6435f..1ffc596e 100644 --- a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java +++ b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java @@ -27,7 +27,8 @@ public class CytosisSettings { public static String SERVER_SECRET = ""; public static int SERVER_PORT = 25565; public static String SERVER_WORLD_NAME = ""; - public static Pos SERVER_SPAWN_POS = new Pos(0,1,0); + public static Pos SERVER_SPAWN_POS = new Pos(0, 1, 0); + public static String SERVER_HOSTNAME = "UNKNOWN"; // RabbitMQ public static boolean RABBITMQ_ENABLED = false; public static String RABBITMQ_HOST = ""; @@ -45,7 +46,6 @@ public static void inportConfig(Map config) { case "logging.player_quit" -> LOG_PLAYER_QUITS = (boolean) value; case "logging.player_command" -> LOG_PLAYER_COMMANDS = (boolean) value; case "logging.player_chat" -> LOG_PLAYER_CHAT = (boolean) value; - // database case "database.enabled" -> DATABASE_ENABLED = (boolean) value; case "database.user" -> DATABASE_USER = (String) value; @@ -54,14 +54,13 @@ public static void inportConfig(Map config) { case "database.port" -> DATABASE_PORT = toInt(value); case "database.name" -> DATABASE_NAME = (String) value; case "database.use_ssl" -> DATABASE_USE_SSL = (boolean) value; - // server case "server.proxy_mode" -> SERVER_PROXY_MODE = (boolean) value; case "server.secret" -> SERVER_SECRET = (String) value; case "server.port" -> SERVER_PORT = toInt(value); case "server.world_name" -> SERVER_WORLD_NAME = (String) value; case "server.spawn_point" -> SERVER_SPAWN_POS = PosSerializer.deserialize((String) value); - + case "server.hostname" -> SERVER_HOSTNAME = (String) value; // RabbitMQ case "rabbitmq.host" -> RABBITMQ_HOST = (String) value; case "rabbitmq.password" -> RABBITMQ_PASSWORD = (String) value; @@ -103,6 +102,7 @@ public static void loadEnvironmentVariables() { if (!(System.getenv("SERVER_PORT") == null)) CytosisSettings.SERVER_PORT = Integer.parseInt(System.getenv("SERVER_PORT")); if (!(System.getenv("SERVER_WORLD_NAME") == null)) CytosisSettings.SERVER_WORLD_NAME = System.getenv("SERVER_WORLD_NAME"); if (!(System.getenv("SERVER_SPAWN_POINT") == null)) CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(System.getenv("SERVER_SPAWN_POINT")); + if (!(System.getenv("SERVER_HOSTNAME") == null)) CytosisSettings.SERVER_HOSTNAME = System.getenv("SERVER_HOSTNAME"); // RabbitMQ if (!(System.getenv("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getenv("RABBITMQ_ENABLED")); if (!(System.getenv("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getenv("RABBITMQ_HOST"); @@ -131,6 +131,7 @@ public static void loadCommandArgs() { if (!(System.getProperty("SERVER_PORT") == null)) CytosisSettings.SERVER_PORT = Integer.parseInt(System.getProperty("SERVER_PORT")); if (!(System.getProperty("SERVER_WORLD_NAME") == null)) CytosisSettings.SERVER_WORLD_NAME = System.getProperty("SERVER_WORLD_NAME"); if (!(System.getProperty("SERVER_SPAWN_POINT") == null)) CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(System.getProperty("SERVER_SPAWN_POINT")); + if (!(System.getProperty("SERVER_HOSTNAME") == null)) CytosisSettings.SERVER_HOSTNAME = System.getProperty("SERVER_HOSTNAME"); // RabbitMQ if (!(System.getProperty("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getProperty("RABBITMQ_ENABLED")); if (!(System.getProperty("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getProperty("RABBITMQ_HOST"); diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index 0478a111..f634c400 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -10,9 +10,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - +import net.cytonic.cytosis.data.enums.ChatChannel; import org.jetbrains.annotations.NotNull; - import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.config.CytosisSettings; import net.cytonic.cytosis.logging.Logger; @@ -67,7 +66,6 @@ public void connect() { } } }); - } public void disconnect() { @@ -135,16 +133,6 @@ private void createRanksTable() { }); } - public void createNameTable() { - PreparedStatement ps; - try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonicnames (uuid VARCHAR(36), name VARCHAR(16), PRIMARY KEY(uuid))"); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_names` table.", e); - } - } - /** * Creates the 'cytonic_worlds' table in the database if it doesn't exist. * The table contains information about the worlds stored in the database. @@ -165,19 +153,25 @@ public void createWorldTable() { }); } - private void createChatChannelsTable() { - worker.submit(() -> { - if (isConnected()) { - PreparedStatement ps; - try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat_channels (player_uuid VARCHAR(36), chat_channel TEXT, PRIMARY KEY(player_uuid))"); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_chat_channels` table.", e); - } + /** + * Creates the 'cytonic_chat_channels' table in the database if it doesn't exist. + * The table contains information about player's chat channels. + * + * @throws IllegalStateException if the database connection is not open. + */ +private void createChatChannelsTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat_channels (uuid VARCHAR(36), chat_channel TEXT, PRIMARY KEY(uuid))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_chat_channels` table.", e); } - }); - } + } + }); +} private void createPlayerJoinsTable() { worker.submit(() -> { @@ -264,43 +258,46 @@ public void addChat(UUID uuid, String message) { ps.setString(2, message); ps.executeUpdate(); } catch (SQLException e) { - Logger.error("An error occurred whilst adding a chat message.",e); + Logger.error("An error occurred whilst adding a chat message.", e); } }); } - public String getName(UUID uuid) { - PreparedStatement ps; - try { - ps = connection.prepareStatement("SELECT name FROM cytonicnames WHERE uuid = ?"); - ps.setString(1, uuid.toString()); - ResultSet rs = ps.executeQuery(); - if (rs.next()) { - return rs.getString("name"); + public void setChatChannel(UUID uuid, ChatChannel chatChannel) { + worker.submit(() -> { + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to add a player's chat!"); + PreparedStatement ps; + try { + ps = connection.prepareStatement("INSERT INTO cytonic_chat_channels (uuid, chat_channel) VALUES (?, ?) ON DUPLICATE KEY UPDATE chat_channel = VALUES(chat_channel)"); + ps.setString(1, uuid.toString()); + ps.setString(2, chatChannel.name()); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst setting a players chat channel.", e); } - } catch (SQLException e) { - Logger.error(STR."An error occurred whilst fetching the name of '\{uuid}'"); - } - return "ERROR!"; + }); } - public UUID getUUID(String name) { - PreparedStatement ps; - try { - ps = connection.prepareStatement("SELECT uuid FROM cytonicnames WHERE name = ?"); - ps.setString(1, name); - ResultSet rs = ps.executeQuery(); - if (rs.next()) { - try { - return UUID.fromString(rs.getString("uuid")); - } catch (IllegalArgumentException ex) { - return null; + public CompletableFuture getChatChannel(@NotNull final UUID uuid) { + CompletableFuture future = new CompletableFuture<>(); + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to fetch a player's chat channel!"); + worker.submit(() -> { + String channel = "ALL"; + try { + PreparedStatement ps = connection.prepareStatement("SELECT chat_channel FROM cytonic_chat_channels WHERE uuid = ?"); + ps.setString(1, uuid.toString()); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + channel = rs.getString("chat_channel"); } + future.complete(ChatChannel.valueOf(channel)); + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst fetching the chat channel of '\{uuid}'", e); } - } catch (SQLException e) { - Logger.error(STR."An error occurred whilst fetching the uuid of '\{name}'"); - } - return null; + }); + return future; } /** @@ -363,26 +360,26 @@ public CompletableFuture getWorld(String worldName) { } /** - * Logs a player's join event to the database. - * - * @param uuid The unique identifier of the player. - * @param ip The IP address of the player. - *

- * This method uses a worker thread to execute the database operation. - * It prepares a SQL statement to insert a new record into the 'cytonic_player_joins' table. - * The 'joined' column is set to the current timestamp, the 'uuid' column is set to the provided UUID, - * and the 'ip' column is set to the provided IP address. - * If an error occurs during the database operation, it is logged using the Logger. - */ -public void logPlayerJoin(UUID uuid, SocketAddress ip) { - worker.submit(() -> { - try (PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_player_joins (joined, uuid, ip) VALUES (CURRENT_TIMESTAMP,?,?)")) { - ps.setString(1, uuid.toString()); - ps.setString(2, ip.toString()); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("Failed to add a player to the database!", e); - } - }); -} + * Logs a player's join event to the database. + * + * @param uuid The unique identifier of the player. + * @param ip The IP address of the player. + *

+ * This method uses a worker thread to execute the database operation. + * It prepares a SQL statement to insert a new record into the 'cytonic_player_joins' table. + * The 'joined' column is set to the current timestamp, the 'uuid' column is set to the provided UUID, + * and the 'ip' column is set to the provided IP address. + * If an error occurs during the database operation, it is logged using the Logger. + */ + public void logPlayerJoin(UUID uuid, SocketAddress ip) { + worker.submit(() -> { + try (PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_player_joins (joined, uuid, ip) VALUES (CURRENT_TIMESTAMP,?,?)")) { + ps.setString(1, uuid.toString()); + ps.setString(2, ip.toString()); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("Failed to add a player to the database!", e); + } + }); + } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/data/objects/Request.java b/src/main/java/net/cytonic/cytosis/data/objects/Request.java deleted file mode 100644 index 0278e3e8..00000000 --- a/src/main/java/net/cytonic/cytosis/data/objects/Request.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.cytonic.cytosis.data.objects; - -import java.time.Instant; -import java.util.UUID; - -public class Request { - private final Instant expiry; - private final UUID author; - private final UUID target; - private final RequestType type; - private final Instant issuedAt; - private boolean accepted; - private boolean declined; - - public Request(Instant expiry, UUID author, UUID target, RequestType type) { - this.expiry = expiry; - this.author = author; - this.target = target; - this.type = type; - issuedAt = Instant.now(); - accepted = false; - declined = false; - } - - public Instant getExpiry() { - return expiry; - } - - public RequestType getType() { - return type; - } - - public Instant getIssuedAt() { - return issuedAt; - } - - public UUID getAuthor() { - return author; - } - - public UUID getTarget() { - return target; - } - - public boolean isAccepted() { - return accepted; - } - - public boolean isDeclined() { - return declined; - } - - public void setAccepted(boolean accepted) { - this.accepted = accepted; - } - - public void setDeclined(boolean declined) { - this.declined = declined; - } - - public enum RequestType { - FRIEND, - LEAGUE, - PARTY - } -} diff --git a/src/main/java/net/cytonic/cytosis/events/EventHandler.java b/src/main/java/net/cytonic/cytosis/events/EventHandler.java index 021f3c54..cb4b75dc 100644 --- a/src/main/java/net/cytonic/cytosis/events/EventHandler.java +++ b/src/main/java/net/cytonic/cytosis/events/EventHandler.java @@ -79,8 +79,7 @@ public boolean registerListener(EventListener listener) { public void handleEvent(T event) { List> matchingListeners = new ArrayList<>(); for (EventListener listener : NAMESPACED_HANDLERS.values()) { - if (listener.getEventClass() == event.getClass() && - !(event instanceof CancellableEvent && ((CancellableEvent) event).isCancelled())) { + if (listener.getEventClass() == event.getClass() && !(event instanceof CancellableEvent && ((CancellableEvent) event).isCancelled())) { matchingListeners.add(listener); } } @@ -184,7 +183,6 @@ private void setupInternalListeners() { GLOBAL_HANDLER.addListener(ClientPingServerEvent.class, (this::handleEvent)); GLOBAL_HANDLER.addListener(ServerListPingEvent.class, (this::handleEvent)); GLOBAL_HANDLER.addListener(ServerTickMonitorEvent.class, (this::handleEvent)); - // Cytosis Events GLOBAL_HANDLER.addListener(RankSetupEvent.class, (this::handleEvent)); GLOBAL_HANDLER.addListener(RankChangeEvent.class, (this::handleEvent)); diff --git a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java index 60f541a4..6c9fa00a 100644 --- a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java +++ b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java @@ -5,12 +5,12 @@ import net.cytonic.cytosis.data.enums.ChatChannel; import net.cytonic.cytosis.logging.Logger; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.entity.Player; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.PlayerChatEvent; import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.event.player.PlayerSpawnEvent; +import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; public class ServerEventListeners { @@ -28,6 +28,11 @@ public static void initServerEvents() { Logger.info(STR."\{player.getUsername()} (\{player.getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); Cytosis.getDatabaseManager().getDatabase().logPlayerJoin(player.getUuid(), player.getPlayerConnection().getRemoteAddress()); Cytosis.getRankManager().addPlayer(player); + Cytosis.getDatabaseManager().getDatabase().getChatChannel(player.getUuid()).whenComplete(((chatChannel, throwable) -> { + if (throwable != null) { + Logger.error("An error occurred whilst getting a player's chat channel!", throwable); + } else Cytosis.getChatManager().setChannel(player.getUuid(), chatChannel); + })); }))); Logger.info("Registering player chat event."); @@ -37,23 +42,29 @@ public static void initServerEvents() { Cytosis.getDatabaseManager().getDatabase().addChat(player.getUuid(), event.getMessage()); event.setCancelled(true); String originalMessage = event.getMessage(); - if(Cytosis.getChatManager().getChannel(player.getUuid()) != ChatChannel.ALL) { - ChatChannel channel = Cytosis.getChatManager().getChannel(player.getUuid()); - Component message = Component.text("") - .append(channel.getPrefix()) - .append(Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getPrefix()) - .append(Component.text(player.getUsername(), (Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor()))) - .appendSpace() - .append(Component.text(originalMessage, NamedTextColor.WHITE)); + if (!originalMessage.contains("|")) { + if (Cytosis.getChatManager().getChannel(player.getUuid()) != ChatChannel.ALL) { + ChatChannel channel = Cytosis.getChatManager().getChannel(player.getUuid()); + Component message = Component.text("") + .append(channel.getPrefix()) + .append(Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getPrefix()) + .appendSpace() + .append(Component.text(player.getUsername(), (Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getTeamColor()))) + .append(Component.text(":", Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor())) + .appendSpace() + .append(Component.text(originalMessage, Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor())); Cytosis.getChatManager().sendMessageToChannel(message, Cytosis.getChatManager().getChannel(player.getUuid())); } else { Component message = Component.text("") - .append(Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getPrefix()) - .append(Component.text(player.getUsername(), (Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor()))) - .appendSpace() - .append(Component.text(originalMessage, NamedTextColor.WHITE)); - Cytosis.getOnlinePlayers().forEach((p) -> {p.sendMessage(message);}); + .append(Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getPrefix()) + .appendSpace() + .append(Component.text(player.getUsername(), (Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getTeamColor()))) + .append(Component.text(":", Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor())) + .appendSpace() + .append(Component.text(originalMessage, Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor())); + Cytosis.getOnlinePlayers().forEach((p) -> p.sendMessage(message)); } + } else player.sendMessage(MM."Hey you cannot do that!"); })); Logger.info("Registering player disconnect event."); @@ -62,22 +73,4 @@ public static void initServerEvents() { Cytosis.getRankManager().removePlayer(player); })); } - - public static void chatEvent(PlayerChatEvent event) { - Player player = event.getPlayer(); - if(Cytosis.getChatManager().getChannel(player.getUuid()) != ChatChannel.ALL) { - ChatChannel channel = Cytosis.getChatManager().getChannel(player.getUuid()); - event.setCancelled(true); - String originalMessage = event.getMessage(); - Component message = Component.text("") - .append(channel.getPrefix()) - .append(Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getPrefix()) - .append(Component.text(player.getUsername(), (Cytosis.getRankManager().getPlayerRank(player.getUuid()).orElseThrow().getChatColor()))) - .appendSpace() - .append(Component.text(originalMessage, NamedTextColor.WHITE)); - Cytosis.getChatManager().sendMessageToChannel(message, Cytosis.getChatManager().getChannel(player.getUuid())); - } else { - event.setCancelled(false); - } - } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/events/ranks/RankChangeEvent.java b/src/main/java/net/cytonic/cytosis/events/ranks/RankChangeEvent.java index 325788c1..364f0bb5 100644 --- a/src/main/java/net/cytonic/cytosis/events/ranks/RankChangeEvent.java +++ b/src/main/java/net/cytonic/cytosis/events/ranks/RankChangeEvent.java @@ -28,4 +28,4 @@ public boolean isCancelled() { public void setCancelled(boolean cancel) { this.canceled = cancel; } -} +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/events/ranks/RankSetupEvent.java b/src/main/java/net/cytonic/cytosis/events/ranks/RankSetupEvent.java index fd06ecf1..a85f4df4 100644 --- a/src/main/java/net/cytonic/cytosis/events/ranks/RankSetupEvent.java +++ b/src/main/java/net/cytonic/cytosis/events/ranks/RankSetupEvent.java @@ -27,4 +27,4 @@ public boolean isCancelled() { public void setCancelled(boolean canceled) { this.canceled = canceled; } -} +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/files/FileManager.java b/src/main/java/net/cytonic/cytosis/files/FileManager.java index 2514c57c..ec35fd4f 100644 --- a/src/main/java/net/cytonic/cytosis/files/FileManager.java +++ b/src/main/java/net/cytonic/cytosis/files/FileManager.java @@ -41,7 +41,6 @@ public CompletableFuture init() { */ public CompletableFuture createConfigFile() { CompletableFuture future = new CompletableFuture<>(); - worker.submit(() -> { if (!CONFIG_PATH.toFile().exists()) { Logger.info("No config file found, creating..."); @@ -131,14 +130,12 @@ private Map recursiveParse(Map map, String paren // If it's a list, check for nested tables within the list else if (value instanceof Iterable iterable) { for (Object item : iterable) { - if (item instanceof TomlTable toml) - resultMap.putAll(recursiveParse(toml.toMap(), key)); + if (item instanceof TomlTable toml) resultMap.putAll(recursiveParse(toml.toMap(), key)); } } else { resultMap.put(key, value); } } - return resultMap; } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/managers/ChatManager.java b/src/main/java/net/cytonic/cytosis/managers/ChatManager.java index dca764c9..35af4364 100644 --- a/src/main/java/net/cytonic/cytosis/managers/ChatManager.java +++ b/src/main/java/net/cytonic/cytosis/managers/ChatManager.java @@ -3,7 +3,6 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; - import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.data.enums.ChatChannel; import net.kyori.adventure.text.Component; @@ -11,11 +10,14 @@ public class ChatManager { private final Map channels = new HashMap<>(); + public void removeChannel(UUID uuid) { channels.remove(uuid); } + public void setChannel(UUID uuid, ChatChannel channel) { channels.put(uuid, channel); + Cytosis.getDatabaseManager().getDatabase().setChatChannel(uuid,channel); } public ChatChannel getChannel(UUID uuid) { @@ -24,7 +26,7 @@ public ChatChannel getChannel(UUID uuid) { public void sendMessageToChannel(Component component, ChatChannel chatChannel) { switch (chatChannel) { - case ADMIN,MOD,STAFF -> // send a message to all servers + case ADMIN, MOD, STAFF -> // send a message to all servers Cytosis.getMessagingManager().getRabbitMQ().sendChatMessage(component, chatChannel); case PARTY -> { // parties.. @@ -35,8 +37,8 @@ public void sendMessageToChannel(Component component, ChatChannel chatChannel) { case PRIVATE_MESSAGE -> { // private messages } - case ALL -> throw new UnsupportedOperationException("Unimplemented case: " + chatChannel); - default -> throw new IllegalArgumentException("Unexpected value: " + chatChannel); + case ALL -> throw new UnsupportedOperationException(STR."Unimplemented case: \{chatChannel}"); + default -> throw new IllegalArgumentException(STR."Unexpected value: \{chatChannel}"); } } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java b/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java index 52f1c379..97200fd1 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java +++ b/src/main/java/net/cytonic/cytosis/messaging/MessagingManager.java @@ -6,11 +6,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - import lombok.Getter; import net.cytonic.cytosis.config.CytosisSettings; -import net.cytonic.cytosis.data.enums.ChatChannel; -import net.kyori.adventure.text.Component; public class MessagingManager { @@ -32,7 +29,6 @@ public CompletableFuture initialize() { rabbitMQ.initializeQueues(); rabbitMQ.sendServerDeclarationMessage(); rabbitMQ.receiveChatMessages(); - rabbitMQ.sendChatMessage(Component.text("hello world!"), ChatChannel.ADMIN); } future.complete(null); }); diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index 43be151d..2af3a534 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -1,9 +1,10 @@ package net.cytonic.cytosis.messaging; import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; +import java.net.*; +import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.*; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -31,6 +32,7 @@ public class RabbitMQ { public static final String SERVER_DECLARE_QUEUE = "server-declaration"; public static final String SHUTDOWN_QUEUE = "server-shutdown"; + public static final String CHAT_CHANNEL_QUEUE = STR."chat-channel-\{Cytosis.SERVER_ID}"; public static final String CHAT_CHANNEL_QUEUE = "chat-channel"; public static final String PLAYER_KICK_QUEUE = "player-kick"; private Connection connection; @@ -50,8 +52,7 @@ public void initializeConnection() { Logger.info("Connected to RabbitMQ!"); try { channel = connection.createChannel(); - connection = factory.newConnection(); - } catch (IOException | TimeoutException e) { + } catch (IOException e) { Logger.error("An error occurred whilst connecting to RabbitMQ!", e); } } @@ -69,9 +70,9 @@ public void initializeQueues() { Logger.error("An error occurred whilst initializing the 'SHUTDOWN_QUEUE'.", e); } try { + channel.exchangeDeclare("chat-testing", BuiltinExchangeType.FANOUT); channel.queueDeclare(CHAT_CHANNEL_QUEUE, false, false, false, null); - channel.exchangeDeclare("chat-messages", "fanout"); - channel.queueBind(CHAT_CHANNEL_QUEUE, "chat-messages", ""); + channel.queueBind(CHAT_CHANNEL_QUEUE,"chat-testing",""); } catch (IOException e) { Logger.error("An error occurred whilst initializing the 'CHAT_CHANNEL_QUEUE'.", e); } @@ -155,21 +156,51 @@ public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { Logger.error("An error occurred whilst attempting to send a chat message!", e); } } + /** + * Sends a chat message to all the servers. + * + * @param chatMessage The chat message to be sent. This should be a {@link Component}. + * @param chatChannel The channel to which the chat message should be sent. + * + */ +public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { + // Formatting: {chat-message}|:|{chat-channel} + String message = STR."\{JSONComponentSerializer.json().serialize(chatMessage)}|\{chatChannel.name()}"; + try { + channel.basicPublish("chat-testing","", null, message.getBytes()); + } catch (IOException e) { + Logger.error("An error occurred whilst attempting to send a chat message!", e); + } +} public void receiveChatMessages() { try { - DeliverCallback deliverCallback = (consumerTag, delivery) -> { - String[] thing = new String(delivery.getBody(), "UTF-8").split("\\|"); - Component chatMessage = JSONComponentSerializer.json().deserialize(thing[0]); - ChatChannel chatChannel = ChatChannel.valueOf(thing[1]); - switch (chatChannel) { - case MOD -> // send a message to all players with cytonic.chat.mod permission - Cytosis.getOnlinePlayers().forEach(player -> { - if (player.hasPermission("cytonic.chat.mod")) { - player.sendMessage(chatMessage); - } - }); - + DeliverCallback deliverCallback = (_, delivery) -> { + String[] thing = new String(delivery.getBody(), StandardCharsets.UTF_8).split("\\|"); + Component chatMessage = JSONComponentSerializer.json().deserialize(thing[0]); + ChatChannel chatChannel = ChatChannel.valueOf(thing[1]); + switch (chatChannel) { + case MOD -> // send a message to all players with cytonic.chat.mod permission + Cytosis.getOnlinePlayers().forEach(player -> { + if (player.hasPermission("cytonic.chat.mod")) { + player.sendMessage(chatMessage); + } + }); + + case STAFF -> // send a message to all players with cytonic.chat.staff permission + Cytosis.getOnlinePlayers().forEach(player -> { + if (player.hasPermission("cytonic.chat.staff")) { + player.sendMessage(chatMessage); + } + }); + case ADMIN -> // send a message to all players with cytonic.chat.admin permission + Cytosis.getOnlinePlayers().forEach(player -> { + if (player.hasPermission("cytonic.chat.admin")) { + player.sendMessage(chatMessage); + } + }); + case LEAGUE -> {// leagues.. + } case STAFF -> // send a message to all players with cytonic.chat.staff permission Cytosis.getOnlinePlayers().forEach(player -> { if (player.hasPermission("cytonic.chat.staff")) { @@ -186,14 +217,13 @@ public void receiveChatMessages() { // leagues.. } - case PARTY -> { - // parties.. - } + case PARTY -> {// parties.. + } + } + }; + channel.basicConsume(CHAT_CHANNEL_QUEUE, true, deliverCallback, _ -> {}); + } catch (IOException e) { + Logger.error("error", e); } - }; - channel.basicConsume(CHAT_CHANNEL_QUEUE, true, deliverCallback, consumerTag -> { }); -} catch (IOException e) { - Logger.error("error", e); -} -} + } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java b/src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java index 606cf646..f63d0a38 100644 --- a/src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java +++ b/src/main/java/net/cytonic/cytosis/ranks/PlayerRank.java @@ -57,13 +57,11 @@ public static boolean canChangeRank(PlayerRank currentUserRole, PlayerRank targe if (isDemotion(targetOriginalRole, targetNewRole)) { return currentUserRole.ordinal() <= targetOriginalRole.ordinal(); } - if (isPromotion(targetOriginalRole, targetNewRole)) { return currentUserRole.ordinal() <= targetOriginalRole.ordinal(); } - // If it's neither promotion nor demotion, it's an invalid operation return false; } -} +} \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/ranks/RankManager.java b/src/main/java/net/cytonic/cytosis/ranks/RankManager.java index f40b6ca4..97c137e0 100644 --- a/src/main/java/net/cytonic/cytosis/ranks/RankManager.java +++ b/src/main/java/net/cytonic/cytosis/ranks/RankManager.java @@ -12,7 +12,6 @@ import net.minestom.server.scoreboard.Team; import net.minestom.server.scoreboard.TeamBuilder; import org.jetbrains.annotations.NotNull; - import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -28,7 +27,6 @@ public void init() { .teamColor(value.getTeamColor()) .prefix(value.getPrefix().appendSpace()) .build(); - teamMap.put(value, team); } } @@ -83,4 +81,4 @@ public final void removePermissions(@NotNull final Player player, @NotNull final public Optional getPlayerRank(UUID uuid) { return Optional.ofNullable(rankMap.get(uuid)); } -} +} \ No newline at end of file diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index aed1bcfe..9d0743eb 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -20,6 +20,7 @@ secret = "hi i am the secret" # this can NOT be empty port = 25565 world_name = "" spawn_point = "" +hostname = "UNKNOWN" # Logging Configuration # Enable/disable logging for various player activities From 6f4de764e67adf9a7195de4d9a2ca68821f2b9fa Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Sat, 25 May 2024 17:26:04 -0500 Subject: [PATCH 38/55] Add todo --- src/main/java/net/cytonic/cytosis/managers/ChatManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/managers/ChatManager.java b/src/main/java/net/cytonic/cytosis/managers/ChatManager.java index 35af4364..efa707e5 100644 --- a/src/main/java/net/cytonic/cytosis/managers/ChatManager.java +++ b/src/main/java/net/cytonic/cytosis/managers/ChatManager.java @@ -29,13 +29,13 @@ public void sendMessageToChannel(Component component, ChatChannel chatChannel) { case ADMIN, MOD, STAFF -> // send a message to all servers Cytosis.getMessagingManager().getRabbitMQ().sendChatMessage(component, chatChannel); case PARTY -> { - // parties.. + //todo parties.. } case LEAGUE -> { - // leagues.. + //todo leagues.. } case PRIVATE_MESSAGE -> { - // private messages + //todo private messages } case ALL -> throw new UnsupportedOperationException(STR."Unimplemented case: \{chatChannel}"); default -> throw new IllegalArgumentException(STR."Unexpected value: \{chatChannel}"); From 4d541058e2ccad049f29b92efdb5d597d244d12f Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Sat, 25 May 2024 17:27:03 -0500 Subject: [PATCH 39/55] Change channel type --- src/main/java/net/cytonic/cytosis/data/Database.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index f634c400..8b74c9a4 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -164,7 +164,7 @@ private void createChatChannelsTable() { if (isConnected()) { PreparedStatement ps; try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat_channels (uuid VARCHAR(36), chat_channel TEXT, PRIMARY KEY(uuid))"); + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat_channels (uuid VARCHAR(36), chat_channel VARCHAR(16), PRIMARY KEY(uuid))"); ps.executeUpdate(); } catch (SQLException e) { Logger.error("An error occurred whilst creating the `cytonic_chat_channels` table.", e); From 4f4f81f233c7b7501ec2e422d5c4dfdf5e0a1162 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Sat, 25 May 2024 17:27:53 -0500 Subject: [PATCH 40/55] Add a variable for the chat channel exchange --- src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index 2af3a534..a84b1fd6 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -35,6 +35,7 @@ public class RabbitMQ { public static final String CHAT_CHANNEL_QUEUE = STR."chat-channel-\{Cytosis.SERVER_ID}"; public static final String CHAT_CHANNEL_QUEUE = "chat-channel"; public static final String PLAYER_KICK_QUEUE = "player-kick"; + public static final String CHAT_CHANNEL_EXCHANGE = "chat-exchange"; private Connection connection; private Channel channel; @@ -70,9 +71,9 @@ public void initializeQueues() { Logger.error("An error occurred whilst initializing the 'SHUTDOWN_QUEUE'.", e); } try { - channel.exchangeDeclare("chat-testing", BuiltinExchangeType.FANOUT); + channel.exchangeDeclare(CHAT_CHANNEL_EXCHANGE, BuiltinExchangeType.FANOUT); channel.queueDeclare(CHAT_CHANNEL_QUEUE, false, false, false, null); - channel.queueBind(CHAT_CHANNEL_QUEUE,"chat-testing",""); + channel.queueBind(CHAT_CHANNEL_QUEUE,CHAT_CHANNEL_EXCHANGE,""); } catch (IOException e) { Logger.error("An error occurred whilst initializing the 'CHAT_CHANNEL_QUEUE'.", e); } @@ -167,7 +168,7 @@ public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { // Formatting: {chat-message}|:|{chat-channel} String message = STR."\{JSONComponentSerializer.json().serialize(chatMessage)}|\{chatChannel.name()}"; try { - channel.basicPublish("chat-testing","", null, message.getBytes()); + channel.basicPublish(CHAT_CHANNEL_EXCHANGE,"", null, message.getBytes()); } catch (IOException e) { Logger.error("An error occurred whilst attempting to send a chat message!", e); } From 4a4cb716483078b7aa72c86a039bb210bf12d487 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Sun, 26 May 2024 22:04:16 -0500 Subject: [PATCH 41/55] Fix indentation --- .../cytonic/cytosis/messaging/RabbitMQ.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index a84b1fd6..8492a249 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -73,7 +73,7 @@ public void initializeQueues() { try { channel.exchangeDeclare(CHAT_CHANNEL_EXCHANGE, BuiltinExchangeType.FANOUT); channel.queueDeclare(CHAT_CHANNEL_QUEUE, false, false, false, null); - channel.queueBind(CHAT_CHANNEL_QUEUE,CHAT_CHANNEL_EXCHANGE,""); + channel.queueBind(CHAT_CHANNEL_QUEUE, CHAT_CHANNEL_EXCHANGE, ""); } catch (IOException e) { Logger.error("An error occurred whilst initializing the 'CHAT_CHANNEL_QUEUE'.", e); } @@ -158,21 +158,20 @@ public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { } } /** - * Sends a chat message to all the servers. - * - * @param chatMessage The chat message to be sent. This should be a {@link Component}. - * @param chatChannel The channel to which the chat message should be sent. - * - */ -public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { - // Formatting: {chat-message}|:|{chat-channel} - String message = STR."\{JSONComponentSerializer.json().serialize(chatMessage)}|\{chatChannel.name()}"; - try { - channel.basicPublish(CHAT_CHANNEL_EXCHANGE,"", null, message.getBytes()); - } catch (IOException e) { - Logger.error("An error occurred whilst attempting to send a chat message!", e); + * Sends a chat message to all the servers. + * + * @param chatMessage The chat message to be sent. This should be a {@link Component}. + * @param chatChannel The channel to which the chat message should be sent. + */ + public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { + // Formatting: {chat-message}|:|{chat-channel} + String message = STR."\{JSONComponentSerializer.json().serialize(chatMessage)}|\{chatChannel.name()}"; + try { + channel.basicPublish(CHAT_CHANNEL_EXCHANGE, "", null, message.getBytes()); + } catch (IOException e) { + Logger.error("An error occurred whilst attempting to send a chat message!", e); + } } -} public void receiveChatMessages() { try { From 788bc80b05a37294c51e59b684b951d876c73386 Mon Sep 17 00:00:00 2001 From: webhead1104 Date: Tue, 28 May 2024 11:55:50 -0500 Subject: [PATCH 42/55] Fix massive bug --- src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index 8492a249..191a7f71 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -61,12 +61,12 @@ public void initializeConnection() { public void initializeQueues() { Logger.info("Initializing RabbitMQ queues..."); try { - channel.queueDeclare(SERVER_DECLARE_QUEUE, false, false, false, null); + channel.queueDeclare(SERVER_DECLARE_QUEUE, false, false, true, null); } catch (IOException e) { Logger.error("An error occurred whilst initializing the 'SERVER_DECLARE_QUEUE'.", e); } try { - channel.queueDeclare(SHUTDOWN_QUEUE, false, false, false, null); + channel.queueDeclare(SHUTDOWN_QUEUE, false, false, true, null); } catch (IOException e) { Logger.error("An error occurred whilst initializing the 'SHUTDOWN_QUEUE'.", e); } @@ -226,4 +226,4 @@ public void receiveChatMessages() { Logger.error("error", e); } } -} \ No newline at end of file +} From 282103a3ba4aae1af7b6398c0587483c541f5b2f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 17:08:41 +0000 Subject: [PATCH 43/55] Update dependency dev.hollowcube:polar to v1.9.4 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 607149b8..5ab14fcf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,7 +27,7 @@ dependencies { annotationProcessor("org.projectlombok:lombok:1.18.32") // lombok implementation("org.tomlj:tomlj:1.1.1") // Config lang implementation("com.rabbitmq:amqp-client:5.21.0") // Message broker - implementation("dev.hollowcube:polar:1.9.3") // Polar + implementation("dev.hollowcube:polar:1.9.4") // Polar } tasks.withType { From a6dfe1d36493810a905cf231647691ab087fac16 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:48:09 -0400 Subject: [PATCH 44/55] Create command to ban players --- src/main/java/net/cytonic/cytosis/commands/CommandHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java index 58e3eb12..70c048f5 100644 --- a/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java +++ b/src/main/java/net/cytonic/cytosis/commands/CommandHandler.java @@ -23,6 +23,7 @@ public void registerCytosisCommands() { CommandManager cm = Cytosis.getCommandManager(); cm.register(new GamemodeCommand()); cm.register(new RankCommand()); + cm.register(new BanCommand()); cm.register(new ChatChannelCommand()); cm.register(new BanCommand()); } From f4c03bc16b81af30a3893da8f2fcf6583b6b2c6d Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:48:32 -0400 Subject: [PATCH 45/55] Delete file --- src/main/java/net/cytonic/cytosis/data/Database.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java index 8b74c9a4..8cba8e70 100644 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ b/src/main/java/net/cytonic/cytosis/data/Database.java @@ -1,3 +1,4 @@ + package net.cytonic.cytosis.data; import java.net.SocketAddress; From 05bd6d64d6f2b02b050522e7bc57c03eac44c5b6 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:49:53 -0400 Subject: [PATCH 46/55] Update listeners with new functionality --- .../cytosis/events/ServerEventListeners.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java index 6c9fa00a..00116ee1 100644 --- a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java +++ b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java @@ -4,6 +4,9 @@ import net.cytonic.cytosis.config.CytosisSettings; import net.cytonic.cytosis.data.enums.ChatChannel; import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.messaging.KickReason; +import net.cytonic.cytosis.utils.MessageUtils; +import net.minestom.server.coordinate.Pos; import net.kyori.adventure.text.Component; import net.minestom.server.entity.Player; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; @@ -12,6 +15,8 @@ import net.minestom.server.event.player.PlayerSpawnEvent; import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; +import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; + public class ServerEventListeners { public static void initServerEvents() { @@ -24,6 +29,26 @@ public static void initServerEvents() { Logger.info("Registering player spawn event."); Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-spawn", false, 1, PlayerSpawnEvent.class, (event -> { + Cytosis.getDatabaseManager().getMysqlDatabase().isBanned(event.getPlayer().getUuid()).whenComplete((data, throwable) -> { + final Player player = event.getPlayer(); + if (throwable != null) { + Logger.error("An error occoured whilst checking if the player is banned!", throwable); + player.kick(MM."An error occured whilst initiating the login sequence!"); + return; + } + + if (data.isBanned()) { + Cytosis.getMessagingManager().getRabbitMQ().kickPlayer(player, KickReason.BANNED, MessageUtils.formatBanMessage(data)); + return; + } + + if (CytosisSettings.LOG_PLAYER_IPS) + Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); + else Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined."); + Cytosis.getDatabaseManager().getMysqlDatabase().addPlayer(player); + + Cytosis.getRankManager().addPlayer(player); + }); final Player player = event.getPlayer(); Logger.info(STR."\{player.getUsername()} (\{player.getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); Cytosis.getDatabaseManager().getDatabase().logPlayerJoin(player.getUuid(), player.getPlayerConnection().getRemoteAddress()); @@ -65,6 +90,7 @@ public static void initServerEvents() { Cytosis.getOnlinePlayers().forEach((p) -> p.sendMessage(message)); } } else player.sendMessage(MM."Hey you cannot do that!"); + Cytosis.getDatabaseManager().getMysqlDatabase().addChat(player.getUuid(), event.getMessage()); })); Logger.info("Registering player disconnect event."); From 2922617109d27b6b2e71b3fbe13ce1f0ac9726dc Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:51:03 -0400 Subject: [PATCH 47/55] Update methods to message more things --- .../cytonic/cytosis/messaging/RabbitMQ.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index 191a7f71..d9902aaa 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -1,5 +1,16 @@ package net.cytonic.cytosis.messaging; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import net.cytonic.cytosis.Cytosis; +import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.logging.Logger; +import net.cytonic.cytosis.utils.OfflinePlayer; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; +import net.minestom.server.entity.Player; + import java.io.IOException; import java.net.*; import java.nio.charset.StandardCharsets; @@ -36,6 +47,7 @@ public class RabbitMQ { public static final String CHAT_CHANNEL_QUEUE = "chat-channel"; public static final String PLAYER_KICK_QUEUE = "player-kick"; public static final String CHAT_CHANNEL_EXCHANGE = "chat-exchange"; + public static final String PLAYER_KICK_QUEUE = "player-kick"; private Connection connection; private Channel channel; @@ -227,3 +239,51 @@ public void receiveChatMessages() { } } } + + + public void sendServerShutdownMessage() { + //formatting: {server-name}|:|{server-ip}|:|{server-port} + String serverIP; + try { + serverIP = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + Logger.error("An error occoured whilst fetching this server's IP address! Bailing out!", e); + return; + } + String message = STR."\{Cytosis.SERVER_ID}|:|\{serverIP}|:|\{CytosisSettings.SERVER_PORT}"; + try { + channel.basicPublish("", SHUTDOWN_QUEUE, null, message.getBytes()); + } catch (IOException e) { + Logger.error("An error occoured whilst attempting to send the server declaration message!", e); + } + Logger.info(STR."Server Declaration message sent! '\{message}'."); + } + + public void shutdown() { + try { + connection.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void kickPlayer(Player player, KickReason reason, Component message) { + // FORMAT: {uuid}|:|{reason}|:|{name}|:|{message}|:|{rescuable} + String rawMessage = STR."\{player.getUuid().toString()}|:|\{reason}|:|\{player.getUsername()}|:|\{JSONComponentSerializer.json().serialize(message)}|:|\{reason.isRescuable()}"; + try { + channel.basicPublish("", PLAYER_KICK_QUEUE, null, rawMessage.getBytes()); + } catch (IOException e) { + Logger.error(STR."An error occoured whilst attempting to kick the player \{player.getName()}.", e); + } + } + + public void kickPlayer(OfflinePlayer player, KickReason reason, Component message) { + // FORMAT: {uuid}|:|{reason}|:|{name}|:|{message}|:|{rescuable} + String rawMessage = STR."\{player.uuid().toString()}|:|\{reason}|:|\{player.name()}|:|\{JSONComponentSerializer.json().serialize(message)}|:|\{reason.isRescuable()}"; + try { + channel.basicPublish("", PLAYER_KICK_QUEUE, null, rawMessage.getBytes()); + } catch (IOException e) { + Logger.error(STR."An error occoured whilst attempting to kick the player \{player.name()}.", e); + } + } +} \ No newline at end of file From b46231ba05962fbde741228c5e2123bc9ce7c883 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:51:25 -0400 Subject: [PATCH 48/55] Rename to mysql database --- src/main/java/net/cytonic/cytosis/commands/RankCommand.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/commands/RankCommand.java b/src/main/java/net/cytonic/cytosis/commands/RankCommand.java index 74c5c121..53e8e2ea 100644 --- a/src/main/java/net/cytonic/cytosis/commands/RankCommand.java +++ b/src/main/java/net/cytonic/cytosis/commands/RankCommand.java @@ -45,7 +45,6 @@ public RankCommand() { sender.sendMessage(MM."You cannot change your own rank!"); return; } - Cytosis.getDatabaseManager().getMysqlDatabase().getPlayerRank(player.getUuid()).whenComplete((rank, throwable) -> { if (throwable != null) { sender.sendMessage("An error occurred whilst fetching the old rank!"); @@ -77,4 +76,4 @@ private void setRank(Player player, PlayerRank rank, CommandSender sender) { sender.sendMessage(MM."Successfully updated \{player.getUsername()}'s rank!"); }); } -} \ No newline at end of file +} From 5dc776c0070ec93b7acf1d70b9dfc369457b8e44 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:51:39 -0400 Subject: [PATCH 49/55] Add RedisDatabase --- .../cytonic/cytosis/data/DatabaseManager.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java b/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java index 60fbfaa8..419f56d9 100644 --- a/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java +++ b/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java @@ -5,18 +5,37 @@ @Getter public class DatabaseManager { - private Database database; + private MysqlDatabase mysqlDatabase; + private RedisDatabase redisDatabase; public DatabaseManager() { } public void shutdown() { database.disconnect(); + mysqlDatabase.disconnect(); + redisDatabase.disconnect(); + Logger.info("Good night!"); } public void setupDatabase() { database = new Database(); database.connect(); database.createTables(); + } + + public void setupDatabases() { + Logger.info("Connecting to MySQL Database."); + mysqlDatabase = new MysqlDatabase(); + mysqlDatabase.connect(); + mysqlDatabase.createTables(); + + Logger.info("Connecting to the Redis Database."); + try { + redisDatabase = new RedisDatabase(); // it handles itnitialization in the constructor + } catch (Exception ex) { + Logger.error("An error occured!", ex); + } + Logger.info("All databases connected."); } } \ No newline at end of file From 0a77e8be7d450b9784052086faa90f76a541e791 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:53:21 -0400 Subject: [PATCH 50/55] Update stuff, generate server ids, reformatting --- .../java/net/cytonic/cytosis/Cytosis.java | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index e22386e9..e734372f 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -29,10 +29,11 @@ import net.minestom.server.instance.block.Block; import net.minestom.server.network.ConnectionManager; import net.minestom.server.permission.Permission; +import org.jetbrains.annotations.Nullable; @Getter public class Cytosis { - + public static final String SERVER_ID = generateID(); // manager stuff @Getter private static MinecraftServer minecraftServer; @@ -60,6 +61,9 @@ public class Cytosis { private static RankManager rankManager; @Getter private static ChatManager chatManager; + @Nullable + @Getter + private static CytonicNetwork cytonicNetwork; private static List FLAGS; @@ -129,6 +133,12 @@ public static Optional getPlayer(String username) { return Optional.ofNullable(target); } + /** + * Gets the player if they are on THIS instance, by UUID + * + * @param uuid The uuid to fetch the player by + * @return The optional holding the player if they exist + */ public static Optional getPlayer(UUID uuid) { Player target = null; for (Player onlinePlayer : getOnlinePlayers()) { @@ -182,6 +192,13 @@ public static void completeNonEssentialTasks(long start) { Logger.info("Initializing server events"); ServerEventListeners.initServerEvents(); + Logger.info("Initializing database"); + databaseManager.setupDatabases(); + + MinecraftServer.getSchedulerManager().buildShutdownTask(() -> { + databaseManager.shutdown(); + messagingManager.shutdown(); + }); MinecraftServer.getSchedulerManager().buildShutdownTask(() -> { databaseManager.shutdown(); Logger.info("Good night!"); @@ -205,6 +222,13 @@ public static void completeNonEssentialTasks(long start) { rankManager = new RankManager(); rankManager.init(); + if (CytosisSettings.SERVER_PROXY_MODE) { + Logger.info("Loading network setup!"); + cytonicNetwork = new CytonicNetwork(); + cytonicNetwork.importDataFromRedis(databaseManager.getRedisDatabase()); + } + + // Start the server Logger.info(STR."Server started on port \{CytosisSettings.SERVER_PORT}"); minecraftServer.start("0.0.0.0", CytosisSettings.SERVER_PORT); @@ -217,4 +241,16 @@ public static void completeNonEssentialTasks(long start) { MinecraftServer.stopCleanly(); } } + + private static String generateID() { + //todo: make a check for existing server ids + StringBuilder id = new StringBuilder("Cytosis-"); + Random random = new Random(); + id.append((char) (random.nextInt(26) + 'a')); + for (int i = 0; i < 4; i++) { + id.append(random.nextInt(10)); + } + id.append((char) (random.nextInt(26) + 'a')); + return id.toString(); + } } \ No newline at end of file From 874cbe46f2eda96a07b0e4c139474795e10d2eb6 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 18:53:41 -0400 Subject: [PATCH 51/55] Update settings --- .../cytosis/config/CytosisSettings.java | 107 ++++++++++++++---- 1 file changed, 84 insertions(+), 23 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java index 1ffc596e..72c75f1c 100644 --- a/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java +++ b/src/main/java/net/cytonic/cytosis/config/CytosisSettings.java @@ -1,6 +1,7 @@ package net.cytonic.cytosis.config; import net.cytonic.cytosis.logging.Logger; + import net.cytonic.cytosis.utils.PosSerializer; import net.minestom.server.coordinate.Pos; import java.util.Map; @@ -14,6 +15,7 @@ public class CytosisSettings { public static boolean LOG_PLAYER_QUITS = true; public static boolean LOG_PLAYER_COMMANDS = true; public static boolean LOG_PLAYER_CHAT = true; + // Database public static boolean DATABASE_ENABLED = true; public static String DATABASE_USER = ""; @@ -22,10 +24,12 @@ public class CytosisSettings { public static int DATABASE_PORT = 3306; public static String DATABASE_NAME = ""; public static boolean DATABASE_USE_SSL = false; + // server public static boolean SERVER_PROXY_MODE = false; public static String SERVER_SECRET = ""; public static int SERVER_PORT = 25565; + public static String SERVER_WORLD_NAME = ""; public static Pos SERVER_SPAWN_POS = new Pos(0, 1, 0); public static String SERVER_HOSTNAME = "UNKNOWN"; @@ -36,6 +40,11 @@ public class CytosisSettings { public static String RABBITMQ_USERNAME = ""; public static int RABBITMQ_PORT = 5672; + //Redis + public static int REDIS_PORT = 6379; + public static String REDIS_HOST = ""; + public static String REDIS_PASSWORD = ""; + public static void inportConfig(Map config) { Logger.info("Importing config!"); config.forEach((key, value) -> { @@ -68,6 +77,11 @@ public static void inportConfig(Map config) { case "rabbitmq.port" -> RABBITMQ_PORT = toInt(value); case "rabbitmq.enabled" -> RABBITMQ_ENABLED = (boolean) value; + // Redis + case "redis.port" -> REDIS_PORT = toInt(value); + case "redis.host" -> REDIS_HOST = (String) value; + case "redis.password" -> REDIS_PASSWORD = (String) value; + default -> { /*Do nothing*/ } } } catch (ClassCastException e) { @@ -88,14 +102,25 @@ public static void loadEnvironmentVariables() { if (!(System.getenv("LOG_PLAYER_QUITS") == null)) CytosisSettings.LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_QUITS")); if (!(System.getenv("LOG_PLAYER_COMMANDS") == null)) CytosisSettings.LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_COMMANDS")); if (!(System.getenv("LOG_PLAYER_CHAT") == null)) CytosisSettings.LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getenv("LOG_PLAYER_CHAT")); + if (!(System.getenv("LOG_PLAYER_JOINS") == null)) + LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_JOINS")); + if (!(System.getenv("LOG_PLAYER_QUITS") == null)) + LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_QUITS")); + if (!(System.getenv("LOG_PLAYER_COMMANDS") == null)) + LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getenv("LOG_PLAYER_COMMANDS")); + if (!(System.getenv("LOG_PLAYER_CHAT") == null)) + LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getenv("LOG_PLAYER_CHAT")); // database - if (!(System.getenv("DATABASE_ENABLED") == null)) CytosisSettings.DATABASE_ENABLED = Boolean.parseBoolean(System.getenv("DATABASE_ENABLED")); - if (!(System.getenv("DATABASE_USER") == null)) CytosisSettings.DATABASE_USER = System.getenv("DATABASE_USER"); - if (!(System.getenv("DATABASE_PASSWORD") == null)) CytosisSettings.DATABASE_PASSWORD = System.getenv("DATABASE_PASSWORD"); - if (!(System.getenv("DATABASE_HOST") == null)) CytosisSettings.DATABASE_HOST = System.getenv("DATABASE_HOST"); - if (!(System.getenv("DATABASE_PORT") == null)) CytosisSettings.DATABASE_PORT = Integer.parseInt((System.getenv("DATABASE_PORT"))); - if (!(System.getenv("DATABASE_NAME") == null)) CytosisSettings.DATABASE_NAME = System.getenv("DATABASE_NAME"); - if (!(System.getenv("DATABASE_USE_SSL") == null)) CytosisSettings.DATABASE_USE_SSL = Boolean.parseBoolean(System.getenv("DATABASE_USE_SSL")); + if (!(System.getenv("DATABASE_ENABLED") == null)) + DATABASE_ENABLED = Boolean.parseBoolean(System.getenv("DATABASE_ENABLED")); + if (!(System.getenv("DATABASE_USER") == null)) DATABASE_USER = System.getenv("DATABASE_USER"); + if (!(System.getenv("DATABASE_PASSWORD") == null)) DATABASE_PASSWORD = System.getenv("DATABASE_PASSWORD"); + if (!(System.getenv("DATABASE_HOST") == null)) DATABASE_HOST = System.getenv("DATABASE_HOST"); + if (!(System.getenv("DATABASE_PORT") == null)) + DATABASE_PORT = Integer.parseInt((System.getenv("DATABASE_PORT"))); + if (!(System.getenv("DATABASE_NAME") == null)) DATABASE_NAME = System.getenv("DATABASE_NAME"); + if (!(System.getenv("DATABASE_USE_SSL") == null)) + DATABASE_USE_SSL = Boolean.parseBoolean(System.getenv("DATABASE_USE_SSL")); //server if (!(System.getenv("SERVER_PROXY_MODE") == null)) CytosisSettings.SERVER_PROXY_MODE = Boolean.parseBoolean(System.getenv("SERVER_PROXY_MODE")); if (!(System.getenv("SERVER_SECRET") == null)) CytosisSettings.SERVER_SECRET = System.getenv("SERVER_SECRET"); @@ -103,12 +128,22 @@ public static void loadEnvironmentVariables() { if (!(System.getenv("SERVER_WORLD_NAME") == null)) CytosisSettings.SERVER_WORLD_NAME = System.getenv("SERVER_WORLD_NAME"); if (!(System.getenv("SERVER_SPAWN_POINT") == null)) CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(System.getenv("SERVER_SPAWN_POINT")); if (!(System.getenv("SERVER_HOSTNAME") == null)) CytosisSettings.SERVER_HOSTNAME = System.getenv("SERVER_HOSTNAME"); + if (!(System.getenv("SERVER_PROXY_MODE") == null)) + SERVER_PROXY_MODE = Boolean.parseBoolean(System.getenv("SERVER_PROXY_MODE")); + if (!(System.getenv("SERVER_SECRET") == null)) SERVER_SECRET = System.getenv("SERVER_SECRET"); + if (!(System.getenv("SERVER_PORT") == null)) SERVER_PORT = Integer.parseInt(System.getenv("SERVER_PORT")); // RabbitMQ - if (!(System.getenv("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getenv("RABBITMQ_ENABLED")); - if (!(System.getenv("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getenv("RABBITMQ_HOST"); - if (!(System.getenv("RABBITMQ_PASSWORD") == null)) CytosisSettings.RABBITMQ_PASSWORD = System.getenv("RABBITMQ_PASSWORD"); - if (!(System.getenv("RABBITMQ_USERNAME") == null)) CytosisSettings.RABBITMQ_USERNAME = System.getenv("RABBITMQ_USERNAME"); - if (!(System.getenv("RABBITMQ_PORT") == null)) CytosisSettings.RABBITMQ_PORT = Integer.parseInt(System.getenv("RABBITMQ_PORT")); + if (!(System.getenv("RABBITMQ_ENABLED") == null)) + RABBITMQ_ENABLED = Boolean.parseBoolean(System.getenv("RABBITMQ_ENABLED")); + if (!(System.getenv("RABBITMQ_HOST") == null)) RABBITMQ_HOST = System.getenv("RABBITMQ_HOST"); + if (!(System.getenv("RABBITMQ_PASSWORD") == null)) RABBITMQ_PASSWORD = System.getenv("RABBITMQ_PASSWORD"); + if (!(System.getenv("RABBITMQ_USERNAME") == null)) RABBITMQ_USERNAME = System.getenv("RABBITMQ_USERNAME"); + if (!(System.getenv("RABBITMQ_PORT") == null)) RABBITMQ_PORT = Integer.parseInt(System.getenv("RABBITMQ_PORT")); + + // redis + if (!(System.getenv("REDIS_HOST") == null)) REDIS_HOST = System.getenv("REDIS_HOST"); + if (!(System.getenv("REDIS_PORT") == null)) REDIS_PORT = Integer.parseInt(System.getenv("REDIS_PORT")); + if (!(System.getenv("REDIS_PASSWORD") == null)) REDIS_PASSWORD = System.getenv("REDIS_PASSWORD"); } public static void loadCommandArgs() { @@ -118,13 +153,24 @@ public static void loadCommandArgs() { if (!(System.getProperty("LOG_PLAYER_QUITS") == null)) CytosisSettings.LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_QUITS")); if (!(System.getProperty("LOG_PLAYER_COMMANDS") == null)) CytosisSettings.LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_COMMANDS")); if (!(System.getProperty("LOG_PLAYER_CHAT") == null)) CytosisSettings.LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_CHAT")); + if (!(System.getProperty("LOG_PLAYER_JOINS") == null)) + LOG_PLAYER_JOINS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_JOINS")); + if (!(System.getProperty("LOG_PLAYER_QUITS") == null)) + LOG_PLAYER_QUITS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_QUITS")); + if (!(System.getProperty("LOG_PLAYER_COMMANDS") == null)) + LOG_PLAYER_COMMANDS = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_COMMANDS")); + if (!(System.getProperty("LOG_PLAYER_CHAT") == null)) + LOG_PLAYER_CHAT = Boolean.parseBoolean(System.getProperty("LOG_PLAYER_CHAT")); // database - if (!(System.getProperty("DATABASE_USER") == null)) CytosisSettings.DATABASE_USER = System.getProperty("DATABASE_USER"); - if (!(System.getProperty("DATABASE_PASSWORD") == null)) CytosisSettings.DATABASE_PASSWORD = System.getProperty("DATABASE_PASSWORD"); - if (!(System.getProperty("DATABASE_HOST") == null)) CytosisSettings.DATABASE_HOST = System.getProperty("DATABASE_HOST"); - if (!(System.getProperty("DATABASE_PORT") == null)) CytosisSettings.DATABASE_PORT = Integer.parseInt((System.getProperty("DATABASE_PORT"))); - if (!(System.getProperty("DATABASE_NAME") == null)) CytosisSettings.DATABASE_NAME = System.getProperty("DATABASE_NAME"); - if (!(System.getProperty("DATABASE_USE_SSL") == null)) CytosisSettings.DATABASE_USE_SSL = Boolean.parseBoolean(System.getProperty("DATABASE_USE_SSL")); + if (!(System.getProperty("DATABASE_USER") == null)) DATABASE_USER = System.getProperty("DATABASE_USER"); + if (!(System.getProperty("DATABASE_PASSWORD") == null)) + DATABASE_PASSWORD = System.getProperty("DATABASE_PASSWORD"); + if (!(System.getProperty("DATABASE_HOST") == null)) DATABASE_HOST = System.getProperty("DATABASE_HOST"); + if (!(System.getProperty("DATABASE_PORT") == null)) + DATABASE_PORT = Integer.parseInt((System.getProperty("DATABASE_PORT"))); + if (!(System.getProperty("DATABASE_NAME") == null)) DATABASE_NAME = System.getProperty("DATABASE_NAME"); + if (!(System.getProperty("DATABASE_USE_SSL") == null)) + DATABASE_USE_SSL = Boolean.parseBoolean(System.getProperty("DATABASE_USE_SSL")); //server if (!(System.getProperty("SERVER_PROXY_MODE") == null)) CytosisSettings.SERVER_PROXY_MODE = Boolean.parseBoolean(System.getProperty("SERVER_PROXY_MODE")); if (!(System.getProperty("SERVER_SECRET") == null)) CytosisSettings.SERVER_SECRET = System.getProperty("SERVER_SECRET"); @@ -132,11 +178,26 @@ public static void loadCommandArgs() { if (!(System.getProperty("SERVER_WORLD_NAME") == null)) CytosisSettings.SERVER_WORLD_NAME = System.getProperty("SERVER_WORLD_NAME"); if (!(System.getProperty("SERVER_SPAWN_POINT") == null)) CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(System.getProperty("SERVER_SPAWN_POINT")); if (!(System.getProperty("SERVER_HOSTNAME") == null)) CytosisSettings.SERVER_HOSTNAME = System.getProperty("SERVER_HOSTNAME"); + if (!(System.getProperty("SERVER_PROXY_MODE") == null)) + SERVER_PROXY_MODE = Boolean.parseBoolean(System.getProperty("SERVER_PROXY_MODE")); + if (!(System.getProperty("SERVER_SECRET") == null)) SERVER_SECRET = System.getProperty("SERVER_SECRET"); + if (!(System.getProperty("SERVER_PORT") == null)) + SERVER_PORT = Integer.parseInt(System.getProperty("SERVER_PORT")); // RabbitMQ - if (!(System.getProperty("RABBITMQ_ENABLED") == null)) CytosisSettings.RABBITMQ_ENABLED = Boolean.parseBoolean(System.getProperty("RABBITMQ_ENABLED")); - if (!(System.getProperty("RABBITMQ_HOST") == null)) CytosisSettings.RABBITMQ_HOST = System.getProperty("RABBITMQ_HOST"); - if (!(System.getProperty("RABBITMQ_PASSWORD") == null)) CytosisSettings.RABBITMQ_PASSWORD = System.getProperty("RABBITMQ_PASSWORD"); - if (!(System.getProperty("RABBITMQ_USERNAME") == null)) CytosisSettings.RABBITMQ_USERNAME = System.getProperty("RABBITMQ_USERNAME"); - if (!(System.getProperty("RABBITMQ_PORT") == null)) CytosisSettings.RABBITMQ_PORT = Integer.parseInt(System.getProperty("RABBITMQ_PORT")); + if (!(System.getProperty("RABBITMQ_ENABLED") == null)) + RABBITMQ_ENABLED = Boolean.parseBoolean(System.getProperty("RABBITMQ_ENABLED")); + if (!(System.getProperty("RABBITMQ_HOST") == null)) RABBITMQ_HOST = System.getProperty("RABBITMQ_HOST"); + if (!(System.getProperty("RABBITMQ_PASSWORD") == null)) + RABBITMQ_PASSWORD = System.getProperty("RABBITMQ_PASSWORD"); + if (!(System.getProperty("RABBITMQ_USERNAME") == null)) + RABBITMQ_USERNAME = System.getProperty("RABBITMQ_USERNAME"); + if (!(System.getProperty("RABBITMQ_PORT") == null)) + RABBITMQ_PORT = Integer.parseInt(System.getProperty("RABBITMQ_PORT")); + + // redis + if (!(System.getProperty("REDIS_HOST") == null)) REDIS_HOST = System.getProperty("REDIS_HOST"); + if (!(System.getProperty("REDIS_PORT") == null)) + REDIS_PORT = Integer.parseInt(System.getProperty("REDIS_PORT")); + if (!(System.getProperty("REDIS_PASSWORD") == null)) REDIS_PASSWORD = System.getProperty("REDIS_PASSWORD"); } } \ No newline at end of file From 37aae8ee3b1bc6dc091ec9c4cf2a0784cb14a79a Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 19:50:37 -0400 Subject: [PATCH 52/55] Delete old database object --- .../net/cytonic/cytosis/data/Database.java | 386 ------------------ 1 file changed, 386 deletions(-) delete mode 100644 src/main/java/net/cytonic/cytosis/data/Database.java diff --git a/src/main/java/net/cytonic/cytosis/data/Database.java b/src/main/java/net/cytonic/cytosis/data/Database.java deleted file mode 100644 index 8cba8e70..00000000 --- a/src/main/java/net/cytonic/cytosis/data/Database.java +++ /dev/null @@ -1,386 +0,0 @@ - -package net.cytonic.cytosis.data; - -import java.net.SocketAddress; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import net.cytonic.cytosis.data.enums.ChatChannel; -import org.jetbrains.annotations.NotNull; -import net.cytonic.cytosis.Cytosis; -import net.cytonic.cytosis.config.CytosisSettings; -import net.cytonic.cytosis.logging.Logger; -import net.cytonic.cytosis.ranks.PlayerRank; -import net.cytonic.cytosis.utils.PosSerializer; -import net.hollowcube.polar.PolarReader; -import net.hollowcube.polar.PolarWorld; -import net.hollowcube.polar.PolarWriter; -import net.minestom.server.MinecraftServer; -import net.minestom.server.coordinate.Pos; - -public class Database { - - private final ExecutorService worker; - private final String host; - private final int port; - private final String database; - private final String username; - private final String password; - private final boolean ssl; - private Connection connection; - - public Database() { - this.worker = Executors.newSingleThreadExecutor(Thread.ofVirtual().name("CytosisDatabaseWorker").uncaughtExceptionHandler((t, e) -> Logger.error(STR."An uncaught exception occoured on the thread: \{t.getName()}", e)).factory()); - this.host = CytosisSettings.DATABASE_HOST; - this.port = CytosisSettings.DATABASE_PORT; - this.database = CytosisSettings.DATABASE_NAME; - this.username = CytosisSettings.DATABASE_USER; - this.password = CytosisSettings.DATABASE_PASSWORD; - this.ssl = CytosisSettings.DATABASE_USE_SSL; - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException e) { - Logger.error("Failed to load database driver", e); - } - } - - public boolean isConnected() { - return (connection != null); - } - - public void connect() { - worker.submit(() -> { - if (!isConnected()) { - try { - connection = DriverManager.getConnection(STR."jdbc:mysql://\{host}:\{port}/\{database}?useSSL=\{ssl}&autoReconnect=true&allowPublicKeyRetrieval=true", username, password); - Logger.info("Successfully connected to the MySQL Database!"); - Cytosis.loadWorld(); - } catch (SQLException e) { - Logger.error("Invalid Database Credentials!", e); - MinecraftServer.stopCleanly(); - } - } - }); - } - - public void disconnect() { - worker.submit(() -> { - if (isConnected()) { - try { - connection.close(); - Logger.info("Database connection closed!"); - } catch (SQLException e) { - Logger.error("An error occurred whilst disconnecting from the database.", e); - } - } - }); - } - - public void createTables() { - createRanksTable(); - createChatTable(); - createWorldTable(); - createPlayerJoinsTable(); - createChatChannelsTable(); - } - - private Connection getConnection() { - return connection; - } - - /** - * Creates the 'cytonic_chat' table in the database if it doesn't exist. - * The table contains information about player chat messages. - * - * @throws IllegalStateException if the database connection is not open. - */ - private void createChatTable() { - worker.submit(() -> { - if (isConnected()) { - PreparedStatement ps; - try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat (id INT NOT NULL AUTO_INCREMENT, timestamp TIMESTAMP, uuid VARCHAR(36), message TEXT, PRIMARY KEY(id))"); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_chat` table.", e); - } - } - }); - } - - /** - * Creates the 'cytonic_ranks' table in the database if it doesn't exist. - * The table contains information about player ranks. - * - * @throws IllegalStateException if the database connection is not open. - */ - private void createRanksTable() { - worker.submit(() -> { - if (isConnected()) { - PreparedStatement ps; - try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_ranks (uuid VARCHAR(36), rank_id VARCHAR(16), PRIMARY KEY(uuid))"); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_ranks` table.", e); - } - } - }); - } - - /** - * Creates the 'cytonic_worlds' table in the database if it doesn't exist. - * The table contains information about the worlds stored in the database. - * - * @throws IllegalStateException if the database connection is not open. - */ - public void createWorldTable() { - worker.submit(() -> { - if (isConnected()) { - PreparedStatement ps; - try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_worlds (world_name TEXT, world_type TEXT, last_modified TIMESTAMP, world_data MEDIUMBLOB, spawn_point TEXT, extra_data varchar(100))"); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_worlds` table.", e); - } - } - }); - } - - /** - * Creates the 'cytonic_chat_channels' table in the database if it doesn't exist. - * The table contains information about player's chat channels. - * - * @throws IllegalStateException if the database connection is not open. - */ -private void createChatChannelsTable() { - worker.submit(() -> { - if (isConnected()) { - PreparedStatement ps; - try { - ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat_channels (uuid VARCHAR(36), chat_channel VARCHAR(16), PRIMARY KEY(uuid))"); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_chat_channels` table.", e); - } - } - }); -} - - private void createPlayerJoinsTable() { - worker.submit(() -> { - if (isConnected()) { - try (PreparedStatement ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_player_joins (joined TIMESTAMP, uuid VARCHAR(36), ip TEXT)")) { - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst creating the `cytonic_player_joins` table.", e); - } - } - }); - } - - /** - * Gets the player's rank. This returns {@link PlayerRank#DEFAULT} even if the player doesn't exist. - * - * @param uuid the player to fetch the id from - * @return The player's {@link PlayerRank} - * @throws IllegalStateException if the database isn't connected - */ - @NotNull - public CompletableFuture getPlayerRank(@NotNull final UUID uuid) { - CompletableFuture future = new CompletableFuture<>(); - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to fetch a player's rank!"); - worker.submit(() -> { - String id = "DEFAULT"; - try { - PreparedStatement ps = connection.prepareStatement("SELECT rank_id FROM cytonic_ranks WHERE uuid = ?"); - ps.setString(1, uuid.toString()); - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - id = rs.getString("rank_id"); - } - future.complete(PlayerRank.valueOf(id)); - } catch (SQLException e) { - Logger.error(STR."An error occurred whilst fetching the rank of '\{uuid}'"); - } - }); - return future; - } - - /** - * Sets the given player's rank to the specified rank. - * - * @param uuid The player's UUID - * @param rank The player's rank constant - * @throws IllegalStateException if the database isn't connected - */ - public CompletableFuture setPlayerRank(UUID uuid, PlayerRank rank) { - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to set a player's rank!"); - CompletableFuture future = new CompletableFuture<>(); - worker.submit(() -> { - try { - PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_ranks (uuid, rank_id) VALUES (?, ?) ON DUPLICATE KEY UPDATE rank_id = VALUES(rank_id)"); - ps.setString(1, uuid.toString()); - ps.setString(2, rank.name()); - ps.executeUpdate(); - future.complete(null); - } catch (SQLException e) { - Logger.error(STR."An error occurred whilst setting the rank of '\{uuid}'"); - future.completeExceptionally(e); - } - }); - return future; - } - - /** - * Adds a players chat message to the database. - * - * @param uuid The player's UUID. - * @param message The player's message. - * @throws IllegalStateException if the database isn't connected. - */ - public void addChat(UUID uuid, String message) { - worker.submit(() -> { - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to add a player's chat!"); - PreparedStatement ps; - try { - ps = connection.prepareStatement("INSERT INTO cytonic_chat (timestamp, uuid, message) VALUES (CURRENT_TIMESTAMP,?,?)"); - ps.setString(1, uuid.toString()); - ps.setString(2, message); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst adding a chat message.", e); - } - }); - } - - public void setChatChannel(UUID uuid, ChatChannel chatChannel) { - worker.submit(() -> { - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to add a player's chat!"); - PreparedStatement ps; - try { - ps = connection.prepareStatement("INSERT INTO cytonic_chat_channels (uuid, chat_channel) VALUES (?, ?) ON DUPLICATE KEY UPDATE chat_channel = VALUES(chat_channel)"); - ps.setString(1, uuid.toString()); - ps.setString(2, chatChannel.name()); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst setting a players chat channel.", e); - } - }); - } - - public CompletableFuture getChatChannel(@NotNull final UUID uuid) { - CompletableFuture future = new CompletableFuture<>(); - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to fetch a player's chat channel!"); - worker.submit(() -> { - String channel = "ALL"; - try { - PreparedStatement ps = connection.prepareStatement("SELECT chat_channel FROM cytonic_chat_channels WHERE uuid = ?"); - ps.setString(1, uuid.toString()); - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - channel = rs.getString("chat_channel"); - } - future.complete(ChatChannel.valueOf(channel)); - } catch (SQLException e) { - Logger.error(STR."An error occurred whilst fetching the chat channel of '\{uuid}'", e); - } - }); - return future; - } - - /** - * Adds a new world to the database. - * - * @param worldName The name of the world to be added. - * @param worldType The type of the world. - * @param world The PolarWorld object representing the world. - * @param spawnPoint The spawn point of the world. - * @throws IllegalStateException If the database connection is not open. - */ - public void addWorld(String worldName, String worldType, PolarWorld world, Pos spawnPoint) { - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to add a world!"); - worker.submit(() -> { - try { - PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_worlds (world_name, world_type, last_modified, world_data, spawn_point) VALUES (?,?, CURRENT_TIMESTAMP,?,?)"); - ps.setString(1, worldName); - ps.setString(2, worldType); - ps.setBytes(3, PolarWriter.write(world)); - ps.setString(4, PosSerializer.serialize(spawnPoint)); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("An error occurred whilst adding a world!", e); - } - }); - } - - /** - * Retrieves a world from the database. - * - * @param worldName The name of the world to fetch. - * @return A {@link CompletableFuture} that completes with the fetched {@link PolarWorld}. - * If the world does not exist in the database, the future will complete exceptionally with a {@link RuntimeException}. - * @throws IllegalStateException If the database connection is not open. - */ - public CompletableFuture getWorld(String worldName) { - CompletableFuture future = new CompletableFuture<>(); - if (!isConnected()) - throw new IllegalStateException("The database must have an open connection to fetch a world!"); - worker.submit(() -> { - try (PreparedStatement ps = connection.prepareStatement("SELECT * FROM cytonic_worlds WHERE world_name = ?")) { - ps.setString(1, worldName); - ResultSet rs = ps.executeQuery(); - if (rs.next()) { - PolarWorld world = PolarReader.read(rs.getBytes("world_data")); - CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(rs.getString("spawn_point")); - future.complete(world); - } else { - Logger.error("The result set is empty!"); - throw new RuntimeException(STR."World not found: \{worldName}"); - } - } catch (Exception e) { - Logger.error("An error occurred whilst fetching a world!", e); - future.completeExceptionally(e); - throw new RuntimeException(e); - } - }); - return future; - } - - /** - * Logs a player's join event to the database. - * - * @param uuid The unique identifier of the player. - * @param ip The IP address of the player. - *

- * This method uses a worker thread to execute the database operation. - * It prepares a SQL statement to insert a new record into the 'cytonic_player_joins' table. - * The 'joined' column is set to the current timestamp, the 'uuid' column is set to the provided UUID, - * and the 'ip' column is set to the provided IP address. - * If an error occurs during the database operation, it is logged using the Logger. - */ - public void logPlayerJoin(UUID uuid, SocketAddress ip) { - worker.submit(() -> { - try (PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_player_joins (joined, uuid, ip) VALUES (CURRENT_TIMESTAMP,?,?)")) { - ps.setString(1, uuid.toString()); - ps.setString(2, ip.toString()); - ps.executeUpdate(); - } catch (SQLException e) { - Logger.error("Failed to add a player to the database!", e); - } - }); - } -} \ No newline at end of file From 37b0085b3f4c4eade23a79f33d21936911d8daa4 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 19:50:56 -0400 Subject: [PATCH 53/55] Merging --- build.gradle.kts | 2 + .../java/net/cytonic/cytosis/Cytosis.java | 14 +- .../cytonic/cytosis/data/DatabaseManager.java | 11 +- .../cytonic/cytosis/data/MysqlDatabase.java | 176 ++++++++++++++++++ .../cytosis/events/ServerEventListeners.java | 15 +- .../cytonic/cytosis/managers/ChatManager.java | 9 +- .../cytonic/cytosis/messaging/RabbitMQ.java | 8 +- 7 files changed, 198 insertions(+), 37 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 5ab14fcf..b8ee7ac4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,6 +28,8 @@ dependencies { implementation("org.tomlj:tomlj:1.1.1") // Config lang implementation("com.rabbitmq:amqp-client:5.21.0") // Message broker implementation("dev.hollowcube:polar:1.9.4") // Polar + implementation("com.google.guava:guava:33.2.0-jre") // a lot of things, but mostly caching + implementation("redis.clients:jedis:3.7.0") // redis client } tasks.withType { diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index e734372f..f866145e 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -1,10 +1,5 @@ package net.cytonic.cytosis; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; import lombok.Getter; import net.cytonic.cytosis.commands.CommandHandler; import net.cytonic.cytosis.config.CytosisSettings; @@ -31,6 +26,8 @@ import net.minestom.server.permission.Permission; import org.jetbrains.annotations.Nullable; +import java.util.*; + @Getter public class Cytosis { public static final String SERVER_ID = generateID(); @@ -169,7 +166,7 @@ public static void loadWorld() { return; } Logger.info(STR."Loading world '\{CytosisSettings.SERVER_WORLD_NAME}'"); - databaseManager.getDatabase().getWorld(CytosisSettings.SERVER_WORLD_NAME).whenComplete((polarWorld, throwable) -> { + databaseManager.getMysqlDatabase().getWorld(CytosisSettings.SERVER_WORLD_NAME).whenComplete((polarWorld, throwable) -> { if (throwable != null) { Logger.error("An error occurred whilst initializing the world!", throwable); } else { @@ -183,7 +180,7 @@ public static void loadWorld() { public static void completeNonEssentialTasks(long start) { Logger.info("Initializing database"); databaseManager = new DatabaseManager(); - databaseManager.setupDatabase(); + databaseManager.setupDatabases(); Logger.info("Database initialized!"); Logger.info("Setting up event handlers"); eventHandler = new EventHandler(MinecraftServer.getGlobalEventHandler()); @@ -192,9 +189,6 @@ public static void completeNonEssentialTasks(long start) { Logger.info("Initializing server events"); ServerEventListeners.initServerEvents(); - Logger.info("Initializing database"); - databaseManager.setupDatabases(); - MinecraftServer.getSchedulerManager().buildShutdownTask(() -> { databaseManager.shutdown(); messagingManager.shutdown(); diff --git a/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java b/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java index 419f56d9..132da655 100644 --- a/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java +++ b/src/main/java/net/cytonic/cytosis/data/DatabaseManager.java @@ -1,6 +1,7 @@ package net.cytonic.cytosis.data; import lombok.Getter; +import net.cytonic.cytosis.logging.Logger; @Getter public class DatabaseManager { @@ -12,18 +13,10 @@ public DatabaseManager() { } public void shutdown() { - database.disconnect(); mysqlDatabase.disconnect(); - redisDatabase.disconnect(); Logger.info("Good night!"); } - public void setupDatabase() { - database = new Database(); - database.connect(); - database.createTables(); - } - public void setupDatabases() { Logger.info("Connecting to MySQL Database."); mysqlDatabase = new MysqlDatabase(); @@ -36,6 +29,6 @@ public void setupDatabases() { } catch (Exception ex) { Logger.error("An error occured!", ex); } - Logger.info("All databases connected."); + Logger.info("All mysqlDatabases connected."); } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/data/MysqlDatabase.java b/src/main/java/net/cytonic/cytosis/data/MysqlDatabase.java index 28aaac98..8fbe5533 100644 --- a/src/main/java/net/cytonic/cytosis/data/MysqlDatabase.java +++ b/src/main/java/net/cytonic/cytosis/data/MysqlDatabase.java @@ -3,13 +3,20 @@ import net.cytonic.cytosis.auditlog.Category; import net.cytonic.cytosis.auditlog.Entry; import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.data.enums.ChatChannel; import net.cytonic.cytosis.logging.Logger; import net.cytonic.cytosis.ranks.PlayerRank; import net.cytonic.cytosis.utils.BanData; +import net.cytonic.cytosis.utils.PosSerializer; +import net.hollowcube.polar.PolarReader; +import net.hollowcube.polar.PolarWorld; +import net.hollowcube.polar.PolarWriter; import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; import org.jetbrains.annotations.NotNull; +import java.net.SocketAddress; import java.sql.*; import java.time.Instant; import java.util.UUID; @@ -81,6 +88,9 @@ public void createTables() { createBansTable(); createAuditLogTable(); createPlayersTable(); + createWorldTable(); + createPlayerJoinsTable(); + createChatChannelsTable(); } private Connection getConnection() { @@ -369,4 +379,170 @@ public CompletableFuture unbanPlayer(UUID uuid) { }); return future; } + + public void createWorldTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_worlds (world_name TEXT, world_type TEXT, last_modified TIMESTAMP, world_data MEDIUMBLOB, spawn_point TEXT, extra_data varchar(100))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_worlds` table.", e); + } + } + }); + } + + /** + * Creates the 'cytonic_chat_channels' table in the database if it doesn't exist. + * The table contains information about player's chat channels. + * + * @throws IllegalStateException if the database connection is not open. + */ + private void createChatChannelsTable() { + worker.submit(() -> { + if (isConnected()) { + PreparedStatement ps; + try { + ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_chat_channels (uuid VARCHAR(36), chat_channel VARCHAR(16), PRIMARY KEY(uuid))"); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_chat_channels` table.", e); + } + } + }); + } + + private void createPlayerJoinsTable() { + worker.submit(() -> { + if (isConnected()) { + try (PreparedStatement ps = getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS cytonic_player_joins (joined TIMESTAMP, uuid VARCHAR(36), ip TEXT)")) { + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst creating the `cytonic_player_joins` table.", e); + } + } + }); + } + + public void setChatChannel(UUID uuid, ChatChannel chatChannel) { + worker.submit(() -> { + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to add a player's chat!"); + PreparedStatement ps; + try { + ps = connection.prepareStatement("INSERT INTO cytonic_chat_channels (uuid, chat_channel) VALUES (?, ?) ON DUPLICATE KEY UPDATE chat_channel = VALUES(chat_channel)"); + ps.setString(1, uuid.toString()); + ps.setString(2, chatChannel.name()); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst setting a players chat channel.", e); + } + }); + } + + public CompletableFuture getChatChannel(@NotNull final UUID uuid) { + CompletableFuture future = new CompletableFuture<>(); + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to fetch a player's chat channel!"); + worker.submit(() -> { + String channel = "ALL"; + try { + PreparedStatement ps = connection.prepareStatement("SELECT chat_channel FROM cytonic_chat_channels WHERE uuid = ?"); + ps.setString(1, uuid.toString()); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + channel = rs.getString("chat_channel"); + } + future.complete(ChatChannel.valueOf(channel)); + } catch (SQLException e) { + Logger.error(STR."An error occurred whilst fetching the chat channel of '\{uuid}'", e); + } + }); + return future; + } + + /** + * Adds a new world to the database. + * + * @param worldName The name of the world to be added. + * @param worldType The type of the world. + * @param world The PolarWorld object representing the world. + * @param spawnPoint The spawn point of the world. + * @throws IllegalStateException If the database connection is not open. + */ + public void addWorld(String worldName, String worldType, PolarWorld world, Pos spawnPoint) { + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to add a world!"); + worker.submit(() -> { + try { + PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_worlds (world_name, world_type, last_modified, world_data, spawn_point) VALUES (?,?, CURRENT_TIMESTAMP,?,?)"); + ps.setString(1, worldName); + ps.setString(2, worldType); + ps.setBytes(3, PolarWriter.write(world)); + ps.setString(4, PosSerializer.serialize(spawnPoint)); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("An error occurred whilst adding a world!", e); + } + }); + } + + /** + * Retrieves a world from the database. + * + * @param worldName The name of the world to fetch. + * @return A {@link CompletableFuture} that completes with the fetched {@link PolarWorld}. + * If the world does not exist in the database, the future will complete exceptionally with a {@link RuntimeException}. + * @throws IllegalStateException If the database connection is not open. + */ + public CompletableFuture getWorld(String worldName) { + CompletableFuture future = new CompletableFuture<>(); + if (!isConnected()) + throw new IllegalStateException("The database must have an open connection to fetch a world!"); + worker.submit(() -> { + try (PreparedStatement ps = connection.prepareStatement("SELECT * FROM cytonic_worlds WHERE world_name = ?")) { + ps.setString(1, worldName); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + PolarWorld world = PolarReader.read(rs.getBytes("world_data")); + CytosisSettings.SERVER_SPAWN_POS = PosSerializer.deserialize(rs.getString("spawn_point")); + future.complete(world); + } else { + Logger.error("The result set is empty!"); + throw new RuntimeException(STR."World not found: \{worldName}"); + } + } catch (Exception e) { + Logger.error("An error occurred whilst fetching a world!", e); + future.completeExceptionally(e); + throw new RuntimeException(e); + } + }); + return future; + } + + /** + * Logs a player's join event to the database. + * + * @param uuid The unique identifier of the player. + * @param ip The IP address of the player. + *

+ * This method uses a worker thread to execute the database operation. + * It prepares a SQL statement to insert a new record into the 'cytonic_player_joins' table. + * The 'joined' column is set to the current timestamp, the 'uuid' column is set to the provided UUID, + * and the 'ip' column is set to the provided IP address. + * If an error occurs during the database operation, it is logged using the Logger. + */ + public void logPlayerJoin(UUID uuid, SocketAddress ip) { + worker.submit(() -> { + try (PreparedStatement ps = connection.prepareStatement("INSERT INTO cytonic_player_joins (joined, uuid, ip) VALUES (CURRENT_TIMESTAMP,?,?)")) { + ps.setString(1, uuid.toString()); + ps.setString(2, ip.toString()); + ps.executeUpdate(); + } catch (SQLException e) { + Logger.error("Failed to add a player to the database!", e); + } + }); + } } \ No newline at end of file diff --git a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java index 00116ee1..c48bdd5e 100644 --- a/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java +++ b/src/main/java/net/cytonic/cytosis/events/ServerEventListeners.java @@ -6,14 +6,12 @@ import net.cytonic.cytosis.logging.Logger; import net.cytonic.cytosis.messaging.KickReason; import net.cytonic.cytosis.utils.MessageUtils; -import net.minestom.server.coordinate.Pos; import net.kyori.adventure.text.Component; import net.minestom.server.entity.Player; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.PlayerChatEvent; import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.event.player.PlayerSpawnEvent; -import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; import static net.cytonic.cytosis.utils.MiniMessageTemplate.MM; @@ -42,18 +40,15 @@ public static void initServerEvents() { return; } - if (CytosisSettings.LOG_PLAYER_IPS) - Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); - else Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined."); + Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); Cytosis.getDatabaseManager().getMysqlDatabase().addPlayer(player); - Cytosis.getRankManager().addPlayer(player); }); final Player player = event.getPlayer(); Logger.info(STR."\{player.getUsername()} (\{player.getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}"); - Cytosis.getDatabaseManager().getDatabase().logPlayerJoin(player.getUuid(), player.getPlayerConnection().getRemoteAddress()); + Cytosis.getDatabaseManager().getMysqlDatabase().logPlayerJoin(player.getUuid(), player.getPlayerConnection().getRemoteAddress()); Cytosis.getRankManager().addPlayer(player); - Cytosis.getDatabaseManager().getDatabase().getChatChannel(player.getUuid()).whenComplete(((chatChannel, throwable) -> { + Cytosis.getDatabaseManager().getMysqlDatabase().getChatChannel(player.getUuid()).whenComplete(((chatChannel, throwable) -> { if (throwable != null) { Logger.error("An error occurred whilst getting a player's chat channel!", throwable); } else Cytosis.getChatManager().setChannel(player.getUuid(), chatChannel); @@ -64,7 +59,7 @@ public static void initServerEvents() { Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-chat", false, 1, PlayerChatEvent.class, event -> { final Player player = event.getPlayer(); if (CytosisSettings.LOG_PLAYER_CHAT) - Cytosis.getDatabaseManager().getDatabase().addChat(player.getUuid(), event.getMessage()); + Cytosis.getDatabaseManager().getMysqlDatabase().addChat(player.getUuid(), event.getMessage()); event.setCancelled(true); String originalMessage = event.getMessage(); if (!originalMessage.contains("|")) { @@ -90,7 +85,7 @@ public static void initServerEvents() { Cytosis.getOnlinePlayers().forEach((p) -> p.sendMessage(message)); } } else player.sendMessage(MM."Hey you cannot do that!"); - Cytosis.getDatabaseManager().getMysqlDatabase().addChat(player.getUuid(), event.getMessage()); + Cytosis.getDatabaseManager().getMysqlDatabase().addChat(player.getUuid(), event.getMessage()); })); Logger.info("Registering player disconnect event."); diff --git a/src/main/java/net/cytonic/cytosis/managers/ChatManager.java b/src/main/java/net/cytonic/cytosis/managers/ChatManager.java index efa707e5..257b7f43 100644 --- a/src/main/java/net/cytonic/cytosis/managers/ChatManager.java +++ b/src/main/java/net/cytonic/cytosis/managers/ChatManager.java @@ -1,12 +1,13 @@ package net.cytonic.cytosis.managers; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.data.enums.ChatChannel; import net.kyori.adventure.text.Component; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + public class ChatManager { private final Map channels = new HashMap<>(); @@ -17,7 +18,7 @@ public void removeChannel(UUID uuid) { public void setChannel(UUID uuid, ChatChannel channel) { channels.put(uuid, channel); - Cytosis.getDatabaseManager().getDatabase().setChatChannel(uuid,channel); + Cytosis.getDatabaseManager().getMysqlDatabase().setChatChannel(uuid, channel); } public ChatChannel getChannel(UUID uuid) { diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index d9902aaa..e9d98c96 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -1,10 +1,9 @@ package net.cytonic.cytosis.messaging; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.*; import net.cytonic.cytosis.Cytosis; import net.cytonic.cytosis.config.CytosisSettings; +import net.cytonic.cytosis.data.enums.ChatChannel; import net.cytonic.cytosis.logging.Logger; import net.cytonic.cytosis.utils.OfflinePlayer; import net.kyori.adventure.text.Component; @@ -12,7 +11,8 @@ import net.minestom.server.entity.Player; import java.io.IOException; -import java.net.*; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeoutException; import com.rabbitmq.client.*; From 93f817a9d5628136375acbd026abae897fa1bfa8 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 20:00:41 -0400 Subject: [PATCH 54/55] Fix merging shenanigans --- .../cytonic/cytosis/messaging/RabbitMQ.java | 107 +----------------- 1 file changed, 2 insertions(+), 105 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java index e9d98c96..0781580b 100644 --- a/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java +++ b/src/main/java/net/cytonic/cytosis/messaging/RabbitMQ.java @@ -15,39 +15,14 @@ import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.*; - -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DeliverCallback; - -import net.cytonic.cytosis.Cytosis; -import net.cytonic.cytosis.Cytosis; -import net.cytonic.cytosis.config.CytosisSettings; -import net.cytonic.cytosis.data.enums.ChatChannel; -import net.cytonic.cytosis.logging.Logger; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; -import net.cytonic.cytosis.utils.OfflinePlayer; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; -import net.minestom.server.entity.Player; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.concurrent.TimeoutException; public class RabbitMQ { public static final String SERVER_DECLARE_QUEUE = "server-declaration"; public static final String SHUTDOWN_QUEUE = "server-shutdown"; public static final String CHAT_CHANNEL_QUEUE = STR."chat-channel-\{Cytosis.SERVER_ID}"; - public static final String CHAT_CHANNEL_QUEUE = "chat-channel"; public static final String PLAYER_KICK_QUEUE = "player-kick"; public static final String CHAT_CHANNEL_EXCHANGE = "chat-exchange"; - public static final String PLAYER_KICK_QUEUE = "player-kick"; private Connection connection; private Channel channel; @@ -169,21 +144,6 @@ public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { Logger.error("An error occurred whilst attempting to send a chat message!", e); } } - /** - * Sends a chat message to all the servers. - * - * @param chatMessage The chat message to be sent. This should be a {@link Component}. - * @param chatChannel The channel to which the chat message should be sent. - */ - public void sendChatMessage(Component chatMessage, ChatChannel chatChannel) { - // Formatting: {chat-message}|:|{chat-channel} - String message = STR."\{JSONComponentSerializer.json().serialize(chatMessage)}|\{chatChannel.name()}"; - try { - channel.basicPublish(CHAT_CHANNEL_EXCHANGE, "", null, message.getBytes()); - } catch (IOException e) { - Logger.error("An error occurred whilst attempting to send a chat message!", e); - } - } public void receiveChatMessages() { try { @@ -213,77 +173,14 @@ public void receiveChatMessages() { }); case LEAGUE -> {// leagues.. } - case STAFF -> // send a message to all players with cytonic.chat.staff permission - Cytosis.getOnlinePlayers().forEach(player -> { - if (player.hasPermission("cytonic.chat.staff")) { - player.sendMessage(chatMessage); - } - }); - case ADMIN -> // send a message to all players with cytonic.chat.admin permission - Cytosis.getOnlinePlayers().forEach(player -> { - if (player.hasPermission("cytonic.chat.admin")) { - player.sendMessage(chatMessage); - } - }); - case LEAGUE -> { - // leagues.. - } - case PARTY -> {// parties.. } } }; - channel.basicConsume(CHAT_CHANNEL_QUEUE, true, deliverCallback, _ -> {}); + channel.basicConsume(CHAT_CHANNEL_QUEUE, true, deliverCallback, _ -> { + }); } catch (IOException e) { Logger.error("error", e); } } } - - - public void sendServerShutdownMessage() { - //formatting: {server-name}|:|{server-ip}|:|{server-port} - String serverIP; - try { - serverIP = InetAddress.getLocalHost().getHostAddress(); - } catch (UnknownHostException e) { - Logger.error("An error occoured whilst fetching this server's IP address! Bailing out!", e); - return; - } - String message = STR."\{Cytosis.SERVER_ID}|:|\{serverIP}|:|\{CytosisSettings.SERVER_PORT}"; - try { - channel.basicPublish("", SHUTDOWN_QUEUE, null, message.getBytes()); - } catch (IOException e) { - Logger.error("An error occoured whilst attempting to send the server declaration message!", e); - } - Logger.info(STR."Server Declaration message sent! '\{message}'."); - } - - public void shutdown() { - try { - connection.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public void kickPlayer(Player player, KickReason reason, Component message) { - // FORMAT: {uuid}|:|{reason}|:|{name}|:|{message}|:|{rescuable} - String rawMessage = STR."\{player.getUuid().toString()}|:|\{reason}|:|\{player.getUsername()}|:|\{JSONComponentSerializer.json().serialize(message)}|:|\{reason.isRescuable()}"; - try { - channel.basicPublish("", PLAYER_KICK_QUEUE, null, rawMessage.getBytes()); - } catch (IOException e) { - Logger.error(STR."An error occoured whilst attempting to kick the player \{player.getName()}.", e); - } - } - - public void kickPlayer(OfflinePlayer player, KickReason reason, Component message) { - // FORMAT: {uuid}|:|{reason}|:|{name}|:|{message}|:|{rescuable} - String rawMessage = STR."\{player.uuid().toString()}|:|\{reason}|:|\{player.name()}|:|\{JSONComponentSerializer.json().serialize(message)}|:|\{reason.isRescuable()}"; - try { - channel.basicPublish("", PLAYER_KICK_QUEUE, null, rawMessage.getBytes()); - } catch (IOException e) { - Logger.error(STR."An error occoured whilst attempting to kick the player \{player.name()}.", e); - } - } -} \ No newline at end of file From df5d3142f74c8d516b5c5411978c6f1980d35712 Mon Sep 17 00:00:00 2001 From: foxikle Date: Tue, 4 Jun 2024 20:14:23 -0400 Subject: [PATCH 55/55] Fix merging shenanigans --- src/main/java/net/cytonic/cytosis/Cytosis.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/cytonic/cytosis/Cytosis.java b/src/main/java/net/cytonic/cytosis/Cytosis.java index 313dc2b5..1823828d 100644 --- a/src/main/java/net/cytonic/cytosis/Cytosis.java +++ b/src/main/java/net/cytonic/cytosis/Cytosis.java @@ -1,7 +1,5 @@ package net.cytonic.cytosis; -import java.util.*; - import lombok.Getter; import net.cytonic.cytosis.commands.CommandHandler; import net.cytonic.cytosis.config.CytosisSettings; @@ -13,6 +11,7 @@ import net.cytonic.cytosis.managers.ChatManager; import net.cytonic.cytosis.messaging.MessagingManager; import net.cytonic.cytosis.ranks.RankManager; +import net.hollowcube.polar.PolarLoader; import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandManager; import net.minestom.server.command.ConsoleSender; @@ -27,6 +26,8 @@ import net.minestom.server.permission.Permission; import org.jetbrains.annotations.Nullable; +import java.util.*; + @Getter public class Cytosis { public static final String SERVER_ID = generateID();