diff --git a/.gitignore b/.gitignore index a43a0f4..8a238de 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,7 @@ out/ .sts4-cache bin/ !**/src/main/**/bin/ -!**/src/test/**/bin/ \ No newline at end of file +!**/src/test/**/bin/ + +### Server ### +run/ \ No newline at end of file diff --git a/CHANGELOG.log b/CHANGELOG.log index a192561..9a1c2a5 100644 --- a/CHANGELOG.log +++ b/CHANGELOG.log @@ -1,6 +1,7 @@ 1.0.8-RC1: Update n°5 (XX/XX/XX) [FEATURES] - Persistence and cache will now fallback to local alternatives when unreachable. + - Developers can now listen to the PlayerDisguiseEvent and cancel the disguise process. [OTHER] - Various optimizations and improvements. diff --git a/build.gradle.kts b/build.gradle.kts index 28f462b..2fda361 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,7 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - plugins { - id("io.github.goooler.shadow") version "8.1.2" id("java") + id("io.github.goooler.shadow") version "8.1.2" + id("xyz.jpenilla.run-paper") version "2.2.2" } group = "xyz.ineanto" @@ -67,16 +66,16 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") } -tasks.processResources { - from("src/main/resources") - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - filesMatching("plugin.yml") { - expand("version" to version) - } -} - tasks { - named("shadowJar") { + processResources { + from("src/main/resources") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + filesMatching("plugin.yml") { + expand("version" to version) + } + } + + shadowJar { mustRunAfter(test) configurations = listOf(shadowImplementation) @@ -122,6 +121,17 @@ tasks { exclude(dependency("net.wesjd:.*")) } } + + runServer { + downloadPlugins { + url("https://download.luckperms.net/1526/bukkit/loader/LuckPerms-Bukkit-5.4.113.jar") + url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar") + } + // Configure the Minecraft version for our task. + // This is the only required configuration besides applying the plugin. + // Your plugin's jar (or shadowJar if present) will be used automatically. + minecraftVersion("1.20.2") + } } tasks.named("jar").configure { diff --git a/src/main/java/xyz/ineanto/nicko/NickoBukkit.java b/src/main/java/xyz/ineanto/nicko/NickoBukkit.java index 8fc665f..94507d5 100644 --- a/src/main/java/xyz/ineanto/nicko/NickoBukkit.java +++ b/src/main/java/xyz/ineanto/nicko/NickoBukkit.java @@ -36,6 +36,7 @@ public class NickoBukkit extends JavaPlugin { private Configuration configuration; private LocaleFileManager localeFileManager; private PlayerNameStore nameStore; + private Metrics metrics; public NickoBukkit() { this.unitTesting = false; @@ -120,7 +121,7 @@ public class NickoBukkit extends JavaPlugin { getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this); getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this); - new Metrics(this, 20483); + metrics = new Metrics(this, 20483); } getLogger().info("Nicko has been enabled."); @@ -138,6 +139,7 @@ public class NickoBukkit extends JavaPlugin { } } + if(!unitTesting) metrics.shutdown(); getLogger().info("Nicko (Bukkit) has been disabled."); } diff --git a/src/main/java/xyz/ineanto/nicko/anvil/AnvilManager.java b/src/main/java/xyz/ineanto/nicko/anvil/AnvilManager.java index 0ce0449..4dd47ce 100644 --- a/src/main/java/xyz/ineanto/nicko/anvil/AnvilManager.java +++ b/src/main/java/xyz/ineanto/nicko/anvil/AnvilManager.java @@ -2,6 +2,7 @@ package xyz.ineanto.nicko.anvil; import net.kyori.adventure.text.Component; import net.wesjd.anvilgui.AnvilGUI; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -9,6 +10,7 @@ import org.bukkit.inventory.meta.ItemMeta; import xyz.ineanto.nicko.NickoBukkit; import xyz.ineanto.nicko.appearance.ActionResult; import xyz.ineanto.nicko.appearance.AppearanceManager; +import xyz.ineanto.nicko.event.custom.PlayerDisguiseEvent; import xyz.ineanto.nicko.i18n.I18N; import xyz.ineanto.nicko.i18n.I18NDict; import xyz.ineanto.nicko.mojang.MojangUtils; @@ -77,8 +79,7 @@ public class AnvilManager { } else { profile.setName(snapshot.getText()); dataStore.updateCache(player.getUniqueId(), profile); - final ActionResult actionResult = appearanceManager.updatePlayer(false, false); - return sendResultAndClose(actionResult); + return sendResultAndClose(false); } } return Collections.emptyList(); @@ -98,8 +99,7 @@ public class AnvilManager { } else { profile.setSkin(snapshot.getText()); dataStore.updateCache(player.getUniqueId(), profile); - final ActionResult actionResult = appearanceManager.updatePlayer(true, false); - return sendResultAndClose(actionResult); + return sendResultAndClose(true); } } return Collections.emptyList(); @@ -107,8 +107,13 @@ public class AnvilManager { .text("New skin..."); } - private List sendResultAndClose(ActionResult actionResult) { + private List sendResultAndClose(boolean skinChange) { + final PlayerDisguiseEvent event = new PlayerDisguiseEvent(player, profile.getSkin(), player.getName()); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { return Collections.singletonList(AnvilGUI.ResponseAction.close()); } + final I18N i18n = new I18N(player); + final ActionResult actionResult = appearanceManager.updatePlayer(skinChange, false); if (!actionResult.isError()) { player.sendMessage(i18n.translate(I18NDict.Event.Appearance.Set.OK)); } else { @@ -120,7 +125,7 @@ public class AnvilManager { private ItemStack getLeftItem(boolean skin) { final ItemStack item = new ItemStack(Material.PAPER); final ItemMeta meta = item.getItemMeta(); - if (meta != null) meta.displayName(Component.text("§0New " + (skin ? "skin" : "name") + "...")); + if (meta != null) meta.displayName(Component.text("New " + (skin ? "skin" : "name") + "...")); item.setItemMeta(meta); return item; } diff --git a/src/main/java/xyz/ineanto/nicko/event/PlayerJoinListener.java b/src/main/java/xyz/ineanto/nicko/event/PlayerJoinListener.java index 133ee1b..31a7d6b 100644 --- a/src/main/java/xyz/ineanto/nicko/event/PlayerJoinListener.java +++ b/src/main/java/xyz/ineanto/nicko/event/PlayerJoinListener.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Optional; import java.util.UUID; import java.util.logging.Logger; -import java.util.stream.Collectors; public class PlayerJoinListener implements Listener { private final Logger logger = Logger.getLogger("PlayerJoinListener"); @@ -53,7 +52,7 @@ public class PlayerJoinListener implements Listener { } }); - 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()).toList()) { final Optional optionalOnlinePlayerProfile = dataStore.getData(online.getUniqueId()); optionalOnlinePlayerProfile.ifPresent(profile -> { diff --git a/src/main/java/xyz/ineanto/nicko/event/custom/PlayerDisguiseEvent.java b/src/main/java/xyz/ineanto/nicko/event/custom/PlayerDisguiseEvent.java new file mode 100644 index 0000000..e7c3776 --- /dev/null +++ b/src/main/java/xyz/ineanto/nicko/event/custom/PlayerDisguiseEvent.java @@ -0,0 +1,47 @@ +package xyz.ineanto.nicko.event.custom; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class PlayerDisguiseEvent extends Event implements Cancellable { + private static final HandlerList HANDLERS_LIST = new HandlerList(); + private boolean isCancelled; + private final Player player; + private final String skin, name; + + public PlayerDisguiseEvent(Player player, String skin, String name) { + this.player = player; + this.skin = skin; + this.name = name; + } + + @Override + public boolean isCancelled() { + return isCancelled; + } + + @Override + public void setCancelled(boolean isCancelled) { + this.isCancelled = isCancelled; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLERS_LIST; + } + + public Player getPlayer() { + return player; + } + + public String getSkin() { + return skin; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/xyz/ineanto/nicko/i18n/I18N.java b/src/main/java/xyz/ineanto/nicko/i18n/I18N.java index bce6c32..9f512a4 100644 --- a/src/main/java/xyz/ineanto/nicko/i18n/I18N.java +++ b/src/main/java/xyz/ineanto/nicko/i18n/I18N.java @@ -50,7 +50,7 @@ public class I18N { final ArrayList lore = readList(loreKey); if (name == null) { - logger.warning(nameKey + " doesn't exists! Please translate this entry."); + logger.warning(nameKey + " doesn't exists! Is your language file outdated?"); return new ItemTranslation(nameKey, new ArrayList<>() {{ add(loreKey); }}); diff --git a/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCache.java b/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCache.java index 77fe270..a3c0525 100644 --- a/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCache.java +++ b/src/main/java/xyz/ineanto/nicko/storage/redis/RedisCache.java @@ -3,8 +3,10 @@ package xyz.ineanto.nicko.storage.redis; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import redis.clients.jedis.Jedis; +import redis.clients.jedis.exceptions.JedisException; import xyz.ineanto.nicko.appearance.ActionResult; import xyz.ineanto.nicko.config.Configuration; +import xyz.ineanto.nicko.i18n.I18NDict; import xyz.ineanto.nicko.profile.NickoProfile; import xyz.ineanto.nicko.storage.Cache; import xyz.ineanto.nicko.storage.CacheProvider; @@ -37,6 +39,8 @@ public class RedisCache extends Cache { try (Jedis jedis = provider.getJedis()) { jedis.set("nicko:" + uuid.toString(), gson.toJson(profile)); return ActionResult.ok(); + } catch (JedisException exception) { + return ActionResult.error(I18NDict.Error.CACHE); } } @@ -44,6 +48,8 @@ public class RedisCache extends Cache { public boolean isCached(UUID uuid) { try (Jedis jedis = provider.getJedis()) { return jedis.exists("nicko:" + uuid.toString()); + } catch (JedisException exception) { + return false; } } @@ -55,6 +61,8 @@ public class RedisCache extends Cache { final String data = jedis.get("nicko:" + uuid.toString()); final NickoProfile profile = gson.fromJson(data, NickoProfile.class); return Optional.of(profile); + } catch (JedisException exception) { + return Optional.empty(); } } @@ -63,6 +71,8 @@ public class RedisCache extends Cache { try (Jedis jedis = provider.getJedis()) { jedis.del("nicko:" + uuid.toString()); return ActionResult.ok(); + } catch (JedisException exception) { + return ActionResult.error(I18NDict.Error.CACHE); } } } diff --git a/src/main/java/xyz/ineanto/nicko/version/Version.java b/src/main/java/xyz/ineanto/nicko/version/Version.java new file mode 100644 index 0000000..fe660cf --- /dev/null +++ b/src/main/java/xyz/ineanto/nicko/version/Version.java @@ -0,0 +1,16 @@ +package xyz.ineanto.nicko.version; + +import org.jetbrains.annotations.NotNull; + +import java.util.Comparator; + +public record Version(int major, int minor, int patch) implements Comparable { + @Override + public int compareTo(@NotNull Version otherVersion) { + final Comparator comparator = Comparator + .comparingInt(Version::major) + .thenComparingInt(Version::minor) + .thenComparingInt(Version::patch); + return comparator.compare(this, otherVersion); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 9b854cd..ce98b0f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,9 @@ # Nicko ${project.version} - Config: +# Don't modify this. +# No, like... really. +version: "1.0.8" + ############ # LANGUAGE # ############ @@ -49,7 +53,7 @@ redis: # Accepted values: false (Disabled), true (Enabled) enabled: false # Redis server's address - # Accepted values: valid IP address (e.g. localhost, 127.0.0.1) + # Accepted values: valid IP address (e.g.: localhost, 127.0.0.1) address: "localhost" # Redis server's port # Accepted values: valid integer (e.g. 3306, 25565) diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml index 84e6d82..6216055 100644 --- a/src/main/resources/en.yml +++ b/src/main/resources/en.yml @@ -1,3 +1,5 @@ +version: "1.0.8" + error: generic: "An unknown error occurred." permission: "§cYou do not have the required permission." diff --git a/src/main/resources/fr.yml b/src/main/resources/fr.yml index 02783c6..79e70a2 100644 --- a/src/main/resources/fr.yml +++ b/src/main/resources/fr.yml @@ -1,3 +1,5 @@ +version: "1.0.8" + error: generic: "Une erreur inconnue c'est produite." permission: "§cVous ne possédez pas la permission."