fix: data save bug

This commit is contained in:
ineanto 2025-05-18 22:15:34 +02:00
parent 8e32264087
commit bcea10c9db
Signed by: ineanto
GPG key ID: E511F9CAA2F9CE84
9 changed files with 73 additions and 44 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.
- 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

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

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

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