From bcea10c9db08a0a5939534030f29767e6783ee40 Mon Sep 17 00:00:00 2001 From: ineanto Date: Sun, 18 May 2025 22:15:34 +0200 Subject: [PATCH 1/2] fix: data save bug --- CHANGELOG.log | 13 +++-- build.gradle.kts | 2 +- .../ineanto/nicko/appearance/Appearance.java | 8 ++++ .../ineanto/nicko/command/NickoCommand.java | 4 +- .../ineanto/nicko/profile/NickoProfile.java | 48 +++++++++++-------- .../nicko/storage/json/JSONStorage.java | 9 ++-- .../storage/json/JSONStorageProvider.java | 7 +-- .../nicko/storage/mariadb/MariaDBStorage.java | 13 +++-- .../nicko/storage/mysql/MySQLStorage.java | 13 +++-- 9 files changed, 73 insertions(+), 44 deletions(-) create mode 100644 src/main/java/xyz/ineanto/nicko/appearance/Appearance.java diff --git a/CHANGELOG.log b/CHANGELOG.log index 6056af3..ec6be1c 100644 --- a/CHANGELOG.log +++ b/CHANGELOG.log @@ -4,18 +4,23 @@ 1.2.0-RC1: Update n°12 (XX/XX/25) [FEATURES] - - Updated to support up to Minecraft 1.21.4. + - Updated to support Minecraft 1.21.5. + - Added a sub-command (/nicko about) to get information about Nicko. - Modernized the messages and added various sound effects upon interacting with the plugin. - - Made GUIs names cleaner. + - Cleaned up GUI titles. - [FIXES] - - Cleaned up the codebase to prepare for future updates. + [FIXES] - Fixed an oversight preventing the configuration from properly being migrated. + - Fixed a rare bug that could prevent data from being saved. - Fixed the placeholder item in the skin cache invalidation not being translated. + - Fixed a oversight about a column name using SQL storage. [LANGUAGE] - Moved the prefix to the language file. + [OTHER] + - Cleaned up the codebase to prepare for future updates. + 1.1.7-RC1: Hotfix n°5 (04/05/24) [OTHER] - Restored download link again on spigotmc.org diff --git a/build.gradle.kts b/build.gradle.kts index b7b8751..eb6dc02 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,7 +44,7 @@ dependencies { implementation("com.mysql:mysql-connector-j:9.2.0") implementation("org.mariadb.jdbc:mariadb-java-client:3.5.2") implementation("redis.clients:jedis:5.2.0") - implementation("com.google.code.gson:gson:2.10.1") + implementation("com.google.code.gson:gson:2.13.1") } tasks { diff --git a/src/main/java/xyz/ineanto/nicko/appearance/Appearance.java b/src/main/java/xyz/ineanto/nicko/appearance/Appearance.java new file mode 100644 index 0000000..9c40462 --- /dev/null +++ b/src/main/java/xyz/ineanto/nicko/appearance/Appearance.java @@ -0,0 +1,8 @@ +package xyz.ineanto.nicko.appearance; + +import javax.annotation.Nullable; + +public record Appearance( + @Nullable String name, + @Nullable String skin +) {} diff --git a/src/main/java/xyz/ineanto/nicko/command/NickoCommand.java b/src/main/java/xyz/ineanto/nicko/command/NickoCommand.java index 1063c4b..7b18427 100644 --- a/src/main/java/xyz/ineanto/nicko/command/NickoCommand.java +++ b/src/main/java/xyz/ineanto/nicko/command/NickoCommand.java @@ -30,13 +30,13 @@ public class NickoCommand implements BasicCommand { if (args.length >= 1 && args[0].equalsIgnoreCase("about")) { final Component firstAboutMessage = MiniMessage.miniMessage().deserialize( - " v", + " (© Ineanto 2023-2025) v ", Placeholder.component("prefix", playerLanguage.getPrefixComponent()), Placeholder.unparsed("version", Nicko.getInstance().getPluginMeta().getVersion()) ); final Component secondAboutMessage = MiniMessage.miniMessage().deserialize( - "Configuration v, I18N v", + "Configuration v, I18N ", Placeholder.component("prefix", playerLanguage.getPrefixComponent()), Placeholder.unparsed("configversion", Configuration.VERSION.toString()), Placeholder.unparsed("i18nversion", Language.VERSION.toString()) diff --git a/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java b/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java index bc75f78..139cff9 100644 --- a/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java +++ b/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java @@ -2,28 +2,36 @@ package xyz.ineanto.nicko.profile; import org.bukkit.entity.Player; import xyz.ineanto.nicko.Nicko; +import xyz.ineanto.nicko.appearance.Appearance; import xyz.ineanto.nicko.language.Language; import xyz.ineanto.nicko.storage.PlayerDataStore; +import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.UUID; public class NickoProfile implements Cloneable { - public static final NickoProfile EMPTY_PROFILE = new NickoProfile(null, null, Language.ENGLISH, true); + public static final NickoProfile EMPTY_PROFILE = new NickoProfile( + new Appearance(null, null), + Language.ENGLISH, + true, + Collections.emptyList() + ); private static final Nicko instance = Nicko.getInstance(); private static final PlayerDataStore dataStore = instance.getDataStore(); - private String name; - private String skin; + private Appearance appearance; private Language language; private boolean randomSkin; + private transient List favorites; - public NickoProfile(String name, String skin, Language language, boolean randomSkin) { - this.name = name; - this.skin = skin; + public NickoProfile(Appearance appearance, Language language, boolean randomSkin, List favorites) { + this.appearance = appearance; this.language = language; this.randomSkin = randomSkin; + this.favorites = favorites; } public static Optional get(Player player) { @@ -35,23 +43,31 @@ public class NickoProfile implements Cloneable { } public boolean hasData() { - return name != null || skin != null; + return appearance.name() != null || appearance.skin() != null; } public String getName() { - return name; + return appearance.name(); } public void setName(String name) { - this.name = name; + this.appearance = new Appearance(name, appearance.skin() == null ? null : appearance.skin()); } public String getSkin() { - return skin; + return appearance.skin(); } public void setSkin(String skin) { - this.skin = skin; + this.appearance = new Appearance(appearance.name() == null ? null : appearance.name(), skin); + } + + public List getFavorites() { + return favorites; + } + + public void setFavorites(List favorites) { + this.favorites = favorites; } public Language getLocale() { @@ -70,16 +86,6 @@ public class NickoProfile implements Cloneable { this.randomSkin = randomSkin; } - @Override - public String toString() { - return "NickoProfile{" + - "name='" + name + '\'' + - ", skin='" + skin + '\'' + - ", locale=" + language + - ", randomSkin=" + randomSkin + - '}'; - } - @Override public NickoProfile clone() { Object o; diff --git a/src/main/java/xyz/ineanto/nicko/storage/json/JSONStorage.java b/src/main/java/xyz/ineanto/nicko/storage/json/JSONStorage.java index 7e804be..cf7a15c 100644 --- a/src/main/java/xyz/ineanto/nicko/storage/json/JSONStorage.java +++ b/src/main/java/xyz/ineanto/nicko/storage/json/JSONStorage.java @@ -46,6 +46,7 @@ public class JSONStorage extends Storage { } } catch (IOException e) { logger.warning("Could not create file."); + e.printStackTrace(); return ActionResult.error(); } @@ -54,14 +55,12 @@ public class JSONStorage extends Storage { @Override public boolean isStored(UUID uuid) { - final File directory = new File(Nicko.getInstance().getDataFolder() + "/players/"); final File file = new File(directory, uuid.toString() + ".json"); return file.exists(); } @Override public Optional retrieve(UUID uuid) { - final File directory = new File(Nicko.getInstance().getDataFolder() + "/players/"); final File file = new File(directory, uuid.toString() + ".json"); try (FileReader fileReader = new FileReader(file)) { try (BufferedReader reader = new BufferedReader(fileReader)) { @@ -75,7 +74,6 @@ public class JSONStorage extends Storage { @Override public ActionResult delete(UUID uuid) { - final File directory = new File(Nicko.getInstance().getDataFolder() + "/players/"); final File file = new File(directory, uuid.toString() + ".json"); if (file.delete() || !file.exists()) { return ActionResult.ok(); @@ -84,6 +82,11 @@ public class JSONStorage extends Storage { } private boolean checkFileExists(File file) throws IOException { + // Additional check if the folder gets deleted while the plugin is running. + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + if (!file.exists()) { return file.createNewFile(); } diff --git a/src/main/java/xyz/ineanto/nicko/storage/json/JSONStorageProvider.java b/src/main/java/xyz/ineanto/nicko/storage/json/JSONStorageProvider.java index c2976f3..e360b6f 100644 --- a/src/main/java/xyz/ineanto/nicko/storage/json/JSONStorageProvider.java +++ b/src/main/java/xyz/ineanto/nicko/storage/json/JSONStorageProvider.java @@ -12,11 +12,12 @@ public class JSONStorageProvider implements StorageProvider { } @Override - public boolean init() - { + public boolean init() { return directory.exists() || directory.mkdirs(); } @Override - public boolean close() { return true; } + public boolean close() { + return true; + } } diff --git a/src/main/java/xyz/ineanto/nicko/storage/mariadb/MariaDBStorage.java b/src/main/java/xyz/ineanto/nicko/storage/mariadb/MariaDBStorage.java index f2590a1..051ff03 100644 --- a/src/main/java/xyz/ineanto/nicko/storage/mariadb/MariaDBStorage.java +++ b/src/main/java/xyz/ineanto/nicko/storage/mariadb/MariaDBStorage.java @@ -1,6 +1,7 @@ package xyz.ineanto.nicko.storage.mariadb; import xyz.ineanto.nicko.appearance.ActionResult; +import xyz.ineanto.nicko.appearance.Appearance; import xyz.ineanto.nicko.config.Configuration; import xyz.ineanto.nicko.language.Language; import xyz.ineanto.nicko.profile.NickoProfile; @@ -10,6 +11,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Collections; import java.util.Optional; import java.util.UUID; import java.util.logging.Logger; @@ -83,15 +85,16 @@ public class MariaDBStorage extends Storage { String name = ""; String skin = ""; String locale = ""; - boolean bungeecord = false; + boolean randomSkin = false; while (resultSet.next()) { name = resultSet.getString("name"); skin = resultSet.getString("skin"); locale = resultSet.getString("locale"); - bungeecord = resultSet.getBoolean("bungeecord"); + randomSkin = resultSet.getBoolean("randomskin"); } - final NickoProfile profile = new NickoProfile(name, skin, Language.fromCode(locale), bungeecord); + // TODO (Ineanto, 17/05/2025): Retrieve favorites + final NickoProfile profile = new NickoProfile(new Appearance(name, skin), Language.fromCode(locale), randomSkin, Collections.emptyList()); return Optional.of(profile); } catch (SQLException e) { logger.warning("Couldn't fetch profile: " + e.getMessage()); @@ -117,7 +120,7 @@ public class MariaDBStorage extends Storage { } private PreparedStatement getInsertStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException { - final String sql = "INSERT IGNORE INTO nicko.DATA (`uuid`, `name`, `skin`, `locale`, `bungeecord`) VALUES (?, ?, ?, ?, ?)"; + final String sql = "INSERT IGNORE INTO nicko.DATA (`uuid`, `name`, `skin`, `locale`, `randomskin`) VALUES (?, ?, ?, ?, ?)"; final PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1, uuid.toString()); statement.setString(2, profile.getName() == null ? null : profile.getName()); @@ -128,7 +131,7 @@ public class MariaDBStorage extends Storage { } private PreparedStatement getUpdateStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException { - final String sql = "UPDATE nicko.DATA SET name = ?, skin = ?, locale = ?, bungeecord = ? WHERE uuid = ?"; + final String sql = "UPDATE nicko.DATA SET name = ?, skin = ?, locale = ?, randomskin = ? WHERE uuid = ?"; final PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1, profile.getName() == null ? null : profile.getName()); statement.setString(2, profile.getSkin() == null ? null : profile.getSkin()); diff --git a/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorage.java b/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorage.java index bd3d22a..c1f0313 100644 --- a/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorage.java +++ b/src/main/java/xyz/ineanto/nicko/storage/mysql/MySQLStorage.java @@ -1,6 +1,7 @@ package xyz.ineanto.nicko.storage.mysql; import xyz.ineanto.nicko.appearance.ActionResult; +import xyz.ineanto.nicko.appearance.Appearance; import xyz.ineanto.nicko.config.Configuration; import xyz.ineanto.nicko.language.Language; import xyz.ineanto.nicko.profile.NickoProfile; @@ -10,6 +11,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Collections; import java.util.Optional; import java.util.UUID; import java.util.logging.Logger; @@ -83,15 +85,16 @@ public class MySQLStorage extends Storage { String name = ""; String skin = ""; String locale = ""; - boolean bungeecord = false; + boolean randomSkin = false; while (resultSet.next()) { name = resultSet.getString("name"); skin = resultSet.getString("skin"); locale = resultSet.getString("locale"); - bungeecord = resultSet.getBoolean("bungeecord"); + randomSkin = resultSet.getBoolean("randomskin"); } - final NickoProfile profile = new NickoProfile(name, skin, Language.fromCode(locale), bungeecord); + // TODO (Ineanto, 17/05/2025): Retrieve favorites + final NickoProfile profile = new NickoProfile(new Appearance(name, skin), Language.fromCode(locale), randomSkin, Collections.emptyList()); return Optional.of(profile); } catch (SQLException e) { logger.warning("Couldn't fetch profile: " + e.getMessage()); @@ -117,7 +120,7 @@ public class MySQLStorage extends Storage { } private PreparedStatement getInsertStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException { - final String sql = "INSERT IGNORE INTO nicko.DATA (`uuid`, `name`, `skin`, `locale`, `bungeecord`) VALUES (?, ?, ?, ?, ?)"; + final String sql = "INSERT IGNORE INTO nicko.DATA (`uuid`, `name`, `skin`, `locale`, `randomskin`) VALUES (?, ?, ?, ?, ?)"; final PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1, uuid.toString()); statement.setString(2, profile.getName() == null ? null : profile.getName()); @@ -128,7 +131,7 @@ public class MySQLStorage extends Storage { } private PreparedStatement getUpdateStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException { - final String sql = "UPDATE nicko.DATA SET name = ?, skin = ?, locale = ?, bungeecord = ? WHERE uuid = ?"; + final String sql = "UPDATE nicko.DATA SET name = ?, skin = ?, locale = ?, randomskin = ? WHERE uuid = ?"; final PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1, profile.getName() == null ? null : profile.getName()); statement.setString(2, profile.getSkin() == null ? null : profile.getSkin()); From 1dbb199258b6e920e1f843638aa891c93bccc14b Mon Sep 17 00:00:00 2001 From: ineanto Date: Fri, 6 Jun 2025 15:10:51 +0200 Subject: [PATCH 2/2] feat: update translation files --- build.gradle.kts | 11 ++++++----- gradle/wrapper/gradle-wrapper.properties | 2 +- .../java/xyz/ineanto/nicko/language/Language.java | 2 +- src/main/resources/en.yml | 6 +++--- src/main/resources/fr.yml | 6 +++--- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index eb6dc02..cd3a7b4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ plugins { id("java") id("com.gradleup.shadow") version "8.3.2" id("xyz.jpenilla.run-paper") version "2.3.0" - id("io.papermc.paperweight.userdev") version "2.0.0-beta.10" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } group = "xyz.ineanto" @@ -13,6 +13,7 @@ val invuiVersion: String = "1.44" java { sourceCompatibility = JavaVersion.VERSION_22 targetCompatibility = JavaVersion.VERSION_22 + toolchain { languageVersion = JavaLanguageVersion.of(22) } @@ -22,10 +23,10 @@ repositories { mavenCentral() mavenLocal() - maven { url = uri("https://repo.xenondevs.xyz/releases") } - maven { url = uri("https://repo.papermc.io/repository/maven-public/") } - maven { url = uri("https://repo.codemc.io/repository/maven-snapshots/") } - maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") } + maven("https://repo.xenondevs.xyz/releases") + maven("https://repo.papermc.io/repository/maven-public/") + maven("https://repo.codemc.io/repository/maven-snapshots/") + maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") } dependencies { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a79..ff23a68 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/xyz/ineanto/nicko/language/Language.java b/src/main/java/xyz/ineanto/nicko/language/Language.java index d916301..db941b6 100644 --- a/src/main/java/xyz/ineanto/nicko/language/Language.java +++ b/src/main/java/xyz/ineanto/nicko/language/Language.java @@ -9,7 +9,7 @@ public enum Language implements Serializable { FRENCH("fr", "Français"), CUSTOM("cm", "Server Custom"); - public static final Version VERSION = new Version(1, 3, 0); + public static final Version VERSION = new Version(1, 3, 1); private final String code; private transient final String name; diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml index ca18fb9..d9ca19e 100644 --- a/src/main/resources/en.yml +++ b/src/main/resources/en.yml @@ -1,7 +1,7 @@ # Nicko ${version} - Language File: # Specifies the configuration version, don't change. -version: "1.3.0" +version: "1.3.1" prefix: "NICKO" whoosh: "WHOOSH!" @@ -38,7 +38,7 @@ event: gui: title: - home: "Nicko - Home" + home: "Nicko" settings: "Settings" admin: "Administration" check: "Player Management" @@ -102,7 +102,7 @@ gui: - "Completely remove your disguise." admin: manage_cache: - name: "Manage the skin cache..." + name: "Manage the skin cache..." lore: - "View and manage the skin cache." manage_player: diff --git a/src/main/resources/fr.yml b/src/main/resources/fr.yml index a2e7472..0f6c57f 100644 --- a/src/main/resources/fr.yml +++ b/src/main/resources/fr.yml @@ -1,7 +1,7 @@ # Nicko ${version} - Fichier de langue: # Précise la version de la configuration, ne pas changer. -version: "1.3.0" +version: "1.3.1" prefix: "NICKO" whoosh: "WHOOSH!" @@ -38,7 +38,7 @@ event: gui: title: - home: "Nicko - Accueil" + home: "Nicko" settings: "Paramètres" admin: "Administration" check: "Gestion des Joueurs" @@ -103,7 +103,7 @@ gui: - "Supprime complètement votre déguisement." admin: manage_cache: - name: "Gérer le cache de skin..." + name: "Gérer le cache de skin..." lore: - "Consultez et gérez le cache de skin." manage_player: