feat(global): support only latest major versions, bump to jre17

This commit is contained in:
ineanto 2023-12-13 16:09:00 +01:00
parent 3949113dee
commit 2fc3194c8c
31 changed files with 99 additions and 199 deletions

2
.idea/gradle.xml generated
View file

@ -6,6 +6,7 @@
<GradleProjectSettings> <GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/share/java/gradle" /> <option name="gradleHome" value="/usr/share/java/gradle" />
<option name="gradleJvm" value="17" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
@ -13,5 +14,6 @@
</option> </option>
</GradleProjectSettings> </GradleProjectSettings>
</option> </option>
<option name="parallelModelFetch" value="true" />
</component> </component>
</project> </project>

5
.idea/misc.xml generated
View file

@ -5,7 +5,10 @@
<option name="description" value="" /> <option name="description" value="" />
</component> </component>
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="17" project-jdk-type="JavaSDK"> <component name="PWA">
<option name="wasEnabledAtLeastOnce" value="true" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View file

@ -1,4 +1,8 @@
Update n°4 (11/12/23): 1.0.7-RC1: Update n°4 (11/12/23)
[OTHER] [OTHER]
• In line with my thinking that Minecraft servers should always be in one of the latest versions to give developers more freedom and less maintenance hassle,
Nicko will now only be supporting the previous major version and current major version.
This results in this version of Nicko now needing at minimum of JRE 17 and a server running 1.19.
If you can't upgrade, consider skipping the plugin altogether. I'm sorry.
• Various optimizations and improvements. • Various optimizations and improvements.

View file

@ -6,15 +6,17 @@ plugins {
} }
group = "xyz.ineanto" group = "xyz.ineanto"
version = "1.0.6-RC1" version = "1.0.7-RC1"
val shadowImplementation: Configuration by configurations.creating val shadowImplementation: Configuration by configurations.creating
configurations["implementation"].extendsFrom(shadowImplementation) configurations["implementation"].extendsFrom(shadowImplementation)
configurations["testImplementation"].extendsFrom(shadowImplementation) configurations["testImplementation"].extendsFrom(shadowImplementation)
java { java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
toolchain { toolchain {
languageVersion = JavaLanguageVersion.of(8) languageVersion = JavaLanguageVersion.of(17)
} }
} }

View file

@ -65,7 +65,7 @@ public class NickoBukkit extends JavaPlugin {
} }
if (!MinecraftVersion.VILLAGE_UPDATE.atOrAbove()) { if (!MinecraftVersion.WILD_UPDATE.atOrAbove()) {
getLogger().severe("This version (" + MinecraftVersion.getCurrentVersion().getVersion() + ") is not supported by Nicko!"); getLogger().severe("This version (" + MinecraftVersion.getCurrentVersion().getVersion() + ") is not supported by Nicko!");
dataStore.getStorage().setError(true); dataStore.getStorage().setError(true);
Bukkit.getPluginManager().disablePlugin(this); Bukkit.getPluginManager().disablePlugin(this);

View file

@ -112,7 +112,7 @@ public class AppearanceManager {
final MojangSkin skinResult = skin.get(); final MojangSkin skinResult = skin.get();
final Multimap<String, WrappedSignedProperty> properties = gameProfile.getProperties(); final Multimap<String, WrappedSignedProperty> properties = gameProfile.getProperties();
properties.get("textures").clear(); properties.get("textures").clear();
properties.put("textures", new WrappedSignedProperty("textures", skinResult.getValue(), skinResult.getSignature())); properties.put("textures", new WrappedSignedProperty("textures", skinResult.value(), skinResult.signature()));
} else { } else {
return ActionResult.error(I18NDict.Error.MOJANG_SKIN); return ActionResult.error(I18NDict.Error.MOJANG_SKIN);
} }
@ -144,7 +144,6 @@ public class AppearanceManager {
respawn.setSeed(world.getSeed()); respawn.setSeed(world.getSeed());
respawn.setGameMode(player.getGameMode()); respawn.setGameMode(player.getGameMode());
respawn.setPreviousGameMode(player.getGameMode()); respawn.setPreviousGameMode(player.getGameMode());
respawn.setDifficulty(world.getDifficulty());
respawn.setCopyMetadata(true); respawn.setCopyMetadata(true);
respawn.sendPacket(player); respawn.sendPacket(player);
player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);

View file

@ -12,8 +12,7 @@ import xyz.ineanto.nicko.i18n.I18NDict;
public class NickoCommand implements CommandExecutor { public class NickoCommand implements CommandExecutor {
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (sender instanceof Player) { if (sender instanceof Player player) {
final Player player = (Player) sender;
if (player.isOp() || player.hasPermission("nicko.use") || player.hasPermission("nicko.*")) { if (player.isOp() || player.hasPermission("nicko.use") || player.hasPermission("nicko.*")) {
new HomeGUI(player).open(); new HomeGUI(player).open();
} else { } else {

View file

@ -53,7 +53,6 @@ public class PlayerJoinListener implements Listener {
} }
}); });
// TODO (Ineanto, 12/6/23): Make this cleaner.
for (Player online : Bukkit.getOnlinePlayers().stream().filter(op -> op.getUniqueId() != player.getUniqueId()).collect(Collectors.toList())) { for (Player online : Bukkit.getOnlinePlayers().stream().filter(op -> op.getUniqueId() != player.getUniqueId()).collect(Collectors.toList())) {
final Optional<NickoProfile> optionalOnlinePlayerProfile = dataStore.getData(online.getUniqueId()); final Optional<NickoProfile> optionalOnlinePlayerProfile = dataStore.getData(online.getUniqueId());

View file

@ -23,7 +23,6 @@ public class SettingsGUI {
"B # # # # # # # #" "B # # # # # # # #"
}; };
// TODO: 3/6/23 Replace when Redis is not enabled
dynamicStructure[1] = dynamicStructure[1].replace("T", "U"); dynamicStructure[1] = dynamicStructure[1].replace("T", "U");
final I18N i18n = new I18N(player); final I18N i18n = new I18N(player);

View file

@ -21,8 +21,8 @@ public class ScrollDownItem extends ScrollItem {
public ItemProvider getItemProvider(ScrollGui gui) { public ItemProvider getItemProvider(ScrollGui gui) {
final ItemBuilder builder = new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE); final ItemBuilder builder = new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE);
final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.SCROLL_DOWN); final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.SCROLL_DOWN);
builder.setDisplayName(translation.getName()); builder.setDisplayName(translation.name());
if (!gui.canScroll(1)) translation.getLore().forEach(builder::addLoreLines); if (!gui.canScroll(1)) translation.lore().forEach(builder::addLoreLines);
return builder; return builder;
} }
} }

View file

@ -21,8 +21,8 @@ public class ScrollUpItem extends ScrollItem {
public ItemProvider getItemProvider(ScrollGui gui) { public ItemProvider getItemProvider(ScrollGui gui) {
final ItemBuilder builder = new ItemBuilder(Material.RED_STAINED_GLASS_PANE); final ItemBuilder builder = new ItemBuilder(Material.RED_STAINED_GLASS_PANE);
final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.SCROLL_UP); final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.SCROLL_UP);
builder.setDisplayName(translation.getName()); builder.setDisplayName(translation.name());
if (!gui.canScroll(-1)) translation.getLore().forEach(builder::addLoreLines); if (!gui.canScroll(-1)) translation.lore().forEach(builder::addLoreLines);
return builder; return builder;
} }

View file

@ -51,8 +51,8 @@ public class BungeeCordCyclingItem {
final ItemBuilder builder = new ItemBuilder(Material.COMPASS); final ItemBuilder builder = new ItemBuilder(Material.COMPASS);
final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.Settings.BUNGEECORD); final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.Settings.BUNGEECORD);
builder.setDisplayName(translation.getName()); builder.setDisplayName(translation.name());
translation.getLore().forEach(builder::addLoreLines); translation.lore().forEach(builder::addLoreLines);
/* /*
if (enabled) { if (enabled) {
builder.addLoreLines("§7> §cDisabled"); builder.addLoreLines("§7> §cDisabled");

View file

@ -43,7 +43,6 @@ public class LanguageCyclingItem {
nickoProfile.setLocale(Locale.values()[integer]); nickoProfile.setLocale(Locale.values()[integer]);
observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C
player.getOpenInventory().close(); player.getOpenInventory().close();
// TODO (Ineanto, 7/14/23): This checks a 2nd time for the profile.
if (dataStore.updateCache(player.getUniqueId(), nickoProfile).isError()) { if (dataStore.updateCache(player.getUniqueId(), nickoProfile).isError()) {
player.sendMessage(i18n.translate(I18NDict.Event.Settings.ERROR)); player.sendMessage(i18n.translate(I18NDict.Event.Settings.ERROR));
} else { } else {
@ -59,7 +58,7 @@ public class LanguageCyclingItem {
final ItemBuilder builder = new ItemBuilder(Material.OAK_SIGN); final ItemBuilder builder = new ItemBuilder(Material.OAK_SIGN);
final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.Settings.LANGUAGE); final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.Settings.LANGUAGE);
builder.setDisplayName(translation.getName()); builder.setDisplayName(translation.name());
for (Locale value : locales) { for (Locale value : locales) {
if (locale != value) { if (locale != value) {
builder.addLoreLines("§7> " + value.getName()); builder.addLoreLines("§7> " + value.getName());
@ -67,7 +66,7 @@ public class LanguageCyclingItem {
builder.addLoreLines("§6§l> §f" + value.getName()); builder.addLoreLines("§6§l> §f" + value.getName());
} }
} }
translation.getLore().forEach(builder::addLoreLines); translation.lore().forEach(builder::addLoreLines);
return builder; return builder;
} }

View file

@ -38,8 +38,8 @@ public class I18N {
public AbstractItemBuilder<?> translateItem(AbstractItemBuilder<?> item, String key, Object... args) { public AbstractItemBuilder<?> translateItem(AbstractItemBuilder<?> item, String key, Object... args) {
final ItemTranslation translation = fetchTranslation(key, args); final ItemTranslation translation = fetchTranslation(key, args);
item.setDisplayName(translation.getName()); item.setDisplayName(translation.name());
translation.getLore().forEach(item::addLoreLines); translation.lore().forEach(item::addLoreLines);
return item; return item;
} }
@ -51,7 +51,7 @@ public class I18N {
if (name == null) { if (name == null) {
logger.warning(nameKey + " doesn't exists! Please translate this entry."); logger.warning(nameKey + " doesn't exists! Please translate this entry.");
return new ItemTranslation(nameKey, new ArrayList<String>() {{ return new ItemTranslation(nameKey, new ArrayList<>() {{
add(loreKey); add(loreKey);
}}); }});
} }

View file

@ -9,8 +9,8 @@ public class I18NDict {
public static final String CACHE = ERROR_KEY + "cache"; public static final String CACHE = ERROR_KEY + "cache";
public static final String MOJANG_NAME = ERROR_KEY + "mojang_name"; public static final String MOJANG_NAME = ERROR_KEY + "mojang_name";
public static final String MOJANG_SKIN = ERROR_KEY + "mojang_skin"; public static final String MOJANG_SKIN = ERROR_KEY + "mojang_skin";
public static final String SQL_ERROR = ERROR_KEY + "sql"; public static final String SQL = ERROR_KEY + "sql";
public static final String JSON_ERROR = ERROR_KEY + "json"; public static final String JSON = ERROR_KEY + "json";
} }
public static class Event { public static class Event {
@ -74,7 +74,6 @@ public class I18NDict {
public static final String GO_BACK = GUI_KEY + "go_back"; public static final String GO_BACK = GUI_KEY + "go_back";
public static final String UNAVAILABLE = GUI_KEY + "unavailable"; public static final String UNAVAILABLE = GUI_KEY + "unavailable";
public static final String LOADING = GUI_KEY + "loading"; public static final String LOADING = GUI_KEY + "loading";
public static final String ERROR = GUI_KEY + "error";
public static final String SCROLL_UP = GUI_KEY + "scroll_up"; public static final String SCROLL_UP = GUI_KEY + "scroll_up";
public static final String SCROLL_DOWN = GUI_KEY + "scroll_down"; public static final String SCROLL_DOWN = GUI_KEY + "scroll_down";

View file

@ -2,20 +2,4 @@ package xyz.ineanto.nicko.i18n;
import java.util.ArrayList; import java.util.ArrayList;
public class ItemTranslation { public record ItemTranslation(String name, ArrayList<String> lore) {}
private final String name;
private final ArrayList<String> lore;
public ItemTranslation(String name, ArrayList<String> lore) {
this.name = name;
this.lore = lore;
}
public String getName() {
return name;
}
public ArrayList<String> getLore() {
return lore;
}
}

View file

@ -27,7 +27,7 @@ public class MojangAPI {
private final Logger logger = Logger.getLogger("MojangAPI"); private final Logger logger = Logger.getLogger("MojangAPI");
private final HashMap<String, String> uuidToName = new HashMap<>(); private final HashMap<String, String> uuidToName = new HashMap<>();
private final CacheLoader<String, Optional<MojangSkin>> skinLoader = new CacheLoader<String, Optional<MojangSkin>>() { private final CacheLoader<String, Optional<MojangSkin>> skinLoader = new CacheLoader<>() {
@Nonnull @Nonnull
public Optional<MojangSkin> load(@Nonnull String uuid) throws Exception { public Optional<MojangSkin> load(@Nonnull String uuid) throws Exception {
return getSkinFromMojang(uuid); return getSkinFromMojang(uuid);
@ -40,7 +40,7 @@ public class MojangAPI {
.expireAfterWrite(24, TimeUnit.HOURS) .expireAfterWrite(24, TimeUnit.HOURS)
.build(skinLoader); .build(skinLoader);
private final CacheLoader<String, Optional<String>> uuidLoader = new CacheLoader<String, Optional<String>>() { private final CacheLoader<String, Optional<String>> uuidLoader = new CacheLoader<>() {
@Nonnull @Nonnull
public Optional<String> load(@Nonnull String name) throws Exception { public Optional<String> load(@Nonnull String name) throws Exception {
return getUUIDFromMojang(name); return getUUIDFromMojang(name);

View file

@ -2,27 +2,11 @@ package xyz.ineanto.nicko.mojang;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
public class MojangSkin { public record MojangSkin(String value, String signature) {
private final String value;
private final String signature;
public MojangSkin(String value, String signature) {
this.value = value;
this.signature = signature;
}
public static MojangSkin buildFromJson(JsonObject object) { public static MojangSkin buildFromJson(JsonObject object) {
final JsonObject properties = object.get("properties").getAsJsonArray().get(0).getAsJsonObject(); final JsonObject properties = object.get("properties").getAsJsonArray().get(0).getAsJsonObject();
final String value = properties.get("value").getAsString(); final String value = properties.get("value").getAsString();
final String signature = properties.get("signature").getAsString(); final String signature = properties.get("signature").getAsString();
return new MojangSkin(value, signature); return new MojangSkin(value, signature);
} }
public String getValue() {
return value;
}
public String getSignature() {
return signature;
}
} }

View file

@ -64,17 +64,12 @@ public class NickoExpansion extends PlaceholderExpansion {
bungeecord = profile.isBungeecordTransfer(); bungeecord = profile.isBungeecordTransfer();
} }
switch (params) { return switch (params) {
case "name": case "name" -> name;
return name; case "skin" -> skin;
case "skin": case "locale" -> locale;
return skin; case "bungeecord" -> String.valueOf(bungeecord);
case "locale": default -> null;
return locale; };
case "bungeecord":
return String.valueOf(bungeecord);
default:
return null;
}
} }
} }

View file

@ -32,13 +32,13 @@ public class PlayerDataStore {
} }
public ActionResult updateCache(UUID uuid, NickoProfile profile) { public ActionResult updateCache(UUID uuid, NickoProfile profile) {
final Optional<NickoProfile> retrieved = getData(uuid); if (storage.isError() || cache.isError()) {
if (retrieved.isPresent()) { return ActionResult.error(I18NDict.Error.CACHE);
}
getCache().cache(uuid, profile); getCache().cache(uuid, profile);
return ActionResult.ok(); return ActionResult.ok();
} }
return ActionResult.error(I18NDict.Error.CACHE);
}
public Optional<NickoProfile> getData(UUID uuid) { public Optional<NickoProfile> getData(UUID uuid) {
if (storage.isError() || cache.isError()) { if (storage.isError() || cache.isError()) {
@ -59,7 +59,7 @@ public class PlayerDataStore {
} }
public Optional<NickoProfile> getOfflineData(String name) { public Optional<NickoProfile> getOfflineData(String name) {
if (storage.isError()) { if (storage.isError() || cache.isError()) {
return Optional.empty(); return Optional.empty();
} }
@ -76,12 +76,12 @@ public class PlayerDataStore {
} }
public ActionResult saveData(Player player) { public ActionResult saveData(Player player) {
if (storage.isError()) return ActionResult.error(I18NDict.Error.GENERIC); if (storage.isError()) return ActionResult.error(I18NDict.Error.SQL);
if (cache.isError()) return ActionResult.error(I18NDict.Error.CACHE); if (cache.isError()) return ActionResult.error(I18NDict.Error.CACHE);
if (!cache.isCached(player.getUniqueId())) return ActionResult.error(I18NDict.Error.GENERIC); if (!cache.isCached(player.getUniqueId())) return ActionResult.error(I18NDict.Error.CACHE);
final Optional<NickoProfile> cachedProfile = cache.retrieve(player.getUniqueId()); final Optional<NickoProfile> cachedProfile = cache.retrieve(player.getUniqueId());
if (!cachedProfile.isPresent()) return ActionResult.error(I18NDict.Error.GENERIC); if (!cachedProfile.isPresent()) return ActionResult.error(I18NDict.Error.CACHE);
cache.delete(player.getUniqueId()); cache.delete(player.getUniqueId());
return storage.store(player.getUniqueId(), cachedProfile.get()); return storage.store(player.getUniqueId(), cachedProfile.get());

View file

@ -42,12 +42,12 @@ public class JSONStorage extends Storage {
} }
} catch (IOException e) { } catch (IOException e) {
logger.warning("Could not write to file."); logger.warning("Could not write to file.");
return ActionResult.error(I18NDict.Error.JSON_ERROR); return ActionResult.error(I18NDict.Error.JSON);
} }
} }
} catch (IOException e) { } catch (IOException e) {
logger.warning("Could not create file."); logger.warning("Could not create file.");
return ActionResult.error(I18NDict.Error.JSON_ERROR); return ActionResult.error(I18NDict.Error.JSON);
} }
return ActionResult.ok(); return ActionResult.ok();
@ -81,7 +81,7 @@ public class JSONStorage extends Storage {
if (file.delete() || !file.exists()) { if (file.delete() || !file.exists()) {
return ActionResult.ok(); return ActionResult.ok();
} }
return ActionResult.error(I18NDict.Error.JSON_ERROR); return ActionResult.error(I18NDict.Error.JSON);
} }
private boolean checkFileExists(File file) throws IOException { private boolean checkFileExists(File file) throws IOException {

View file

@ -36,7 +36,7 @@ public class MariaDBStorage extends Storage {
@Override @Override
public ActionResult store(UUID uuid, NickoProfile profile) { public ActionResult store(UUID uuid, NickoProfile profile) {
final Connection connection = getProvider().getConnection(); final Connection connection = getProvider().getConnection();
if (connection == null) return ActionResult.error(I18NDict.Error.SQL_ERROR); if (connection == null) return ActionResult.error(I18NDict.Error.SQL);
try { try {
final PreparedStatement statement = isStored(uuid) ? final PreparedStatement statement = isStored(uuid) ?
@ -45,7 +45,7 @@ public class MariaDBStorage extends Storage {
return ActionResult.ok(); return ActionResult.ok();
} catch (SQLException e) { } catch (SQLException e) {
logger.warning("Couldn't send SQL Request: " + e.getMessage()); logger.warning("Couldn't send SQL Request: " + e.getMessage());
return ActionResult.error(I18NDict.Error.SQL_ERROR); return ActionResult.error(I18NDict.Error.SQL);
} }
} }
@ -103,17 +103,17 @@ public class MariaDBStorage extends Storage {
@Override @Override
public ActionResult delete(UUID uuid) { public ActionResult delete(UUID uuid) {
final Connection connection = getProvider().getConnection(); final Connection connection = getProvider().getConnection();
if (connection == null) return ActionResult.error(I18NDict.Error.SQL_ERROR); if (connection == null) return ActionResult.error(I18NDict.Error.SQL);
try { try {
final String sql = "DELETE FROM nicko.DATA WHERE uuid = ?"; final String sql = "DELETE FROM nicko.DATA WHERE uuid = ?";
final PreparedStatement statement = connection.prepareStatement(sql); final PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, uuid.toString()); statement.setString(1, uuid.toString());
int rows = statement.executeUpdate(); int rows = statement.executeUpdate();
return (rows == 1 ? ActionResult.ok() : ActionResult.error(I18NDict.Error.SQL_ERROR)); return (rows == 1 ? ActionResult.ok() : ActionResult.error(I18NDict.Error.SQL));
} catch (SQLException e) { } catch (SQLException e) {
logger.warning("Couldn't delete profile: " + e.getMessage()); logger.warning("Couldn't delete profile: " + e.getMessage());
return ActionResult.error(I18NDict.Error.SQL_ERROR); return ActionResult.error(I18NDict.Error.SQL);
} }
} }

View file

@ -58,15 +58,13 @@ public class MariaDBStorageProvider implements StorageProvider {
private void createTable() throws SQLException { private void createTable() throws SQLException {
final Connection connection = getConnection(); final Connection connection = getConnection();
final String query = "CREATE TABLE IF NOT EXISTS %s.DATA ".replace("%s", schemaName) +
String query = "CREATE TABLE IF NOT EXISTS %s.DATA " +
"(uuid varchar(36) NOT NULL," + "(uuid varchar(36) NOT NULL," +
"name varchar(16)," + "name varchar(16)," +
"skin varchar(16)," + "skin varchar(16)," +
"locale char(2) NOT NULL," + "locale char(2) NOT NULL," +
"bungeecord boolean NOT NULL," + "bungeecord boolean NOT NULL," +
"PRIMARY KEY (uuid))"; "PRIMARY KEY (uuid))";
query = query.replace("%s", schemaName);
final PreparedStatement statement = connection.prepareStatement(query); final PreparedStatement statement = connection.prepareStatement(query);
statement.executeUpdate(); statement.executeUpdate();
@ -74,9 +72,7 @@ public class MariaDBStorageProvider implements StorageProvider {
private void createDatabase() throws SQLException { private void createDatabase() throws SQLException {
final Connection connection = getConnection(); final Connection connection = getConnection();
final String query = "CREATE DATABASE IF NOT EXISTS %s".replace("%s", schemaName);
String query = "CREATE DATABASE IF NOT EXISTS %s";
query = query.replace("%s", schemaName);
final PreparedStatement statement = connection.prepareStatement(query); final PreparedStatement statement = connection.prepareStatement(query);
statement.executeUpdate(); statement.executeUpdate();

View file

@ -36,7 +36,7 @@ public class MySQLStorage extends Storage {
@Override @Override
public ActionResult store(UUID uuid, NickoProfile profile) { public ActionResult store(UUID uuid, NickoProfile profile) {
final Connection connection = getProvider().getConnection(); final Connection connection = getProvider().getConnection();
if (connection == null) return ActionResult.error(I18NDict.Error.SQL_ERROR); if (connection == null) return ActionResult.error(I18NDict.Error.SQL);
try { try {
final PreparedStatement statement = isStored(uuid) ? final PreparedStatement statement = isStored(uuid) ?
@ -45,7 +45,7 @@ public class MySQLStorage extends Storage {
return ActionResult.ok(); return ActionResult.ok();
} catch (SQLException e) { } catch (SQLException e) {
logger.warning("Couldn't send SQL Request: " + e.getMessage()); logger.warning("Couldn't send SQL Request: " + e.getMessage());
return ActionResult.error(I18NDict.Error.SQL_ERROR); return ActionResult.error(I18NDict.Error.SQL);
} }
} }
@ -103,17 +103,17 @@ public class MySQLStorage extends Storage {
@Override @Override
public ActionResult delete(UUID uuid) { public ActionResult delete(UUID uuid) {
final Connection connection = getProvider().getConnection(); final Connection connection = getProvider().getConnection();
if (connection == null) return ActionResult.error(I18NDict.Error.SQL_ERROR); if (connection == null) return ActionResult.error(I18NDict.Error.SQL);
try { try {
final String sql = "DELETE FROM nicko.DATA WHERE uuid = ?"; final String sql = "DELETE FROM nicko.DATA WHERE uuid = ?";
final PreparedStatement statement = connection.prepareStatement(sql); final PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, uuid.toString()); statement.setString(1, uuid.toString());
int rows = statement.executeUpdate(); int rows = statement.executeUpdate();
return (rows == 1 ? ActionResult.ok() : ActionResult.error(I18NDict.Error.SQL_ERROR)); return (rows == 1 ? ActionResult.ok() : ActionResult.error(I18NDict.Error.SQL));
} catch (SQLException e) { } catch (SQLException e) {
logger.warning("Couldn't delete profile: " + e.getMessage()); logger.warning("Couldn't delete profile: " + e.getMessage());
return ActionResult.error(I18NDict.Error.SQL_ERROR); return ActionResult.error(I18NDict.Error.SQL);
} }
} }

View file

@ -58,15 +58,13 @@ public class MySQLStorageProvider implements StorageProvider {
private void createTable() throws SQLException { private void createTable() throws SQLException {
final Connection connection = getConnection(); final Connection connection = getConnection();
final String query = "CREATE TABLE IF NOT EXISTS %s.DATA ".replace("%s", schemaName) +
String query = "CREATE TABLE IF NOT EXISTS %s.DATA " +
"(uuid varchar(36) NOT NULL," + "(uuid varchar(36) NOT NULL," +
"name varchar(16)," + "name varchar(16)," +
"skin varchar(16)," + "skin varchar(16)," +
"locale char(2) NOT NULL," + "locale char(2) NOT NULL," +
"bungeecord boolean NOT NULL," + "bungeecord boolean NOT NULL," +
"PRIMARY KEY (uuid))"; "PRIMARY KEY (uuid))";
query = query.replace("%s", schemaName);
final PreparedStatement statement = connection.prepareStatement(query); final PreparedStatement statement = connection.prepareStatement(query);
statement.executeUpdate(); statement.executeUpdate();
@ -74,9 +72,7 @@ public class MySQLStorageProvider implements StorageProvider {
private void createDatabase() throws SQLException { private void createDatabase() throws SQLException {
final Connection connection = getConnection(); final Connection connection = getConnection();
final String query = "CREATE DATABASE IF NOT EXISTS %s".replace("%s", schemaName);
String query = "CREATE DATABASE IF NOT EXISTS %s";
query = query.replace("%s", schemaName);
final PreparedStatement statement = connection.prepareStatement(query); final PreparedStatement statement = connection.prepareStatement(query);
statement.executeUpdate(); statement.executeUpdate();

View file

@ -51,7 +51,7 @@ public class RedisCache extends Cache {
public Optional<NickoProfile> retrieve(UUID uuid) { public Optional<NickoProfile> retrieve(UUID uuid) {
try (Jedis jedis = provider.getJedis()) { try (Jedis jedis = provider.getJedis()) {
// 08/29/23: what the fuck was I talking about? // 08/29/23: what the fuck was I talking about?
// TODO (Ineanto, 05/20/23): Check if cached before because Jedis returns a bulk reply so this is unsafe // old_todo (Ineanto, 05/20/23): Check if cached before because Jedis returns a bulk reply so this is unsafe
final String data = jedis.get("nicko:" + uuid.toString()); final String data = jedis.get("nicko:" + uuid.toString());
final NickoProfile profile = gson.fromJson(data, NickoProfile.class); final NickoProfile profile = gson.fromJson(data, NickoProfile.class);
return Optional.of(profile); return Optional.of(profile);

View file

@ -70,19 +70,4 @@ public abstract class AbstractPacket {
public void broadcastPacket() { public void broadcastPacket() {
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle()); ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle());
} }
/**
* Simulate receiving the current packet from the given sender.
*
* @param sender - the sender.
* @throws RuntimeException if the packet cannot be received.
*/
public void receivePacket(Player sender) {
try {
ProtocolLibrary.getProtocolManager().receiveClientPacket(sender,
getHandle());
} catch (Exception e) {
throw new RuntimeException("Cannot receive packet.", e);
}
}
} }

