diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 162fbbbc..c3c27b2e 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -41,10 +41,17 @@ 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
+ - 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:
@@ -61,7 +68,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: |-
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/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java
index bfd95dd3..1b9f41b2 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;
@@ -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/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayStorage.java b/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java
similarity index 94%
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..5fb9d079 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;
@@ -25,6 +25,4 @@ public interface DisplayStorage {
@NotNull List getGroupTags();
@NotNull List getAnimationTags();
-
-
}
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();
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);
}
diff --git a/docs/release-notes/3.7.1.md b/docs/release-notes/3.7.1.md
new file mode 100644
index 00000000..633fcadb
--- /dev/null
+++ b/docs/release-notes/3.7.1.md
@@ -0,0 +1,18 @@
+**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`
+
+### Breaking Changes
+- Moved `DisplayStorage` into `net.donnypz.displayentityutils.database` package
+
+## Bug Fixes / QOL
+- Improved queries for `MongoDB` storage
+- Implemented changes to prevent SQL injection
\ No newline at end of file
diff --git a/plugin/pom.xml b/plugin/pom.xml
index 89a3cf69..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
@@ -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
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/ConfigUtils.java
index 6e524e62..382e2e47 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.database.MYSQLDisplayStorage;
+import net.donnypz.displayentityutils.database.MongoDisplayStorage;
import net.donnypz.displayentityutils.managers.DisplayAnimationManager;
-import net.donnypz.displayentityutils.managers.MYSQLManager;
-import net.donnypz.displayentityutils.managers.MongoManager;
+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;
@@ -54,25 +55,61 @@ 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");
- MongoManager.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")){
DisplayConfig.isMYSQLEnabled = true;
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);
+ 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");
- MYSQLManager.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 1e36db05..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.managers.LocalManager;
-import net.donnypz.displayentityutils.managers.MYSQLManager;
-import net.donnypz.displayentityutils.managers.MongoManager;
+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 LocalManager();
- DisplayAPI.MONGODB_STORAGE = new MongoManager();
- DisplayAPI.MYSQL_STORAGE = new MYSQLManager();
+ 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() {
- MYSQLManager.closeConnection();
- MongoManager.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){
- MongoManager.closeConnection();
- MYSQLManager.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/CommonDisplayStorageUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java
new file mode 100644
index 00000000..4eb94e9b
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java
@@ -0,0 +1,36 @@
+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);
+ }
+
+ 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/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/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/database/MYSQLDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java
new file mode 100644
index 00000000..0de19e13
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java
@@ -0,0 +1,333 @@
+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;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.apache.commons.dbutils.DbUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+public final class MYSQLDisplayStorage implements DBDisplayStorage {
+
+ 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";
+
+ 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;
+ }
+ String url = "jdbc:mysql://"+host+":"+port+"/"+database+"?autoReconnect=true&allowMultiQueries=true&useSSL="+usessl;
+ createConnection(url, username, password);
+ }
+
+ public void createConnection(
+ String url,
+ String username,
+ String password
+ ){
+ if (connected){
+ return;
+ }
+ DisplayAPI.getScheduler().runAsync(() -> {
+ try {
+ //Set Data Source
+ dataSource = new HikariDataSource();
+ dataSource.setJdbcUrl(url);
+ dataSource.setUsername(username);
+ dataSource.setPassword(password);
+
+ dataSource.setMinimumIdle(3);
+ dataSource.setMaximumPoolSize(6);
+
+ //Test Connection
+ Connection connection = dataSource.getConnection();
+
+
+ //Create Default Table
+ Statement statement = connection.createStatement();
+ 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);
+ DbUtils.closeQuietly(connection);
+
+ Bukkit.getConsoleSender().sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully connected to MYSQL!")));
+ connected = true;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ Bukkit.getConsoleSender().sendMessage(DisplayAPI.pluginPrefix.append(Component.text("There was an error connecting to the MYSQL database", NamedTextColor.RED)));
+ closeConnection();
+ }
+ });
+ }
+
+ @Override
+ public void closeConnection(){
+ try{
+ if (dataSource != null){
+ dataSource.close();
+ }
+ }
+ finally {
+ connected = false;
+ dataSource = null;
+ }
+ }
+
+ /**
+ * Check whether MySQL is connected
+ * @return a boolean
+ */
+ @Override
+ public boolean isConnected() {
+ return connected;
+ }
+
+ private Connection getConnection(){
+ try{
+ return dataSource.getConnection();
+ }
+ catch(SQLException e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){
+ String tag = displayEntityGroup.getTag();
+ return saveEntity(tag, displayEntityGroup, GROUP_TABLE, GROUP_DISPLAY_NAME, saver);
+ }
+
+ @Override
+ public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player deleter){
+ deleteEntity(tag, deleter, GROUP_TABLE, "display entity group");
+ }
+
+ @Override
+ public @Nullable DisplayEntityGroup getDisplayEntityGroup(@NotNull String tag){
+ if (!isConnected()){
+ return null;
+ }
+ Blob blob = getEntity(tag, GROUP_TABLE, GROUP_COLUMN);
+ if (blob == null) return null;
+ try{
+ return DisplayGroupManager.getGroup(blob.getBinaryStream());
+ }
+ catch(SQLException e){
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Override
+ public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, @Nullable Player saver){
+ 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());
+ }
+ 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 "+displayName+" 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 "+displayName+" to MYSQL!"));
+ }
+ return true;
+ }
+ catch(SQLIntegrityConstraintViolationException e){
+ if (saver != null) {
+ 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;
+ }
+ catch(SQLException | IOException e){
+ if (saver != null) {
+ saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save "+displayName+" to MYSQL!"));
+ }
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+
+
+ 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 "+displayName+" does not exist in MYSQL database!"));
+ }
+ return;
+ }
+
+ statement.setString(1, tag);
+ statement.executeUpdate(delete);
+ if (deleter != null){
+ deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted "+displayName+" from MYSQL database!"));
+ }
+ }
+ catch(SQLException e){
+ e.printStackTrace();
+ deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved "+displayName+" does not exist in MYSQL database!"));
+ }
+ }
+
+ private Blob getEntity(String tag, String tableName, String columnName){
+ PreparedStatement statement = null;
+ Connection connection = null;
+ try{
+ connection = getConnection();
+ 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;
+ }
+ finally {
+ DbUtils.closeQuietly(statement);
+ DbUtils.closeQuietly(connection);
+ }
+ }
+
+ private boolean hasEntity(String tag, String tableName, Connection connection){
+ String retrieve = "SELECT 1 FROM "+tableName+" WHERE "+TAG_COLUMN+" = ?;";
+
+ try(PreparedStatement statement = connection.prepareStatement(retrieve)){
+ statement.setString(1, tag);
+ ResultSet resultSet = statement.executeQuery();
+ return resultSet.next();
+ }
+ catch(SQLException e){
+ return false;
+ }
+ }
+
+ private List getTags(String tableName){ //internally set table name
+ if (!isConnected()) return Collections.emptyList();
+ List tags = new ArrayList<>();
+ 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_COLUMN));
+ }
+ }
+ catch(SQLException e){
+ e.printStackTrace();
+ }
+ return tags;
+ }
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java
new file mode 100644
index 00000000..30b9a1fd
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java
@@ -0,0 +1,339 @@
+package net.donnypz.displayentityutils.database;
+
+import com.mongodb.*;
+import com.mongodb.client.MongoClient;
+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;
+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;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+import org.bson.types.Binary;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.*;
+
+public final class MongoDisplayStorage implements DBDisplayStorage {
+
+ 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 MongoClient client;
+ 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 groupCollection,
+ String animationCollection
+ ) {
+ if (!this.canConnect(databaseName, groupCollection, animationCollection)) return;
+
+ DisplayAPI.getScheduler().runAsync(() -> {
+ try{
+ ConnectionString cString = new ConnectionString(connectionString);
+ MongoClientSettings settings = MongoClientSettings.builder()
+ .applyConnectionString(cString)
+ .serverApi(ServerApi.builder()
+ .version(ServerApiVersion.V1)
+ .build())
+ .build();
+
+ client = MongoClients.create(settings);
+ database = client.getDatabase(databaseName);
+
+ this.createIfNotExisting(groupCollection);
+ this.createIfNotExisting(animationCollection);
+
+ 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;
+ }
+ catch (IllegalArgumentException | MongoException e){
+ isConnected = false;
+ Bukkit.getConsoleSender().sendMessage(Component.text("There was an error connecting to the MongoDB Database!", NamedTextColor.RED));
+ e.printStackTrace();
+ }
+ });
+ }
+
+ 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()){
+ if (s.equals(collectionName)){
+ contains = true;
+ break;
+ }
+ }
+ if (!contains){
+ database.createCollection(collectionName);
+ GROUP_COLLECTION = database.getCollection(collectionName);
+ }
+ }
+
+ @Override
+ public boolean isConnected(){
+ return isConnected;
+ }
+
+ @Override
+ public void closeConnection(){
+ if (client == null || !isConnected){
+ return;
+ }
+ try{
+ client.close();
+ isConnected = false;
+ }
+ catch(MongoException e){
+ isConnected = false;
+ e.printStackTrace();
+ Bukkit.getConsoleSender().sendMessage(Component.text("There was an error closing the connection to the MongoDB Database", NamedTextColor.RED));
+ }
+ }
+
+ @Override
+ 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_FIELD, tag))
+ .first();
+ }
+
+ private Document getAnimationDocument(String tag){
+ return ANIMATION_COLLECTION.find(new Document(TAG_FIELD, tag))
+ .first();
+ }
+
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java
deleted file mode 100644
index a24287bc..00000000
--- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MYSQLManager.java
+++ /dev/null
@@ -1,440 +0,0 @@
-package net.donnypz.displayentityutils.managers;
-
-import com.zaxxer.hikari.HikariDataSource;
-import net.donnypz.displayentityutils.DisplayAPI;
-import net.donnypz.displayentityutils.DisplayConfig;
-import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation;
-import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.format.NamedTextColor;
-import net.kyori.adventure.text.format.TextDecoration;
-import net.kyori.adventure.text.minimessage.MiniMessage;
-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;
-
-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 MYSQLManager implements DisplayStorage{
-
- private static boolean connected = false;
- private static HikariDataSource dataSource;
-
- @ApiStatus.Internal
- public static void createConnection(String host, int port, String database, String username, String password, boolean usessl){
- if (connected){
- return;
- }
- String url = "jdbc:mysql://"+host+":"+port+"/"+database+"?autoReconnect=true&allowMultiQueries=true&useSSL="+usessl;
- createConnection(url, username, password);
- }
-
- @ApiStatus.Internal
- public static void createConnection(String url, String username, String password){
- if (connected){
- return;
- }
- DisplayAPI.getScheduler().runAsync(() -> {
- try {
- //Set Data Source
- dataSource = new HikariDataSource();
- dataSource.setJdbcUrl(url);
- dataSource.setUsername(username);
- dataSource.setPassword(password);
-
- dataSource.setMinimumIdle(3);
- dataSource.setMaximumPoolSize(6);
-
- //Test Connection
- Connection connection = dataSource.getConnection();
-
-
- //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);
-
-
- DbUtils.closeQuietly(statement);
- DbUtils.closeQuietly(connection);
-
- Bukkit.getConsoleSender().sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully connected to MYSQL!")));
- connected = true;
- } catch (SQLException e) {
- e.printStackTrace();
- Bukkit.getConsoleSender().sendMessage(DisplayAPI.pluginPrefix.append(Component.text("There was an error connecting to the MYSQL database", NamedTextColor.RED)));
- closeConnection();
- }
- });
- }
-
- @ApiStatus.Internal
- public static 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;
- }
- }
-
- /**
- * Check whether MySQL is connected
- * @return a boolean
- */
- public static boolean isConnected() {
- return connected;
- }
-
- private static Connection getConnection(){
- try{
- return dataSource.getConnection();
- }
- catch(SQLException e){
- throw new RuntimeException(e);
- }
- }
-
- 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);
- }
- }
-
- 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);
- }
- }
-
- public @Nullable DisplayEntityGroup getDisplayEntityGroup(@NotNull String tag){
- if (!isConnected()){
- return null;
- }
- Blob blob = getSingleGroupBlob(tag);
- if (blob == null) return null;
- try{
- return DisplayGroupManager.getGroup(blob.getBinaryStream());
- }
- catch(SQLException e){
- e.printStackTrace();
- return null;
- }
- }
-
- public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, @Nullable Player saver){
- if (!connected){
- return false;
- }
- 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){
- if (DisplayConfig.overwritexistingSaves()){
- deleteDisplayAnimation(tag, null);
- }
- else{
- if (saver != null) {
- saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save animation 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 animation to MYSQL!"));
- }
- return true;
- }
- catch(SQLException | IOException e){
- if (saver != null) {
- saver.sendMessage(MiniMessage.miniMessage().deserialize("- Failed to save animation to MYSQL!"));
- }
- e.printStackTrace();
- return false;
- }
- finally {
- DbUtils.closeQuietly(statement);
- DbUtils.closeQuietly(connection);
- }
- }
-
- 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)){
- if (deleter != null){
- deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Saved animation does not exist in MYSQL database!"));
- }
- return;
- }
-
- statement = connection.createStatement();
- String delete = "DELETE FROM saved_animations WHERE tag = \""+tag+"\";";
- statement.executeUpdate(delete);
- if (deleter != null){
-
- deleter.sendMessage(MiniMessage.miniMessage().deserialize("- Successfully deleted animation 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);
- }
- }
-
- private static Blob getSingleGroupBlob(String tag){
- Statement 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){
- e.printStackTrace();
- return null;
- }
- finally {
- DbUtils.closeQuietly(statement);
- DbUtils.closeQuietly(connection);
- }
- }
-
- 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 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;
- }
- finally {
- DbUtils.closeQuietly(statement);
- DbUtils.closeQuietly(connection);
- }
- }
-
- private static List getTags(String tableName){
- List tags = new ArrayList<>();
- String retrieve = "SELECT * FROM "+tableName+";";
- try(Connection connection = getConnection();
- Statement statement = connection.createStatement();
- ResultSet results = statement.executeQuery(retrieve)){
-
- while(results.next()){
- tags.add(results.getString("tag"));
- }
- }catch(SQLException e){
- e.printStackTrace();
- }
- return tags;
- }
-}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java
deleted file mode 100644
index 0452bb2a..00000000
--- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/MongoManager.java
+++ /dev/null
@@ -1,308 +0,0 @@
-package net.donnypz.displayentityutils.managers;
-
-import com.mongodb.*;
-import com.mongodb.client.MongoClient;
-import com.mongodb.client.MongoClients;
-import com.mongodb.client.MongoCollection;
-import com.mongodb.client.MongoDatabase;
-import net.donnypz.displayentityutils.DisplayAPI;
-import net.donnypz.displayentityutils.DisplayConfig;
-import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation;
-import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.format.NamedTextColor;
-import net.kyori.adventure.text.format.TextDecoration;
-import net.kyori.adventure.text.minimessage.MiniMessage;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-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.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.zip.GZIPOutputStream;
-
-public final class MongoManager implements DisplayStorage{
- private static MongoClient client;
- private static MongoDatabase database;
- private static MongoCollection groupCollection;
- private static MongoCollection animationCollection;
- private static boolean isConnected = false;
-
- 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);
- groupCollection.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{
- groupCollection.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;
- }
- }
-
- 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);
- 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!"));
- }
- });
- }
-
- 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);
- }
-
-
- 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);
- animationCollection.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{
- animationCollection.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;
- }
- }
-
- 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);
- 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!"));
- }
- });
- }
-
- 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);
- }
-
-
- 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;
- }
-
- public @NotNull List getAnimationTags(){
- if (!isConnected()) return Collections.emptyList();
- List tags = new ArrayList<>();
- for(Document doc : animationCollection.find()){
- tags.add(doc.getString("tag"));
- }
- return tags;
- }
-
- @ApiStatus.Internal
- public static void createConnection(String connectionString, String databaseName, String groupColl, String animColl) {
- 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;
- }
-
- DisplayAPI.getScheduler().runAsync(() -> {
- try{
- ConnectionString cString = new ConnectionString(connectionString);
- MongoClientSettings settings = MongoClientSettings.builder()
- .applyConnectionString(cString)
- .serverApi(ServerApi.builder()
- .version(ServerApiVersion.V1)
- .build())
- .build();
-
- client = MongoClients.create(settings);
- database = client.getDatabase(databaseName);
-
- createIfNotExisting(groupColl);
- createIfNotExisting(animColl);
-
- groupCollection = database.getCollection(groupColl);
- animationCollection = database.getCollection(animColl);
-
- Bukkit.getConsoleSender().sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully connected to MongoDB!")));
- isConnected = true;
- }
- catch (IllegalArgumentException | MongoException e){
- isConnected = false;
- Bukkit.getConsoleSender().sendMessage(Component.text("There was an error connecting to the MongoDB Database!", NamedTextColor.RED));
- e.printStackTrace();
- }
- });
- }
-
- private static void createIfNotExisting(String collectionName){
- boolean contains = false;
- for (String s : database.listCollectionNames()){
- if (s.equals(collectionName)){
- contains = true;
- break;
- }
- }
- if (!contains){
- database.createCollection(collectionName);
- groupCollection = database.getCollection(collectionName);
- }
- }
-
- public static void closeConnection(){
- if (client == null || !isConnected){
- return;
- }
- try{
- client.close();
- isConnected = false;
- }
- catch(MongoException e){
- isConnected = false;
- e.printStackTrace();
- Bukkit.getConsoleSender().sendMessage(Component.text("There was an error closing the connection to the MongoDB Database", NamedTextColor.RED));
- }
- }
-
- /**
- * Check whether MongoDB is connected
- * @return a boolean
- */
- public static boolean isConnected(){
- return isConnected;
- }
-
- private static Document getGroupDocument(String tag){
- return groupCollection.find(new Document("tag", tag)).first();
- }
-
- private static Document getAnimationDocument(String tag){
- return animationCollection.find(new Document("tag", tag)).first();
- }
-
-}
diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml
index 01acd8aa..ef6c63c0 100644
--- a/plugin/src/main/resources/config.yml
+++ b/plugin/src/main/resources/config.yml
@@ -8,20 +8,25 @@ 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: "user"
+ password: "password"
groupCollection: "saved_displays"
animationCollection: "saved_animations"
+ #Using a connection string will override settings above
+ connectionString: ""
mysql:
enabled: false
host: "localhost"
port: 3306
- database: "mydb"
- username: "root"
+ database: "displayentityutils"
+ username: "user"
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
@@ -97,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
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