From 4bd86434f58c08b5420bce29049f1fd89d05999a Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:57:21 -0500 Subject: [PATCH 01/16] Remove "DEU" from release titles --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 162fbbbc..c5623203 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,7 +41,7 @@ jobs: gh release create "$TAG" \ "plugin/target/displayentityutils-$TAG.jar" \ --verify-tag \ - --title "DEU $TAG" \ + --title "$TAG" \ --notes-file "docs/release-notes/$TAG.md" \ --generate-notes @@ -61,7 +61,7 @@ jobs: with: token: ${{ secrets.MODRINTH_TOKEN }} project: ${{ vars.MODRINTH_ID }} - name: DEU ${{ env.TAG }} + name: ${{ env.TAG }} version: ${{ env.TAG }} changelog: ${{ steps.release_notes.outputs.body }} loaders: |- From 5f23e7503481a3f434e57559dc09ecd407bdd168 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 2 Aug 2026 22:03:48 -0500 Subject: [PATCH 02/16] Update documentation --- .../events/AnimationCameraPlayerRemovedEvent.java | 4 +--- .../events/AnimationCameraStartEvent.java | 10 +++++++--- .../events/AnimationCameraStopEvent.java | 3 +-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraPlayerRemovedEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraPlayerRemovedEvent.java index 81486fff..10ae9f5c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraPlayerRemovedEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraPlayerRemovedEvent.java @@ -1,7 +1,6 @@ package net.donnypz.displayentityutils.events; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimator; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimation; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -12,8 +11,7 @@ import java.util.UUID; /** - * Called when a {@link DisplayAnimator} starts playing a {@link SpawnedDisplayAnimation}. - * This is called once on an animator of the type {@link DisplayAnimator.AnimationType#LOOP}. + * Called when a player is removed from their animation camera view. */ public class AnimationCameraPlayerRemovedEvent extends Event{ private static final HandlerList handlers = new HandlerList(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraStartEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraStartEvent.java index bc815463..37ca5fa7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraStartEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraStartEvent.java @@ -16,8 +16,7 @@ import java.util.UUID; /** - * Called when a {@link DisplayAnimator} starts playing a {@link SpawnedDisplayAnimation}. - * This is called once on an animator of the type {@link DisplayAnimator.AnimationType#LOOP}. + * Called when an animation camera begins its camera path */ public class AnimationCameraStartEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); @@ -29,7 +28,12 @@ public class AnimationCameraStartEvent extends Event implements Cancellable { int startFrameId; private boolean isCancelled = false; - public AnimationCameraStartEvent(ActiveGroup group, DisplayAnimator animator, SpawnedDisplayAnimation animation, Collection players, int startFrameId, UUID cameraUUID){ + public AnimationCameraStartEvent(ActiveGroup group, + DisplayAnimator animator, + SpawnedDisplayAnimation animation, + Collection players, + int startFrameId, + UUID cameraUUID){ super(!Bukkit.isPrimaryThread()); this.group = group; this.animation = animation; diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraStopEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraStopEvent.java index 8d1428df..4fdd6a27 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraStopEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/AnimationCameraStopEvent.java @@ -14,8 +14,7 @@ import java.util.UUID; /** - * Called when a {@link DisplayAnimator} starts playing a {@link SpawnedDisplayAnimation}. - * This is called once on an animator of the type {@link DisplayAnimator.AnimationType#LOOP}. + * Called when an animation camera completes its path */ public class AnimationCameraStopEvent extends Event{ private static final HandlerList handlers = new HandlerList(); From 9a89974bcbeb93f588bd928e6b7459a3cdb31425 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 2 Aug 2026 23:56:17 -0500 Subject: [PATCH 03/16] Trigger jitpack build after creating release --- .github/workflows/publish.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c5623203..c3c27b2e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -45,6 +45,13 @@ jobs: --notes-file "docs/release-notes/$TAG.md" \ --generate-notes + - name: Trigger Build on Jitpack + background: true + continue-on-error: true + run: | + curl -L --fail --retry 3 --retry-delay 7 \ + "https://jitpack.io/com/github/PZDonny/DisplayEntityUtils/${TAG}/build.log" + - name: Get Release body id: release_notes env: From 53a2b3840b24fa0ceae6d8866548578914d42b68 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Mon, 14 Sep 2026 00:56:53 -0500 Subject: [PATCH 04/16] move storage/db related classes to `database` package --- .../displayentityutils/DisplayAPI.java | 2 +- .../DisplayStorage.java | 2 +- .../displayentityutils/ConfigUtils.java | 10 +++++----- .../DisplayEntityPlugin.java | 20 +++++++++---------- .../LocalDisplayStorage.java} | 7 +++++-- .../MYSQLDisplayStorage.java} | 6 ++++-- .../MongoDisplayStorage.java} | 6 ++++-- 7 files changed, 30 insertions(+), 23 deletions(-) rename api/src/main/java/net/donnypz/displayentityutils/{managers => database}/DisplayStorage.java (95%) rename plugin/src/main/java/net/donnypz/displayentityutils/{managers/LocalManager.java => database/LocalDisplayStorage.java} (95%) rename plugin/src/main/java/net/donnypz/displayentityutils/{managers/MYSQLManager.java => database/MYSQLDisplayStorage.java} (98%) rename plugin/src/main/java/net/donnypz/displayentityutils/{managers/MongoManager.java => database/MongoDisplayStorage.java} (97%) diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index bfd95dd3..26ab3022 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -1,6 +1,6 @@ package net.donnypz.displayentityutils; -import net.donnypz.displayentityutils.managers.DisplayStorage; +import net.donnypz.displayentityutils.database.DisplayStorage; import net.donnypz.displayentityutils.managers.LoadMethod; import net.donnypz.displayentityutils.utils.DisplayEntities.AnimationPlayer; import net.donnypz.displayentityutils.utils.bdengine.convert.common.BDEConversionHandler; diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayStorage.java b/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java similarity index 95% rename from api/src/main/java/net/donnypz/displayentityutils/managers/DisplayStorage.java rename to api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java index 14c1895d..8b9a705e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayStorage.java +++ b/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.managers; +package net.donnypz.displayentityutils.database; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java index 6e524e62..bf2e89b0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java @@ -1,8 +1,8 @@ package net.donnypz.displayentityutils; import net.donnypz.displayentityutils.managers.DisplayAnimationManager; -import net.donnypz.displayentityutils.managers.MYSQLManager; -import net.donnypz.displayentityutils.managers.MongoManager; +import net.donnypz.displayentityutils.database.MYSQLDisplayStorage; +import net.donnypz.displayentityutils.database.MongoDisplayStorage; import net.donnypz.displayentityutils.managers.PluginFolders; import net.donnypz.displayentityutils.utils.controller.DisplayController; import net.kyori.adventure.text.Component; @@ -57,7 +57,7 @@ static void read(FileConfiguration config){ String databaseName = config.getString("mongodb.database"); String groupCollection = config.getString("mongodb.groupCollection"); String animationCollection = config.getString("mongodb.animationCollection"); - MongoManager.createConnection(cString, databaseName, groupCollection, animationCollection); + MongoDisplayStorage.createConnection(cString, databaseName, groupCollection, animationCollection); } if (config.getBoolean("mysql.enabled")){ @@ -65,14 +65,14 @@ static void read(FileConfiguration config){ String username = config.getString("mysql.username"); String password = config.getString("mysql.password"); if (!config.getString("mysql.connectionURL").isBlank()){ - MYSQLManager.createConnection(config.getString("mysql.connectionURL"), username, password); + MYSQLDisplayStorage.createConnection(config.getString("mysql.connectionURL"), username, password); } else{ String database = config.getString("mysql.database"); String host = config.getString("mysql.host"); int port = config.getInt("mysql.port"); boolean useSSL = config.getBoolean("mysql.useSSL"); - MYSQLManager.createConnection(host, port, database, username, password, useSSL); + MYSQLDisplayStorage.createConnection(host, port, database, username, password, useSSL); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index 1e36db05..45393185 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -14,9 +14,9 @@ import net.donnypz.displayentityutils.listeners.gizmo.DEUGizmoListener; import net.donnypz.displayentityutils.listeners.player.*; import net.donnypz.displayentityutils.listeners.player.essentials.DEUEssentialsListener; -import net.donnypz.displayentityutils.managers.LocalManager; -import net.donnypz.displayentityutils.managers.MYSQLManager; -import net.donnypz.displayentityutils.managers.MongoManager; +import net.donnypz.displayentityutils.database.LocalDisplayStorage; +import net.donnypz.displayentityutils.database.MYSQLDisplayStorage; +import net.donnypz.displayentityutils.database.MongoDisplayStorage; import net.donnypz.displayentityutils.managers.PluginFolders; import net.donnypz.displayentityutils.skript.SkriptTypes; import net.donnypz.displayentityutils.skript.active.ActiveModule; @@ -67,9 +67,9 @@ public void onLoad() { @Override public void onEnable() { DisplayAPI.plugin = this; - DisplayAPI.LOCAL_STORAGE = new LocalManager(); - DisplayAPI.MONGODB_STORAGE = new MongoManager(); - DisplayAPI.MYSQL_STORAGE = new MYSQLManager(); + DisplayAPI.LOCAL_STORAGE = new LocalDisplayStorage(); + DisplayAPI.MONGODB_STORAGE = new MongoDisplayStorage(); + DisplayAPI.MYSQL_STORAGE = new MYSQLDisplayStorage(); DisplayAPI.ANIMATION_PLAYER_SERVICE = new AnimationPlayerProviderImpl(); DisplayAPI.BDE_CONVERSION_HANDLER = new BDEConversionHandlerImpl(); DisplayAPI.SCHEDULER = new SchedulerImpl(); @@ -93,8 +93,8 @@ public void onEnable() { @Override public void onDisable() { - MYSQLManager.closeConnection(); - MongoManager.closeConnection(); + MYSQLDisplayStorage.closeConnection(); + MongoDisplayStorage.closeConnection(); } void checkFolia(){ @@ -196,8 +196,8 @@ public static void reloadPlugin(boolean isOnEnable){ PluginFolders.createLocalSaveFolders(plugin); if (!isOnEnable){ - MongoManager.closeConnection(); - MYSQLManager.closeConnection(); + MongoDisplayStorage.closeConnection(); + MYSQLDisplayStorage.closeConnection(); } else{ plugin.saveDefaultConfig(); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/LocalDisplayStorage.java similarity index 95% rename from plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java rename to plugin/src/main/java/net/donnypz/displayentityutils/database/LocalDisplayStorage.java index 01da25ab..550fdea2 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/LocalDisplayStorage.java @@ -1,6 +1,9 @@ -package net.donnypz.displayentityutils.managers; +package net.donnypz.displayentityutils.database; import net.donnypz.displayentityutils.DisplayConfig; +import net.donnypz.displayentityutils.managers.DisplayAnimationManager; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.managers.PluginFolders; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; import net.kyori.adventure.text.Component; @@ -16,7 +19,7 @@ import java.util.List; import java.util.zip.GZIPOutputStream; -public final class LocalManager implements DisplayStorage{ +public final class LocalDisplayStorage implements DisplayStorage { public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){ try{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java similarity index 98% rename from plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java rename to plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java index a24287bc..2915fb83 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java @@ -1,8 +1,10 @@ -package net.donnypz.displayentityutils.managers; +package net.donnypz.displayentityutils.database; import com.zaxxer.hikari.HikariDataSource; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.DisplayConfig; +import net.donnypz.displayentityutils.managers.DisplayAnimationManager; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; import net.kyori.adventure.text.Component; @@ -27,7 +29,7 @@ import java.util.zip.GZIPOutputStream; -public final class MYSQLManager implements DisplayStorage{ +public final class MYSQLDisplayStorage implements DisplayStorage { private static boolean connected = false; private static HikariDataSource dataSource; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java similarity index 97% rename from plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java rename to plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java index 0452bb2a..fc4bbcc9 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.managers; +package net.donnypz.displayentityutils.database; import com.mongodb.*; import com.mongodb.client.MongoClient; @@ -7,6 +7,8 @@ import com.mongodb.client.MongoDatabase; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.DisplayConfig; +import net.donnypz.displayentityutils.managers.DisplayAnimationManager; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; import net.kyori.adventure.text.Component; @@ -31,7 +33,7 @@ import java.util.List; import java.util.zip.GZIPOutputStream; -public final class MongoManager implements DisplayStorage{ +public final class MongoDisplayStorage implements DisplayStorage { private static MongoClient client; private static MongoDatabase database; private static MongoCollection groupCollection; From 73e7a59207642fec15a833ba14b3d1f44e6e53a6 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:14:25 -0500 Subject: [PATCH 05/16] prevent SQL injection, save anims gzipped, cleanup --- .../database/DisplayStorage.java | 2 - .../database/CommonDisplayStorageUtils.java | 23 + .../database/MYSQLDisplayStorage.java | 397 +++++++----------- 3 files changed, 167 insertions(+), 255 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java b/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java index 8b9a705e..5fb9d079 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java +++ b/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java @@ -25,6 +25,4 @@ public interface DisplayStorage { @NotNull List getGroupTags(); @NotNull List getAnimationTags(); - - } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java new file mode 100644 index 00000000..6e7d743b --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java @@ -0,0 +1,23 @@ +package net.donnypz.displayentityutils.database; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.zip.GZIPOutputStream; + +class CommonDisplayStorageUtils { + + static ByteArrayInputStream toByteArrayInputStream(Object entityObject) throws IOException { + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + GZIPOutputStream gzipOut = new GZIPOutputStream(byteOut); + ObjectOutputStream objOut = new ObjectOutputStream(gzipOut); + objOut.writeObject(entityObject); + gzipOut.close(); + objOut.close(); + + byte[] data = byteOut.toByteArray(); + byteOut.close(); + return new ByteArrayInputStream(data); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java index 2915fb83..5f73f36e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java @@ -19,23 +19,37 @@ import org.jetbrains.annotations.Nullable; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.ObjectOutputStream; import java.sql.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.zip.GZIPOutputStream; public final class MYSQLDisplayStorage implements DisplayStorage { - private static boolean connected = false; - private static HikariDataSource dataSource; + private static final String GROUP_TABLE = "saved_displays"; + private static final String GROUP_COLUMN = "display_group"; + private static final String GROUP_DISPLAY_NAME = "display entity group"; - @ApiStatus.Internal - public static void createConnection(String host, int port, String database, String username, String password, boolean usessl){ + private static final String ANIMATION_TABLE = "saved_animations"; + private static final String ANIMATION_COLUMN = "display_anim"; + private static final String ANIMATION_DISPLAY_NAME = "animation"; + + private static final String TAG_COLUMN = "tag"; + + + private boolean connected = false; + private HikariDataSource dataSource; + + public void createConnection( + String host, + int port, + String database, + String username, + String password, + boolean usessl + ){ if (connected){ return; } @@ -43,8 +57,11 @@ public static void createConnection(String host, int port, String database, Stri createConnection(url, username, password); } - @ApiStatus.Internal - public static void createConnection(String url, String username, String password){ + public void createConnection( + String url, + String username, + String password + ){ if (connected){ return; } @@ -65,10 +82,11 @@ public static void createConnection(String url, String username, String password //Create Default Table Statement statement = connection.createStatement(); - String groupCreator = "CREATE TABLE IF NOT EXISTS saved_displays(tag VARCHAR(128) UNIQUE, display_group BLOB)"; - statement.execute(groupCreator); - String animCreator = "CREATE TABLE IF NOT EXISTS saved_animations(tag VARCHAR(128) UNIQUE, display_anim BLOB)"; - statement.execute(animCreator); + String groupTableSQL = "CREATE TABLE IF NOT EXISTS saved_displays(tag VARCHAR(128) UNIQUE, display_group BLOB)"; + statement.execute(groupTableSQL); + + String animTableSQL = "CREATE TABLE IF NOT EXISTS saved_animations(tag VARCHAR(128) UNIQUE, display_anim BLOB)"; + statement.execute(animTableSQL); DbUtils.closeQuietly(statement); @@ -84,17 +102,12 @@ public static void createConnection(String url, String username, String password }); } - @ApiStatus.Internal - public static void closeConnection(){ + public void closeConnection(){ try{ if (dataSource != null){ dataSource.close(); } } - /*catch(SQLException e){ - e.printStackTrace(); - Bukkit.getConsoleSender().sendMessage(Component.text("There was an error closing the connection to the MYSQL Database", NamedTextColor.RED); - }*/ finally { connected = false; dataSource = null; @@ -105,11 +118,11 @@ public static void closeConnection(){ * Check whether MySQL is connected * @return a boolean */ - public static boolean isConnected() { + public boolean isConnected() { return connected; } - private static Connection getConnection(){ + private Connection getConnection(){ try{ return dataSource.getConnection(); } @@ -118,105 +131,23 @@ private static Connection getConnection(){ } } + @Override public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){ - if (!connected){ - return false; - } - PreparedStatement statement = null; - Connection connection = null; - try{ - String tag = displayEntityGroup.getTag(); - ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - GZIPOutputStream gzipOut = new GZIPOutputStream(byteOut); - ObjectOutputStream objOut = new ObjectOutputStream(gzipOut); - objOut.writeObject(displayEntityGroup); - - gzipOut.close(); - objOut.close(); - - byte[] data = byteOut.toByteArray(); - - ByteArrayInputStream blobStream = new ByteArrayInputStream(data); - - String save = "INSERT INTO saved_displays VALUES(\""+tag+"\", ?);"; - connection = getConnection(); - statement = connection.prepareStatement(save); - statement.setBlob(1, blobStream); - if (getDisplayEntityGroup(tag) != null){ - if (DisplayConfig.overwritexistingSaves()){ - deleteDisplayEntityGroup(tag, null); - } - else{ - if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save display entity group to MYSQL!")); - saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); - } - return false; - } - } - statement.executeUpdate(); - blobStream.close(); - if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully saved display entity group to MYSQL!")); - } - return true; - } - catch(SQLIntegrityConstraintViolationException e){ - if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save display entity group to MYSQL!")); - saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); - } - e.printStackTrace(); - return false; - } - catch(SQLException | IOException e){ - if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save display entity group to MYSQL!")); - } - e.printStackTrace(); - return false; - } - finally { - DbUtils.closeQuietly(statement); - DbUtils.closeQuietly(connection); - } + String tag = displayEntityGroup.getTag(); + return saveEntity(tag, displayEntityGroup, GROUP_TABLE, GROUP_DISPLAY_NAME, saver); } + @Override public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player deleter){ - if (!isConnected()) return; - Connection connection = null; - Statement statement = null; - try{ - connection = getConnection(); - - if (!hasSingleGroup(tag, connection)){ - if (deleter != null){ - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved display entity group does not exist in MYSQL database!")); - } - return; - } - - statement = connection.createStatement(); - String delete = "DELETE FROM saved_displays WHERE tag = \""+tag+"\";"; - statement.executeUpdate(delete); - if (deleter != null){ - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted group from MYSQL")); - } - } - catch(SQLException e){ - e.printStackTrace(); - } - finally { - DbUtils.closeQuietly(statement); - DbUtils.closeQuietly(connection); - } + deleteEntity(tag, deleter, GROUP_TABLE, "display entity group"); } + @Override public @Nullable DisplayEntityGroup getDisplayEntityGroup(@NotNull String tag){ if (!isConnected()){ return null; } - Blob blob = getSingleGroupBlob(tag); + Blob blob = getEntity(tag, GROUP_TABLE, GROUP_COLUMN); if (blob == null) return null; try{ return DisplayGroupManager.getGroup(blob.getBinaryStream()); @@ -227,36 +158,63 @@ public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player delet } } + @Override public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, @Nullable Player saver){ - if (!connected){ - return false; + String tag = displayAnimation.getAnimationTag(); + return saveEntity(tag, displayAnimation, ANIMATION_TABLE, ANIMATION_DISPLAY_NAME, saver); + } + + @Override + public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter){ + deleteEntity(tag, deleter, ANIMATION_TABLE, "animation"); + } + + @Override + public @Nullable DisplayAnimation getDisplayAnimation(@NotNull String tag) { + if (!isConnected()) return null; + + try { + Blob blob = getEntity(tag, ANIMATION_TABLE, ANIMATION_COLUMN); + return blob == null + ? null + : DisplayAnimationManager.getAnimation(blob.getBinaryStream()); } - PreparedStatement statement = null; - Connection connection = null; - try{ - String tag = displayAnimation.getAnimationTag(); - ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - GZIPOutputStream gzipOut = new GZIPOutputStream(byteOut); - ObjectOutputStream objOut = new ObjectOutputStream(byteOut); - objOut.writeObject(displayAnimation); - gzipOut.close(); - objOut.close(); - - byte[] data = byteOut.toByteArray(); - byteOut.close(); - ByteArrayInputStream blobStream = new ByteArrayInputStream(data); - - String save = "INSERT INTO saved_animations VALUES(\""+tag+"\", ?);"; - connection = getConnection(); - statement = connection.prepareStatement(save); - statement.setBlob(1, blobStream); - if (getDisplayAnimation(tag) != null){ + catch (SQLException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public @NotNull List getGroupTags(){ + return getTags(GROUP_TABLE); + } + + @Override + public @NotNull List getAnimationTags(){ + return getTags(ANIMATION_TABLE); + } + + private boolean saveEntity(String tag, Object entity, String tableName, String displayName, Player saver){ + if (!isConnected()) return false; + String save = "INSERT INTO "+tableName+" VALUES(?, ?);"; + + try( + ByteArrayInputStream blobStream = CommonDisplayStorageUtils.toByteArrayInputStream(entity); + Connection connection = getConnection(); + PreparedStatement statement = connection.prepareStatement(save); + ){ + + statement.setString(1, tag); + statement.setBlob(2, blobStream); + + if (hasEntity(tag, tableName, connection)){ if (DisplayConfig.overwritexistingSaves()){ deleteDisplayAnimation(tag, null); } else{ if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save animation to MYSQL!")); + saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save "+displayName+" to MYSQL!")); saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); } return false; @@ -265,116 +223,73 @@ public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, statement.executeUpdate(); blobStream.close(); if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully saved animation to MYSQL!")); + saver.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully saved "+displayName+" to MYSQL!")); } return true; } - catch(SQLException | IOException e){ + catch(SQLIntegrityConstraintViolationException e){ if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save animation to MYSQL!")); + saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save "+displayName+" to MYSQL!")); + saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); } e.printStackTrace(); return false; } - finally { - DbUtils.closeQuietly(statement); - DbUtils.closeQuietly(connection); + catch(SQLException | IOException e){ + if (saver != null) { + saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save "+displayName+" to MYSQL!")); + } + e.printStackTrace(); + return false; } } - public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter){ - if (!isConnected()){ - return; - } - Statement statement = null; - Connection connection = null; - ResultSet resultSet = null; - try{ - connection = getConnection(); - if (!hasSingleAnimation(tag, connection)){ + + private void deleteEntity(String tag, Player deleter, String tableName, String displayName){ + if (!isConnected()) return; + + String delete = "DELETE FROM "+tableName+" WHERE "+TAG_COLUMN+" = ?;"; + try( + Connection connection = getConnection(); + PreparedStatement statement = connection.prepareStatement(delete); + ){ + + if (!hasEntity(tag, tableName, connection)){ if (deleter != null){ - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved animation does not exist in MYSQL database!")); + deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved "+displayName+" does not exist in MYSQL database!")); } return; } - statement = connection.createStatement(); - String delete = "DELETE FROM saved_animations WHERE tag = \""+tag+"\";"; + statement.setString(1, tag); statement.executeUpdate(delete); if (deleter != null){ - - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted animation from MYSQL database!")); + deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted "+displayName+" from MYSQL database!")); } } catch(SQLException e){ e.printStackTrace(); - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved animation does not exist in MYSQL database!")); - } - finally { - DbUtils.closeQuietly(resultSet); - DbUtils.closeQuietly(statement); - DbUtils.closeQuietly(connection); - } - } - - public @Nullable DisplayAnimation getDisplayAnimation(@NotNull String tag) { - if (!isConnected()){ - return null; - } - Blob blob = getSingleAnimationBlob(tag); - if (blob == null) return null; - try { - return DisplayAnimationManager.getAnimation(blob.getBinaryStream()); - } - catch (SQLException e) { - e.printStackTrace(); - return null; - } - } - - public @NotNull List getGroupTags(){ - if (!isConnected()) return Collections.emptyList(); - return getTags("saved_displays"); - } - - public @NotNull List getAnimationTags(){ - if (!isConnected()) return Collections.emptyList(); - return getTags("saved_animations"); - } - - private static boolean hasSingleGroup(String tag, Connection connection){ - Statement statement = null; - ResultSet resultSet = null; - try{ - statement = connection.createStatement(); - String retrieve = "SELECT * FROM saved_displays WHERE tag = \""+tag+"\";"; - resultSet = statement.executeQuery(retrieve); - return resultSet.next(); - }catch(SQLException e){ - return false; - } - finally { - DbUtils.closeQuietly(resultSet); - DbUtils.closeQuietly(statement); + deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved "+displayName+" does not exist in MYSQL database!")); } } - private static Blob getSingleGroupBlob(String tag){ - Statement statement = null; + private Blob getEntity(String tag, String tableName, String columnName){ + PreparedStatement statement = null; Connection connection = null; try{ connection = getConnection(); - statement = connection.createStatement(); - String retrieve = "SELECT * FROM saved_displays WHERE tag = \""+tag+"\";"; - ResultSet results = statement.executeQuery(retrieve); - if (results != null && results.next()){ - return results.getBlob("display_group"); - } - else{ - return null; - } - }catch(SQLException e){ + String retrieve = "SELECT "+columnName+" FROM "+tableName+" WHERE "+TAG_COLUMN+" = ?;"; + statement = connection.prepareStatement(retrieve); + statement.setString(1, tag); + + ResultSet results = statement.executeQuery(); + + return results.next() + ? results.getBlob(columnName) + : null; + } + catch(SQLException e){ e.printStackTrace(); return null; } @@ -384,57 +299,33 @@ private static Blob getSingleGroupBlob(String tag){ } } - private static boolean hasSingleAnimation(String tag, Connection connection){ - Statement statement = null; - ResultSet resultSet = null; - try{ - statement = connection.createStatement(); - String retrieve = "SELECT * FROM saved_animations WHERE tag = \""+tag+"\";"; - resultSet = statement.executeQuery(retrieve); - return resultSet.next(); - }catch(SQLException e){ - return false; - } - finally { - DbUtils.closeQuietly(resultSet); - DbUtils.closeQuietly(statement); - } - } + private boolean hasEntity(String tag, String tableName, Connection connection){ + String retrieve = "SELECT 1 FROM "+tableName+" WHERE "+TAG_COLUMN+" = ?;"; - private static Blob getSingleAnimationBlob(String tag){ - Statement statement = null; - Connection connection = null; - try{ - connection = getConnection(); - statement = connection.createStatement(); - String retrieve = "SELECT * FROM saved_animations WHERE tag = \""+tag+"\";"; - ResultSet results = statement.executeQuery(retrieve); - if (results != null && results.next()){ - return results.getBlob("display_anim"); - } - else{ - return null; - } - }catch(SQLException e){ - return null; + try(PreparedStatement statement = connection.prepareStatement(retrieve)){ + statement.setString(1, tag); + ResultSet resultSet = statement.executeQuery(); + return resultSet.next(); } - finally { - DbUtils.closeQuietly(statement); - DbUtils.closeQuietly(connection); + catch(SQLException e){ + return false; } } - private static List getTags(String tableName){ + private List getTags(String tableName){ //internally set table name + if (!isConnected()) return Collections.emptyList(); List tags = new ArrayList<>(); - String retrieve = "SELECT * FROM "+tableName+";"; + String retrieve = "SELECT "+TAG_COLUMN+" FROM "+tableName+";"; + try(Connection connection = getConnection(); Statement statement = connection.createStatement(); ResultSet results = statement.executeQuery(retrieve)){ while(results.next()){ - tags.add(results.getString("tag")); + tags.add(results.getString(TAG_COLUMN)); } - }catch(SQLException e){ + } + catch(SQLException e){ e.printStackTrace(); } return tags; From 07aeb9390a4899068f2669c9feb9a95e2236f63f Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:30:45 -0500 Subject: [PATCH 06/16] add DBDisplayStorage interface to cleanup code in some areas --- .../displayentityutils/DisplayAPI.java | 22 ++--- .../displayentityutils/ConfigUtils.java | 27 +++++- .../DisplayEntityPlugin.java | 29 ++++--- .../database/DBDisplayStorage.java | 15 ++++ .../database/MYSQLDisplayStorage.java | 5 +- .../database/MongoDisplayStorage.java | 86 +++++++++++-------- 6 files changed, 117 insertions(+), 67 deletions(-) create mode 100644 plugin/src/main/java/net/donnypz/displayentityutils/database/DBDisplayStorage.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index 26ab3022..1b9f41b2 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -12,6 +12,9 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import java.util.HashMap; +import java.util.Map; + public final class DisplayAPI { public static final Component pluginPrefix = Component.text("[DisplayEntityUtils] ", NamedTextColor.YELLOW); @@ -29,9 +32,7 @@ public final class DisplayAPI { private static final String legacyPartTagPrefix = "deu.parttag_"; - static DisplayStorage LOCAL_STORAGE; - static DisplayStorage MYSQL_STORAGE; - static DisplayStorage MONGODB_STORAGE; + static Map storages = new HashMap<>(); static AnimationPlayer.AnimationPlayerProvider ANIMATION_PLAYER_SERVICE; static BDEConversionHandler BDE_CONVERSION_HANDLER; static Scheduler SCHEDULER; @@ -113,20 +114,7 @@ public static boolean isEssentialsInstalled() { } public static DisplayStorage getStorage(@NotNull LoadMethod method){ - switch(method){ - case LOCAL -> { - return LOCAL_STORAGE; - } - case MYSQL -> { - return MYSQL_STORAGE; - } - case MONGODB -> { - return MONGODB_STORAGE; - } - default -> { - return null; - } - } + return storages.get(method); } public static Scheduler getScheduler(){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java index bf2e89b0..19f6aff2 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java @@ -1,8 +1,9 @@ package net.donnypz.displayentityutils; -import net.donnypz.displayentityutils.managers.DisplayAnimationManager; import net.donnypz.displayentityutils.database.MYSQLDisplayStorage; import net.donnypz.displayentityutils.database.MongoDisplayStorage; +import net.donnypz.displayentityutils.managers.DisplayAnimationManager; +import net.donnypz.displayentityutils.managers.LoadMethod; import net.donnypz.displayentityutils.managers.PluginFolders; import net.donnypz.displayentityutils.utils.controller.DisplayController; import net.kyori.adventure.text.Component; @@ -57,22 +58,40 @@ static void read(FileConfiguration config){ String databaseName = config.getString("mongodb.database"); String groupCollection = config.getString("mongodb.groupCollection"); String animationCollection = config.getString("mongodb.animationCollection"); - MongoDisplayStorage.createConnection(cString, databaseName, groupCollection, animationCollection); + ((MongoDisplayStorage) DisplayAPI.getStorage(LoadMethod.MONGODB)).createConnection( + cString, + databaseName, + groupCollection, + animationCollection + ); } if (config.getBoolean("mysql.enabled")){ DisplayConfig.isMYSQLEnabled = true; String username = config.getString("mysql.username"); String password = config.getString("mysql.password"); + if (!config.getString("mysql.connectionURL").isBlank()){ - MYSQLDisplayStorage.createConnection(config.getString("mysql.connectionURL"), username, password); + String connectionUrl = config.getString("mysql.connectionURL"); + ((MYSQLDisplayStorage) DisplayAPI.getStorage(LoadMethod.MYSQL)).createConnection( + connectionUrl, + username, + password + ); } else{ String database = config.getString("mysql.database"); String host = config.getString("mysql.host"); int port = config.getInt("mysql.port"); boolean useSSL = config.getBoolean("mysql.useSSL"); - MYSQLDisplayStorage.createConnection(host, port, database, username, password, useSSL); + ((MYSQLDisplayStorage) DisplayAPI.getStorage(LoadMethod.MYSQL)).createConnection( + host, + port, + database, + username, + password, + useSSL + ); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index 45393185..8ddd3113 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -5,6 +5,7 @@ import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.event.PacketListenerPriority; import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; +import net.donnypz.displayentityutils.database.*; import net.donnypz.displayentityutils.listeners.autogroup.DEULoadingListeners; import net.donnypz.displayentityutils.listeners.bdengine.BDEngineConversionListener; import net.donnypz.displayentityutils.listeners.entity.DEUEntityListener; @@ -14,9 +15,7 @@ import net.donnypz.displayentityutils.listeners.gizmo.DEUGizmoListener; import net.donnypz.displayentityutils.listeners.player.*; import net.donnypz.displayentityutils.listeners.player.essentials.DEUEssentialsListener; -import net.donnypz.displayentityutils.database.LocalDisplayStorage; -import net.donnypz.displayentityutils.database.MYSQLDisplayStorage; -import net.donnypz.displayentityutils.database.MongoDisplayStorage; +import net.donnypz.displayentityutils.managers.LoadMethod; import net.donnypz.displayentityutils.managers.PluginFolders; import net.donnypz.displayentityutils.skript.SkriptTypes; import net.donnypz.displayentityutils.skript.active.ActiveModule; @@ -51,6 +50,8 @@ import org.jetbrains.annotations.ApiStatus; import org.skriptlang.skript.addon.SkriptAddon; +import java.util.Map; + public final class DisplayEntityPlugin extends JavaPlugin implements Listener { SkriptAddon addon; @@ -67,9 +68,11 @@ public void onLoad() { @Override public void onEnable() { DisplayAPI.plugin = this; - DisplayAPI.LOCAL_STORAGE = new LocalDisplayStorage(); - DisplayAPI.MONGODB_STORAGE = new MongoDisplayStorage(); - DisplayAPI.MYSQL_STORAGE = new MYSQLDisplayStorage(); + Map storages = DisplayAPI.storages; + storages.put(LoadMethod.LOCAL, new LocalDisplayStorage()); + storages.put(LoadMethod.MONGODB, new MongoDisplayStorage()); + storages.put(LoadMethod.MYSQL, new MYSQLDisplayStorage()); + DisplayAPI.ANIMATION_PLAYER_SERVICE = new AnimationPlayerProviderImpl(); DisplayAPI.BDE_CONVERSION_HANDLER = new BDEConversionHandlerImpl(); DisplayAPI.SCHEDULER = new SchedulerImpl(); @@ -93,8 +96,11 @@ public void onEnable() { @Override public void onDisable() { - MYSQLDisplayStorage.closeConnection(); - MongoDisplayStorage.closeConnection(); + for (DisplayStorage storage : DisplayAPI.storages.values()) { + if (storage instanceof DBDisplayStorage ds){ + ds.closeConnection(); + } + } } void checkFolia(){ @@ -196,8 +202,11 @@ public static void reloadPlugin(boolean isOnEnable){ PluginFolders.createLocalSaveFolders(plugin); if (!isOnEnable){ - MongoDisplayStorage.closeConnection(); - MYSQLDisplayStorage.closeConnection(); + for (DisplayStorage storage : DisplayAPI.storages.values()) { + if (storage instanceof DBDisplayStorage ds){ + ds.closeConnection(); + } + } } else{ plugin.saveDefaultConfig(); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/DBDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/DBDisplayStorage.java new file mode 100644 index 00000000..635eba9b --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/DBDisplayStorage.java @@ -0,0 +1,15 @@ +package net.donnypz.displayentityutils.database; + +public interface DBDisplayStorage extends DisplayStorage { + + /** + * Check if this Database store is connected + * @return a boolean + */ + boolean isConnected(); + + /** + * Close this active database connection + */ + void closeConnection(); +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java index 5f73f36e..66a31fd4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java @@ -14,7 +14,6 @@ import org.apache.commons.dbutils.DbUtils; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,7 +25,7 @@ import java.util.List; -public final class MYSQLDisplayStorage implements DisplayStorage { +public final class MYSQLDisplayStorage implements DBDisplayStorage { private static final String GROUP_TABLE = "saved_displays"; private static final String GROUP_COLUMN = "display_group"; @@ -102,6 +101,7 @@ public void createConnection( }); } + @Override public void closeConnection(){ try{ if (dataSource != null){ @@ -118,6 +118,7 @@ public void closeConnection(){ * Check whether MySQL is connected * @return a boolean */ + @Override public boolean isConnected() { return connected; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java index fc4bbcc9..352881bc 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java @@ -28,18 +28,26 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.zip.GZIPOutputStream; -public final class MongoDisplayStorage implements DisplayStorage { +public final class MongoDisplayStorage implements DBDisplayStorage { private static MongoClient client; private static MongoDatabase database; - private static MongoCollection groupCollection; - private static MongoCollection animationCollection; + + private static MongoCollection GROUP_COLLECTION; + private static final String GROUP_FIELD = "displayGroup"; + private static final String GROUP_DISPLAY_NAME = "display entity group"; + + private static MongoCollection ANIMATION_COLLECTION; + private static final String ANIMATION_FIELD = "displayAnimation"; + private static final String ANIMATION_DISPLAY_NAME = "animation"; + + private static final String TAG_FIELD = "tag"; + private static boolean isConnected = false; + @Override public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){ if (!isConnected){ return false; @@ -62,7 +70,7 @@ public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityG if (existing != null){ if (DisplayConfig.overwritexistingSaves()){ Bson updateOperation = new Document ("$set", doc); - groupCollection.updateOne(existing, updateOperation); + GROUP_COLLECTION.updateOne(existing, updateOperation); } else{ if (saver != null){ @@ -74,7 +82,7 @@ public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityG } else{ - groupCollection.insertOne(doc); + GROUP_COLLECTION.insertOne(doc); } if (saver != null) { @@ -91,12 +99,13 @@ public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityG } } + @Override public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player deleter){ if (!isConnected()) return; DisplayAPI.getScheduler().runAsync(() -> { Document doc = getGroupDocument(tag); if (doc != null){ - groupCollection.deleteOne(doc); + GROUP_COLLECTION.deleteOne(doc); if (deleter != null){ deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted group from MongoDB!")); @@ -109,6 +118,7 @@ public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player delet }); } + @Override public @Nullable DisplayEntityGroup getDisplayEntityGroup(@NotNull String tag){ if (!isConnected) return null; Document doc = getGroupDocument(tag); @@ -121,6 +131,7 @@ public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player delet } + @Override public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, @Nullable Player saver){ if (!isConnected){ return false; @@ -143,7 +154,7 @@ public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, if (existing != null){ if (DisplayConfig.overwritexistingSaves()){ Bson updateOperation = new Document ("$set", doc); - animationCollection.updateOne(existing, updateOperation); + ANIMATION_COLLECTION.updateOne(existing, updateOperation); } else{ if (saver != null){ @@ -155,7 +166,7 @@ public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, } else{ - animationCollection.insertOne(doc); + ANIMATION_COLLECTION.insertOne(doc); } if (saver != null) { @@ -172,12 +183,13 @@ public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, } } + @Override public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter){ if (!isConnected()) return; DisplayAPI.getScheduler().runAsync(() -> { Document doc = getAnimationDocument(tag); if (doc != null){ - animationCollection.deleteOne(doc); + ANIMATION_COLLECTION.deleteOne(doc); if (deleter != null){ deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted animation from MongoDB database!")); return; @@ -189,6 +201,7 @@ public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter }); } + @Override public @Nullable DisplayAnimation getDisplayAnimation(@NotNull String tag){ if (!isConnected){ return null; @@ -203,26 +216,33 @@ public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter } + @Override public @NotNull List getGroupTags(){ - if (!isConnected()) return Collections.emptyList(); - List tags = new ArrayList<>(); - for(Document doc : groupCollection.find()){ - tags.add(doc.getString("tag")); - } - return tags; + return getTags(GROUP_COLLECTION); } + @Override public @NotNull List getAnimationTags(){ + return getTags(ANIMATION_COLLECTION); + + } + + private List getTags(MongoCollection collection){ if (!isConnected()) return Collections.emptyList(); List tags = new ArrayList<>(); - for(Document doc : animationCollection.find()){ + for(Document doc : collection.find()){ tags.add(doc.getString("tag")); } return tags; } @ApiStatus.Internal - public static void createConnection(String connectionString, String databaseName, String groupColl, String animColl) { + public void createConnection( + String connectionString, + String databaseName, + String groupColl, + String animColl + ) { if (isConnected()){ return; } @@ -248,8 +268,8 @@ public static void createConnection(String connectionString, String databaseName createIfNotExisting(groupColl); createIfNotExisting(animColl); - groupCollection = database.getCollection(groupColl); - animationCollection = database.getCollection(animColl); + GROUP_COLLECTION = database.getCollection(groupColl); + ANIMATION_COLLECTION = database.getCollection(animColl); Bukkit.getConsoleSender().sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully connected to MongoDB!"))); isConnected = true; @@ -262,7 +282,7 @@ public static void createConnection(String connectionString, String databaseName }); } - private static void createIfNotExisting(String collectionName){ + private void createIfNotExisting(String collectionName){ boolean contains = false; for (String s : database.listCollectionNames()){ if (s.equals(collectionName)){ @@ -272,11 +292,12 @@ private static void createIfNotExisting(String collectionName){ } if (!contains){ database.createCollection(collectionName); - groupCollection = database.getCollection(collectionName); + GROUP_COLLECTION = database.getCollection(collectionName); } } - public static void closeConnection(){ + @Override + public void closeConnection(){ if (client == null || !isConnected){ return; } @@ -291,20 +312,17 @@ public static void closeConnection(){ } } - /** - * Check whether MongoDB is connected - * @return a boolean - */ - public static boolean isConnected(){ + @Override + public boolean isConnected(){ return isConnected; } - private static Document getGroupDocument(String tag){ - return groupCollection.find(new Document("tag", tag)).first(); + private Document getGroupDocument(String tag){ + return GROUP_COLLECTION.find(new Document("tag", tag)).first(); } - private static Document getAnimationDocument(String tag){ - return animationCollection.find(new Document("tag", tag)).first(); + private Document getAnimationDocument(String tag){ + return ANIMATION_COLLECTION.find(new Document("tag", tag)).first(); } } From 5788bdc53c47f3850c49e704c12ef9b2b9524941 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:28:22 -0500 Subject: [PATCH 07/16] cleanup mongodb logic. reduce query result size, getting only needed data --- .../database/CommonDisplayStorageUtils.java | 13 + .../database/MongoDisplayStorage.java | 378 ++++++++---------- 2 files changed, 190 insertions(+), 201 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java index 6e7d743b..4eb94e9b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java @@ -20,4 +20,17 @@ static ByteArrayInputStream toByteArrayInputStream(Object entityObject) throws I byteOut.close(); return new ByteArrayInputStream(data); } + + static byte[] toByteArray(Object entityObject) throws IOException { + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + GZIPOutputStream gzipOut = new GZIPOutputStream(byteOut); + ObjectOutputStream objOut = new ObjectOutputStream(gzipOut); + objOut.writeObject(entityObject); + gzipOut.close(); + objOut.close(); + + byte[] data = byteOut.toByteArray(); + byteOut.close(); + return data; + } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java index 352881bc..70eca3f2 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java @@ -5,6 +5,7 @@ import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Projections; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.DisplayConfig; import net.donnypz.displayentityutils.managers.DisplayAnimationManager; @@ -20,20 +21,14 @@ import org.bson.types.Binary; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.ObjectOutputStream; import java.util.*; -import java.util.zip.GZIPOutputStream; public final class MongoDisplayStorage implements DBDisplayStorage { - private static MongoClient client; - private static MongoDatabase database; private static MongoCollection GROUP_COLLECTION; private static final String GROUP_FIELD = "displayGroup"; @@ -45,198 +40,10 @@ public final class MongoDisplayStorage implements DBDisplayStorage { private static final String TAG_FIELD = "tag"; - private static boolean isConnected = false; + private MongoClient client; + private MongoDatabase database; + private boolean isConnected = false; - @Override - public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){ - if (!isConnected){ - return false; - } - try{ - ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - GZIPOutputStream gzipOut = new GZIPOutputStream(byteOut); - ObjectOutputStream objOut = new ObjectOutputStream(gzipOut); - objOut.writeObject(displayEntityGroup); - - gzipOut.close(); - objOut.close(); - byte[] data = byteOut.toByteArray(); - Document doc = new Document(); - - doc.append("tag", displayEntityGroup.getTag()) - .append("displayGroup", data); - - Document existing = getGroupDocument(displayEntityGroup.getTag()); - if (existing != null){ - if (DisplayConfig.overwritexistingSaves()){ - Bson updateOperation = new Document ("$set", doc); - GROUP_COLLECTION.updateOne(existing, updateOperation); - } - else{ - if (saver != null){ - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save display entity group to MongoDB!")); - saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); - } - return false; - } - - } - else{ - GROUP_COLLECTION.insertOne(doc); - } - - if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully saved display entity group to MongoDB!")); - } - return true; - } - catch(IOException ex){ - ex.printStackTrace(); - if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save display entity group to MongoDB!")); - } - return false; - } - } - - @Override - public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player deleter){ - if (!isConnected()) return; - DisplayAPI.getScheduler().runAsync(() -> { - Document doc = getGroupDocument(tag); - if (doc != null){ - GROUP_COLLECTION.deleteOne(doc); - if (deleter != null){ - - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted group from MongoDB!")); - return; - } - } - if (deleter != null){ - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved display entity group does not exist in MongoDB database!")); - } - }); - } - - @Override - public @Nullable DisplayEntityGroup getDisplayEntityGroup(@NotNull String tag){ - if (!isConnected) return null; - Document doc = getGroupDocument(tag); - if (doc == null){ - return null; - } - byte[] bytes = ((Binary) doc.get("displayGroup")).getData(); - ByteArrayInputStream in = new ByteArrayInputStream(bytes); - return DisplayGroupManager.getGroup(in); - } - - - @Override - public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, @Nullable Player saver){ - if (!isConnected){ - return false; - } - try{ - ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - GZIPOutputStream gzipOut = new GZIPOutputStream(byteOut); - ObjectOutputStream objOut = new ObjectOutputStream(gzipOut); - objOut.writeObject(displayAnimation); - gzipOut.close(); - objOut.close(); - - byte[] data = byteOut.toByteArray(); - Document doc = new Document(); - - doc.append("tag", displayAnimation.getAnimationTag()) - .append("displayAnimation", data); - - Document existing = getAnimationDocument(displayAnimation.getAnimationTag()); - if (existing != null){ - if (DisplayConfig.overwritexistingSaves()){ - Bson updateOperation = new Document ("$set", doc); - ANIMATION_COLLECTION.updateOne(existing, updateOperation); - } - else{ - if (saver != null){ - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save animation to MongoDB!")); - saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); - } - return false; - } - - } - else{ - ANIMATION_COLLECTION.insertOne(doc); - } - - if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully saved animation to MongoDB!")); - } - return true; - } - catch(IOException ex){ - ex.printStackTrace(); - if (saver != null) { - saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save animation to MongoDB!")); - } - return false; - } - } - - @Override - public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter){ - if (!isConnected()) return; - DisplayAPI.getScheduler().runAsync(() -> { - Document doc = getAnimationDocument(tag); - if (doc != null){ - ANIMATION_COLLECTION.deleteOne(doc); - if (deleter != null){ - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted animation from MongoDB database!")); - return; - } - } - if (deleter != null){ - deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved animation does not exist in MongoDB database!")); - } - }); - } - - @Override - public @Nullable DisplayAnimation getDisplayAnimation(@NotNull String tag){ - if (!isConnected){ - return null; - } - Document doc = getAnimationDocument(tag); - if (doc == null){ - return null; - } - byte[] bytes = ((Binary) doc.get("displayAnimation")).getData(); - ByteArrayInputStream in = new ByteArrayInputStream(bytes); - return DisplayAnimationManager.getAnimation(in); - } - - - @Override - public @NotNull List getGroupTags(){ - return getTags(GROUP_COLLECTION); - } - - @Override - public @NotNull List getAnimationTags(){ - return getTags(ANIMATION_COLLECTION); - - } - - private List getTags(MongoCollection collection){ - if (!isConnected()) return Collections.emptyList(); - List tags = new ArrayList<>(); - for(Document doc : collection.find()){ - tags.add(doc.getString("tag")); - } - return tags; - } - - @ApiStatus.Internal public void createConnection( String connectionString, String databaseName, @@ -296,6 +103,11 @@ private void createIfNotExisting(String collectionName){ } } + @Override + public boolean isConnected(){ + return isConnected; + } + @Override public void closeConnection(){ if (client == null || !isConnected){ @@ -313,16 +125,180 @@ public void closeConnection(){ } @Override - public boolean isConnected(){ - return isConnected; + public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){ + String tag = displayEntityGroup.getTag(); + return saveEntity( + tag, + displayEntityGroup, + GROUP_COLLECTION, + GROUP_FIELD, + "display entity group", + saver); + } + + @Override + public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player deleter){ + deleteEntity( + tag, + GROUP_COLLECTION, + GROUP_DISPLAY_NAME, + deleter + ); + } + + @Override + public @Nullable DisplayEntityGroup getDisplayEntityGroup(@NotNull String tag){ + if (!isConnected) return null; + Document doc = getGroupDocument(tag); + if (doc == null){ + return null; + } + byte[] bytes = ((Binary) doc.get(GROUP_FIELD)).getData(); + ByteArrayInputStream in = new ByteArrayInputStream(bytes); + return DisplayGroupManager.getGroup(in); + } + + + @Override + public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, @Nullable Player saver){ + String tag = displayAnimation.getAnimationTag(); + return saveEntity( + tag, + displayAnimation, + ANIMATION_COLLECTION, + ANIMATION_FIELD, + "animation", + saver + ); + } + + @Override + public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter){ + deleteEntity( + tag, + ANIMATION_COLLECTION, + ANIMATION_DISPLAY_NAME, + deleter + ); + } + + @Override + public @Nullable DisplayAnimation getDisplayAnimation(@NotNull String tag){ + if (!isConnected){ + return null; + } + Document doc = getAnimationDocument(tag); + if (doc == null){ + return null; + } + byte[] bytes = ((Binary) doc.get(ANIMATION_FIELD)).getData(); + ByteArrayInputStream in = new ByteArrayInputStream(bytes); + return DisplayAnimationManager.getAnimation(in); + } + + + @Override + public @NotNull List getGroupTags(){ + return getTags(GROUP_COLLECTION); + } + + @Override + public @NotNull List getAnimationTags(){ + return getTags(ANIMATION_COLLECTION); + } + + + private boolean saveEntity( + String tag, + Object entity, + MongoCollection collection, + String fieldName, + String displayName, + Player saver){ + if (!isConnected) return false; + try{ + byte[] data = CommonDisplayStorageUtils.toByteArray(entity); + Document doc = new Document(); + + doc + .append(TAG_FIELD, tag) + .append(fieldName, data); + + Document existing = getGroupDocument(tag); + if (existing != null){ + if (DisplayConfig.overwritexistingSaves()){ + Bson updateOperation = new Document ("$set", doc); + collection.updateOne(existing, updateOperation); + } + else{ + if (saver != null){ + saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save "+displayName+" to MongoDB!")); + saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); + } + return false; + } + + } + else{ + collection.insertOne(doc); + } + + if (saver != null) { + saver.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully saved "+displayName+" to MongoDB!")); + } + return true; + } + catch(IOException ex){ + ex.printStackTrace(); + if (saver != null) { + saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save "+displayName+" to MongoDB!")); + } + return false; + } + } + + private void deleteEntity( + String tag, + MongoCollection collection, + String displayName, + Player deleter + ){ + if (!isConnected()) return; + Document doc = getGroupDocument(tag); + if (doc != null){ + collection.deleteOne(doc); + if (deleter != null){ + deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted "+displayName+" from MongoDB!")); + return; + } + } + if (deleter != null){ + deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved "+displayName+" does not exist in MongoDB database!")); + } + } + + private List getTags(MongoCollection collection){ + if (!isConnected()) return new ArrayList<>(); + + return collection.find() + .projection( + Projections.fields( + Projections.include(TAG_FIELD), + Projections.excludeId() + ) + ) + .map(doc -> doc.getString(TAG_FIELD)) + .into(new ArrayList<>()); } private Document getGroupDocument(String tag){ - return GROUP_COLLECTION.find(new Document("tag", tag)).first(); + return GROUP_COLLECTION.find(new Document(TAG_FIELD, tag)) + .first(); } private Document getAnimationDocument(String tag){ - return ANIMATION_COLLECTION.find(new Document("tag", tag)).first(); + return ANIMATION_COLLECTION.find(new Document(TAG_FIELD, tag)) + .first(); } } From 30407f2f2ce823f111289f1be1a7784b5c2a39bf Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:30:39 -0500 Subject: [PATCH 08/16] Update db related dependencies --- plugin/pom.xml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/plugin/pom.xml b/plugin/pom.xml index 89a3cf69..ac3321ca 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -102,7 +102,6 @@ org.mongodb mongodb-driver-sync - 5.1.2 @@ -114,7 +113,7 @@ com.zaxxer HikariCP - 5.1.0 + 7.1.0 @@ -153,4 +152,16 @@ + + + + org.mongodb + mongodb-driver-bom + 5.11.1 + pom + import + + + + \ No newline at end of file From ffc8399281982933bddf6305e5e830ab14372bec Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:38:22 -0500 Subject: [PATCH 09/16] create new release notes --- docs/release-notes/3.7.1.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/release-notes/3.7.1.md diff --git a/docs/release-notes/3.7.1.md b/docs/release-notes/3.7.1.md new file mode 100644 index 00000000..797f33d2 --- /dev/null +++ b/docs/release-notes/3.7.1.md @@ -0,0 +1,14 @@ +**Release Highlights** +- Database optimizations 🐇 +- Database security fixes 🔒 + +## API Changes +> [!NOTE] +>**New Version:** `3.7.1` + +### Breaking Changes +- Moved `DisplayStorage` into `net.donnypz.displayentityutils.database` package + +## Bug Fixes / QOL +- Improved queries for `MongoDB` storage +- Implemented changes to prevent SQL related security issues \ No newline at end of file From 7f1ba8faf486a4a919a89955cdb3e00b6ef9de3d Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:37:28 -0500 Subject: [PATCH 10/16] don't print stack trace for SQLIntegrityConstraintViolationException --- .../donnypz/displayentityutils/database/MYSQLDisplayStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java index 66a31fd4..0de19e13 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java @@ -233,7 +233,6 @@ private boolean saveEntity(String tag, Object entity, String tableName, String d saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save "+displayName+" to MYSQL!")); saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); } - e.printStackTrace(); return false; } catch(SQLException | IOException e){ From f6cd1b2e4b185b9139edde825fd1be5171b6ee7a Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:36:25 -0500 Subject: [PATCH 11/16] Update config for simpler mongodb connection setup --- .../displayentityutils/ConfigUtils.java | 30 +++++++-- .../database/MongoDisplayStorage.java | 63 ++++++++++++++----- plugin/src/main/resources/config.yml | 9 ++- 3 files changed, 80 insertions(+), 22 deletions(-) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java index 19f6aff2..382e2e47 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java @@ -55,15 +55,33 @@ static void read(FileConfiguration config){ if (config.getBoolean("mongodb.enabled")){ DisplayConfig.isMongoEnabled = true; String cString = config.getString("mongodb.connectionString"); + String host = config.getString("mongodb.host"); + int port = config.getInt("mongodb.port"); String databaseName = config.getString("mongodb.database"); + String username = config.getString("mongodb.username"); + String password = config.getString("mongodb.password"); String groupCollection = config.getString("mongodb.groupCollection"); String animationCollection = config.getString("mongodb.animationCollection"); - ((MongoDisplayStorage) DisplayAPI.getStorage(LoadMethod.MONGODB)).createConnection( - cString, - databaseName, - groupCollection, - animationCollection - ); + if (cString == null || cString.isBlank()){ + ((MongoDisplayStorage) DisplayAPI.getStorage(LoadMethod.MONGODB)).createConnection( + host, + port, + databaseName, + username, + password, + groupCollection, + animationCollection + ); + } + else{ + ((MongoDisplayStorage) DisplayAPI.getStorage(LoadMethod.MONGODB)).createConnection( + cString, + databaseName, + groupCollection, + animationCollection + ); + } + } if (config.getBoolean("mysql.enabled")){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java index 70eca3f2..30b9a1fd 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java @@ -44,20 +44,39 @@ public final class MongoDisplayStorage implements DBDisplayStorage { private MongoDatabase database; private boolean isConnected = false; + public void createConnection( + String host, + int port, + String databaseName, + String username, + String password, + String groupCollection, + String animationCollection + ){ + String connectionString = String.format( + "mongodb://%s:%s@%s:%d/%s", + username, + password, + host, + port, + databaseName + ); + + this.createConnection( + connectionString, + databaseName, + groupCollection, + animationCollection + ); + } + public void createConnection( String connectionString, String databaseName, - String groupColl, - String animColl + String groupCollection, + String animationCollection ) { - if (isConnected()){ - return; - } - if (databaseName.isEmpty() || groupColl.isBlank() || animColl.isBlank()){ - Bukkit.getConsoleSender().sendMessage(Component.text("There was an error connecting to the MongoDB Database! Database and/or Collection names are empty!", NamedTextColor.RED)); - isConnected = false; - return; - } + if (!this.canConnect(databaseName, groupCollection, animationCollection)) return; DisplayAPI.getScheduler().runAsync(() -> { try{ @@ -72,11 +91,11 @@ public void createConnection( client = MongoClients.create(settings); database = client.getDatabase(databaseName); - createIfNotExisting(groupColl); - createIfNotExisting(animColl); + this.createIfNotExisting(groupCollection); + this.createIfNotExisting(animationCollection); - GROUP_COLLECTION = database.getCollection(groupColl); - ANIMATION_COLLECTION = database.getCollection(animColl); + GROUP_COLLECTION = database.getCollection(groupCollection); + ANIMATION_COLLECTION = database.getCollection(animationCollection); Bukkit.getConsoleSender().sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully connected to MongoDB!"))); isConnected = true; @@ -89,6 +108,22 @@ public void createConnection( }); } + private boolean canConnect( + String databaseName, + String groupCollection, + String animationCollection + ){ + if (isConnected()) return false; + + if (databaseName.isBlank() || groupCollection.isBlank() || animationCollection.isBlank()){ + Bukkit.getConsoleSender().sendMessage(Component.text("There was an error connecting to the MongoDB Database! Database and/or Collection names are empty!", NamedTextColor.RED)); + isConnected = false; + return false; + } + + return true; + } + private void createIfNotExisting(String collectionName){ boolean contains = false; for (String s : database.listCollectionNames()){ diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index 01acd8aa..8ca33561 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -8,10 +8,15 @@ localStorageEnabled: true #The database and collections will automatically be created if it does not exist already mongodb: enabled: false - connectionString: "" + host: "localhost" + port: 27017 database: "DisplayEntityUtils" + username: "root" + password: "password" groupCollection: "saved_displays" animationCollection: "saved_animations" + #Using a connection string will override settings above + connectionString: "" mysql: enabled: false @@ -21,7 +26,7 @@ mysql: username: "root" password: "password" useSSL: false -#Using connection url will override settings above +#Using a connection url will override settings above connectionURL: "" #Determine whether plugin commands should be registered and usable From d4356ba4d21cf03ba91c5008b280f3af8586517b Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:37:05 -0500 Subject: [PATCH 12/16] update error messages --- .../managers/DisplayAnimationManager.java | 17 +++++++++++++++-- .../managers/DisplayGroupManager.java | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java index 28675070..c823e2c8 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java @@ -81,9 +81,22 @@ public static void deselectSpawnedAnimation(@NotNull Player player){ * @return boolean whether the save was successful */ public static boolean saveDisplayAnimation(@NotNull LoadMethod loadMethod, @NotNull DisplayAnimation displayAnimation, @Nullable Player saver){ - if (displayAnimation.getAnimationTag() == null || !loadMethod.isEnabled()){ + if (!loadMethod.isEnabled()){ + if (saver != null) { + saver.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to save animation", NamedTextColor.RED))); + saver.sendMessage(Component.text("| Storage location is not enabled.", NamedTextColor.GRAY, TextDecoration.ITALIC)); + } + return false; + } + + if (displayAnimation.getAnimationTag() == null) { + if (saver != null) { + saver.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to save animation", NamedTextColor.RED))); + saver.sendMessage(Component.text("| The animation does not have a tag.", NamedTextColor.GRAY, TextDecoration.ITALIC)); + } return false; } + boolean success = DisplayAPI.getStorage(loadMethod).saveDisplayAnimation(displayAnimation, saver); if (success){ attemptCacheAnimation(displayAnimation.getAnimationTag(), displayAnimation.toSpawnedDisplayAnimation()); @@ -104,7 +117,7 @@ public static boolean saveDisplayAnimationJson(@NotNull DisplayAnimation display if (!DisplayConfig.overwritexistingSaves()){ if (saver != null){ saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save animation JSON locally!")); - saver.sendMessage(Component.text("Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); + saver.sendMessage(Component.text("| Save with tag already exists!", NamedTextColor.GRAY, TextDecoration.ITALIC)); } return false; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index 9749ab29..4cc55575 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -428,9 +428,22 @@ public static boolean isGroupRegistered(@NotNull SpawnedDisplayEntityGroup spawn * @return boolean whether the save was successful */ public static boolean saveDisplayEntityGroup(@NotNull LoadMethod loadMethod, @NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver) { - if (displayEntityGroup.getTag() == null || !loadMethod.isEnabled()) { + if (!loadMethod.isEnabled()){ + if (saver != null) { + saver.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to save display entity group", NamedTextColor.RED))); + saver.sendMessage(Component.text("| Storage location is not enabled.", NamedTextColor.GRAY, TextDecoration.ITALIC)); + } + return false; + } + + if (displayEntityGroup.getTag() == null) { + if (saver != null) { + saver.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to save display entity group", NamedTextColor.RED))); + saver.sendMessage(Component.text("| The group does not have a tag.", NamedTextColor.GRAY, TextDecoration.ITALIC)); + } return false; } + return DisplayAPI.getStorage(loadMethod).saveDisplayEntityGroup(displayEntityGroup, saver); } From 3691850739c5004e3a62f1e5683405efc51c7fb2 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:46:22 -0500 Subject: [PATCH 13/16] Bump version to 3.7.1 --- api/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index ff4df2a4..cba5ccea 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.7.0 + 3.7.1 api diff --git a/plugin/pom.xml b/plugin/pom.xml index ac3321ca..9e57c9c9 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.7.0 + 3.7.1 plugin diff --git a/pom.xml b/pom.xml index 84da3df0..bd44d60e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.7.0 + 3.7.1 pom DisplayEntityUtils From 061ad08d68c83f9f6febaa1fa3e420586c42f3a3 Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:27:25 -0500 Subject: [PATCH 14/16] update config placeholders --- plugin/src/main/resources/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index 8ca33561..ef6c63c0 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -11,7 +11,7 @@ mongodb: host: "localhost" port: 27017 database: "DisplayEntityUtils" - username: "root" + username: "user" password: "password" groupCollection: "saved_displays" animationCollection: "saved_animations" @@ -22,8 +22,8 @@ mysql: enabled: false host: "localhost" port: 3306 - database: "mydb" - username: "root" + database: "displayentityutils" + username: "user" password: "password" useSSL: false #Using a connection url will override settings above @@ -102,7 +102,7 @@ autoCulling: heightCullingAdder: 1.0 #Optionally cache animations after retrieving them from a storage location. -#This option prevents constant server freezes/lag when retrieving animations at the cost of using more memory +#This option can prevent server freezes/lag when retrieving animations at the cost of using more memory cacheAnimations: enabled: true From 4d6bfc6dc5976c5e9a97c14ea8f5d88cd170dead Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:27:55 -0500 Subject: [PATCH 15/16] update release notes --- docs/release-notes/3.7.1.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes/3.7.1.md b/docs/release-notes/3.7.1.md index 797f33d2..4e5e9717 100644 --- a/docs/release-notes/3.7.1.md +++ b/docs/release-notes/3.7.1.md @@ -1,7 +1,11 @@ **Release Highlights** +- Updated config ⚙ - Database optimizations 🐇 - Database security fixes 🔒 +## Config Changes +- Added additional config settings for `mongodb`, simplifying connections + ## API Changes > [!NOTE] >**New Version:** `3.7.1` From 0975aee1857bdb5d132148d1add9efba699df7cf Mon Sep 17 00:00:00 2001 From: Jay <76460079+PZDonny@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:30:10 -0500 Subject: [PATCH 16/16] update release notes --- docs/release-notes/3.7.1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/3.7.1.md b/docs/release-notes/3.7.1.md index 4e5e9717..633fcadb 100644 --- a/docs/release-notes/3.7.1.md +++ b/docs/release-notes/3.7.1.md @@ -15,4 +15,4 @@ ## Bug Fixes / QOL - Improved queries for `MongoDB` storage -- Implemented changes to prevent SQL related security issues \ No newline at end of file +- Implemented changes to prevent SQL injection \ No newline at end of file