View file

@ -20,15 +20,6 @@ public class WrapperPlayServerEntityDestroy extends AbstractPacket {
handle.getModifier().writeDefaults(); handle.getModifier().writeDefaults();
} }
/**
* Gets a list of entity ids to remove
*
* @return 'entityIds' to remove
*/
public IntList getEntityIds() {
return this.handle.getModifier().withType(IntList.class, Converters.passthrough(IntList.class)).read(0);
}
/** /**
* Sets the list of entity ids to remove * Sets the list of entity ids to remove
* *

View file

@ -3,37 +3,21 @@ package xyz.ineanto.nicko.wrapper;
import com.comphenix.protocol.PacketType; import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.InternalStructure; import com.comphenix.protocol.events.InternalStructure;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.EnumWrappers; import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.MinecraftKey; import com.comphenix.protocol.wrappers.MinecraftKey;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import org.bukkit.Difficulty;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.World; import org.bukkit.World;
/** /**
* Up-to-date version of the Wrapper class * PacketPlayServerRespawn Wrapper class (1.19 to 1.20.2)
* for the PacketPlayServerRespawn.
* *
* @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland * @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland
* <p> * <p>
* <p>
* Packet changes history (not accurate)
* <p>
* In 1.20.2, all the fields were replaced with a * In 1.20.2, all the fields were replaced with a
* single "CommonPlayerSpawnInfo" record object. * single "CommonPlayerSpawnInfo" record object.
* <p>
* The dimension field was changed numerous times:
* - 1.8 through 1.17 (?) required an integer,
* - 1.18 need an instance of a Holder of a ResourceKey,
* - 1.19 and after dropped this requirement.
* N.b.: this field is a nightmare please mojang stop refactoring
* your code to change things that were working perfectly fine before
* <p>
* The Seed field was added in 1.15.
* The Difficulty field was removed in 1.14.
*/ */
public class WrapperPlayServerRespawn extends AbstractPacket { public class WrapperPlayServerRespawn extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.RESPAWN; public static final PacketType TYPE = PacketType.Play.Server.RESPAWN;
@ -51,28 +35,10 @@ public class WrapperPlayServerRespawn extends AbstractPacket {
public void setDimension(World value) { public void setDimension(World value) {
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) { if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
// 1.20.2 // 1.20.2
final InternalStructure dimensionType = commonPlayerSpawnInfoStructure.getStructures().read(0); writeDimensionToStructure(value, commonPlayerSpawnInfoStructure.getStructures(), commonPlayerSpawnInfoStructure.getWorldKeys());
dimensionType.getMinecraftKeys().writeSafely(0, new MinecraftKey("minecraft", "dimension_type"));
dimensionType.getMinecraftKeys().writeSafely(1, new MinecraftKey("minecraft", "overworld"));
commonPlayerSpawnInfoStructure.getStructures().writeSafely(0, dimensionType);
commonPlayerSpawnInfoStructure.getWorldKeys().writeSafely(0, value);
} else if (MinecraftVersion.WILD_UPDATE.atOrAbove()) { } else if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
// 1.19 to 1.20.1 // 1.19 to 1.20.1, props to lukalt for helping me figure this out.
// Thank you lukalt! writeDimensionToStructure(value, handle.getStructures(), handle.getWorldKeys());
final InternalStructure dimensionType = handle.getStructures().read(0);
dimensionType.getMinecraftKeys().writeSafely(0, new MinecraftKey("minecraft", "dimension_type"));
dimensionType.getMinecraftKeys().writeSafely(1, new MinecraftKey("minecraft", "overworld"));
handle.getStructures().writeSafely(0, dimensionType);
handle.getWorldKeys().writeSafely(0, value);
} else if (MinecraftVersion.CAVES_CLIFFS_2.atOrAbove()) {
// 1.18
handle.getHolders(
MinecraftReflection.getDimensionManager(),
BukkitConverters.getDimensionConverter()
).writeSafely(0, value);
} else {
// 1.17 and below (untested)
handle.getDimensions().writeSafely(0, value.getEnvironment().ordinal());
} }
} }
@ -81,7 +47,6 @@ public class WrapperPlayServerRespawn extends AbstractPacket {
commonPlayerSpawnInfoStructure.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value)); commonPlayerSpawnInfoStructure.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value));
return; return;
} }
handle.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value)); handle.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value));
} }
@ -103,14 +68,16 @@ public class WrapperPlayServerRespawn extends AbstractPacket {
} }
public void setSeed(long value) { public void setSeed(long value) {
if (MinecraftVersion.BEE_UPDATE.atOrAbove() && !MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) { if (MinecraftVersion.WILD_UPDATE.atOrAbove() && !MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
handle.getLongs().writeSafely(0, Hashing.sha256().hashLong(value).asLong()); handle.getLongs().writeSafely(0, Hashing.sha256().hashLong(value).asLong());
} }
} }
public void setDifficulty(Difficulty difficulty) { private void writeDimensionToStructure(World value, StructureModifier<InternalStructure> structures, StructureModifier<World> worldKeys) {
if (difficulty != null && !MinecraftVersion.VILLAGE_UPDATE.atOrAbove()) { final InternalStructure dimensionType = structures.read(0);
handle.getDifficulties().writeSafely(0, EnumWrappers.Difficulty.valueOf(difficulty.name())); dimensionType.getMinecraftKeys().writeSafely(0, new MinecraftKey("minecraft", "dimension_type"));
} dimensionType.getMinecraftKeys().writeSafely(1, new MinecraftKey("minecraft", "overworld"));
structures.writeSafely(0, dimensionType);
worldKeys.writeSafely(0, value);
} }
} }

View file

@ -35,8 +35,8 @@ public class ItemTranslationTest {
public void translateItemTranslationWithoutLore() { public void translateItemTranslationWithoutLore() {
final I18N i18n = new I18N(Locale.FRENCH); final I18N i18n = new I18N(Locale.FRENCH);
final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.GO_BACK); final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.GO_BACK);
assertTrue(translation.getLore().isEmpty()); assertTrue(translation.lore().isEmpty());
assertEquals(translation.getName(), "Retour"); assertEquals(translation.name(), "Retour");
} }
@Test @Test
@ -44,10 +44,10 @@ public class ItemTranslationTest {
public void translateItemLore() { public void translateItemLore() {
final I18N i18n = new I18N(Locale.FRENCH); final I18N i18n = new I18N(Locale.FRENCH);
final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.Admin.Cache.STATISTICS, "1", "1"); final ItemTranslation translation = i18n.fetchTranslation(I18NDict.GUI.Admin.Cache.STATISTICS, "1", "1");
assertFalse(translation.getLore().isEmpty()); assertFalse(translation.lore().isEmpty());
assertEquals("§fNombre de requêtes: §b1", translation.getLore().get(0)); assertEquals("§fNombre de requêtes: §b1", translation.lore().get(0));
assertEquals("§fNb. de skin dans le cache: §b1", translation.getLore().get(1)); assertEquals("§fNb. de skin dans le cache: §b1", translation.lore().get(1));
assertEquals("§8§oLe cache est vidé toutes les 24 heures.", translation.getLore().get(2)); assertEquals("§8§oLe cache est vidé toutes les 24 heures.", translation.lore().get(2));
} }
@AfterAll @AfterAll

View file

@ -1,7 +1,6 @@
package xyz.ineanto.nicko.test.i18n; package xyz.ineanto.nicko.test.i18n;
import be.seeseemelk.mockbukkit.MockBukkit; import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.entity.PlayerMock;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
@ -16,8 +15,6 @@ import xyz.ineanto.nicko.i18n.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class TranslationTest { public class TranslationTest {
private static PlayerMock player;
@BeforeAll @BeforeAll
public static void setup() { public static void setup() {
final Configuration config = new Configuration( final Configuration config = new Configuration(