Compare commits

...

2 commits

Author SHA1 Message Date
1dbb199258
feat: update translation files 2025-06-06 15:10:51 +02:00
bcea10c9db
fix: data save bug 2025-05-18 22:15:34 +02:00
13 changed files with 87 additions and 57 deletions

View file

@ -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

View file

@ -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 {
@ -44,7 +45,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 {

View file

@ -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

View file

@ -0,0 +1,8 @@
package xyz.ineanto.nicko.appearance;
import javax.annotation.Nullable;
public record Appearance(
@Nullable String name,
@Nullable String skin
) {}

View file

@ -30,13 +30,13 @@ public class NickoCommand implements BasicCommand {
if (args.length >= 1 && args[0].equalsIgnoreCase("about")) {
final Component firstAboutMessage = MiniMessage.miniMessage().deserialize(
"<prefix> <gray>v<version></gray>",
"<prefix> <dark_gray>(© Ineanto 2023-2025) </dark_gray><gray>v<version></gray> ",
Placeholder.component("prefix", playerLanguage.getPrefixComponent()),
Placeholder.unparsed("version", Nicko.getInstance().getPluginMeta().getVersion())
);
final Component secondAboutMessage = MiniMessage.miniMessage().deserialize(
"<gradient:#01a97c:#8ffd54>Configuration</gradient> <gray>v<configversion></gray>, <gradient:#01a97c:#8ffd54>I18N</gradient> <gray>v<i18nversion></gray>",
"<gradient:#01a97c:#8ffd54>Configuration</gradient> <gray>v<configversion></gray>, <gradient:#01a97c:#8ffd54>I18N</gradient> <gray><i18nversion></gray>",
Placeholder.component("prefix", playerLanguage.getPrefixComponent()),
Placeholder.unparsed("configversion", Configuration.VERSION.toString()),
Placeholder.unparsed("i18nversion", Language.VERSION.toString())

View file

@ -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;

View file

@ -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<Appearance> 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<Appearance> favorites) {
this.appearance = appearance;
this.language = language;
this.randomSkin = randomSkin;
this.favorites = favorites;
}
public static Optional<NickoProfile> 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<Appearance> getFavorites() {
return favorites;
}
public void setFavorites(List<Appearance> 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;

View file

@ -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<NickoProfile> 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();
}

View file

@ -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;
}
}

View file

@ -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());

View file

@ -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());

View file

@ -1,7 +1,7 @@
# Nicko ${version} - Language File:
# Specifies the configuration version, don't change.
version: "1.3.0"
version: "1.3.1"
prefix: "<b><gradient:#01a97c:#8ffd54>NICKO</gradient></b>"
whoosh: "<b><gradient:#01a97c:#8ffd54>WHOOSH!</gradient></b>"
@ -38,7 +38,7 @@ event:
gui:
title:
home: "Nicko - Home"
home: "Nicko"
settings: "Settings"
admin: "Administration"
check: "Player Management"
@ -102,7 +102,7 @@ gui:
- "<gray>Completely remove your disguise.</gray>"
admin:
manage_cache:
name: "Manage the <gold>skin</gold> cache..."
name: "Manage the skin cache..."
lore:
- "<gray>View and manage the skin cache.</gray>"
manage_player:

View file

@ -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: "<b><gradient:#01a97c:#8ffd54>NICKO</gradient></b>"
whoosh: "<b><gradient:#01a97c:#8ffd54>WHOOSH!</gradient></b>"
@ -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:
- "<gray>Supprime complètement votre déguisement.</gray>"
admin:
manage_cache:
name: "Gérer le cache de <gold>skin...</gold>"
name: "Gérer le cache de skin..."
lore:
- "<gray>Consultez et gérez le cache de skin.</gray>"
manage_player: