diff --git a/build.gradle.kts b/build.gradle.kts index ca19101..868f042 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java") id("com.gradleup.shadow") version "8.3.2" - id("xyz.jpenilla.run-paper") version "2.3.0" + id("xyz.jpenilla.run-paper") version "2.3.1" id("io.papermc.paperweight.userdev") version "2.0.0-beta.10" } @@ -31,11 +31,11 @@ repositories { dependencies { paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT") - compileOnly("com.comphenix.protocol:ProtocolLib:5.4.0-SNAPSHOT") compileOnly("me.clip:placeholderapi:2.11.5") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("xyz.xenondevs.invui:invui-core:$invuiVersion") compileOnly("net.wesjd:anvilgui:1.10.4-SNAPSHOT") + compileOnly("com.comphenix.protocol:ProtocolLib:5.4.0-SNAPSHOT") implementation("de.rapha149.signgui:signgui:2.5.0") implementation("com.github.jsixface:yamlconfig:1.2") @@ -62,7 +62,7 @@ tasks { relocate("net.wesjd", "xyz.ineanto.nicko.libs.anvilgui") relocate("com.github.jsixface", "xyz.ineanto.nicko.libs.yaml") relocate("me.clip", "xyz.ineanto.nicko.libs.placeholderapi") - relocate("com.fasterxml.jackson", "xyz.ineanto.nicko.libs.jacksonpr") + relocate("com.fasterxml.jackson", "xyz.ineanto.nicko.libs.jackson") relocate("com.mysql", "xyz.ineanto.nicko.libs.mysql") relocate("org.mariadb.jdbc", "xyz.ineanto.nicko.libs.mariadb") relocate("redis.clients", "xyz.ineanto.nicko.libs.redis") @@ -95,10 +95,10 @@ tasks { runServer { downloadPlugins { - url("https://download.luckperms.net/1568/bukkit/loader/LuckPerms-Bukkit-5.4.151.jar") + url("https://download.luckperms.net/1575/bukkit/loader/LuckPerms-Bukkit-5.4.158.jar") // 1.20.5 - latest testing - url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar") + //url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar") } minecraftVersion("1.21.4") diff --git a/img/LOGO.png b/img/LOGO.png deleted file mode 100644 index 7472229..0000000 Binary files a/img/LOGO.png and /dev/null differ diff --git a/src/main/java/xyz/ineanto/nicko/appearance/AppearanceManager.java b/src/main/java/xyz/ineanto/nicko/appearance/AppearanceManager.java index ecc22ff..23bd447 100644 --- a/src/main/java/xyz/ineanto/nicko/appearance/AppearanceManager.java +++ b/src/main/java/xyz/ineanto/nicko/appearance/AppearanceManager.java @@ -6,7 +6,7 @@ import org.bukkit.event.player.PlayerTeleportEvent; import xyz.ineanto.nicko.Nicko; import xyz.ineanto.nicko.event.custom.PlayerDisguiseEvent; import xyz.ineanto.nicko.event.custom.PlayerResetDisguiseEvent; -import xyz.ineanto.nicko.packet.InternalPacketSender; +import xyz.ineanto.nicko.packet.PaperPacketSender; import xyz.ineanto.nicko.packet.PacketSender; import xyz.ineanto.nicko.profile.NickoProfile; import xyz.ineanto.nicko.storage.PlayerDataStore; @@ -24,7 +24,7 @@ public class AppearanceManager { public AppearanceManager(Player player) { this.player = player; - this.packetSender = new InternalPacketSender(player, getNickoProfile()); + this.packetSender = new PaperPacketSender(player, getNickoProfile()); } public ActionResult reset() { @@ -51,10 +51,14 @@ public class AppearanceManager { final NickoProfile profile = getNickoProfile(); final String displayName = profile.getName() == null ? player.getName() : profile.getName(); - final ActionResult result = packetSender.sendGameProfileUpdate(displayName, skinChange, reset); + final ActionResult result = packetSender.updatePlayerProfile(displayName); - if (result.isError()) { - return reset(); + if (skinChange) { + final ActionResult propertiesUpdateResult = packetSender.updatePlayerProfileProperties(); + + if (propertiesUpdateResult.isError()) { + return reset(); + } } // Call the event. @@ -63,8 +67,8 @@ public class AppearanceManager { packetSender.sendEntityMetadataUpdate(); packetSender.sendTabListUpdate(displayName); - respawnPlayer(); - packetSender.sendEntityRespawn(); + //respawnPlayer(); + //packetSender.sendEntityRespawn(); return result; } diff --git a/src/main/java/xyz/ineanto/nicko/gui/prompt/SignPrompt.java b/src/main/java/xyz/ineanto/nicko/gui/prompt/SignPrompt.java index 3f16d9a..f31fbb8 100644 --- a/src/main/java/xyz/ineanto/nicko/gui/prompt/SignPrompt.java +++ b/src/main/java/xyz/ineanto/nicko/gui/prompt/SignPrompt.java @@ -8,6 +8,7 @@ import org.bukkit.entity.Player; import xyz.ineanto.nicko.language.LanguageKey; import xyz.ineanto.nicko.language.PlayerLanguage; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -16,12 +17,13 @@ import java.util.concurrent.atomic.AtomicReference; public class SignPrompt implements Prompt { private final Player player; private final PlayerLanguage playerLanguage; - - private List lines = List.of( - "VVVVVVVVVVVVVVV", - null, - null, - "ΛΛΛΛΛΛΛΛΛΛΛΛΛΛΛ" + private final ArrayList lines = new ArrayList<>( + List.of( + "VVVVVVVVVVVVVVV", + "", + "", + "ΛΛΛΛΛΛΛΛΛΛΛΛΛΛΛ" + ) ); private final AtomicReference> name = new AtomicReference<>(); @@ -73,6 +75,7 @@ public class SignPrompt implements Prompt { try { final SignGUI gui = SignGUI.builder() .setLines(lines.toArray(new String[0])) + .setLine(2, null) .setType(Material.OAK_SIGN) .setHandler((_, result) -> { final String internalLine2 = result.getLineWithoutColor(2); @@ -89,6 +92,7 @@ public class SignPrompt implements Prompt { gui.open(player); return reference.get(); } catch (SignGUIVersionException exception) { + exception.printStackTrace(); return Optional.empty(); } } diff --git a/src/main/java/xyz/ineanto/nicko/language/Language.java b/src/main/java/xyz/ineanto/nicko/language/Language.java index 049039c..d916301 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, 2, 0); + public static final Version VERSION = new Version(1, 3, 0); private final String code; private transient final String name; diff --git a/src/main/java/xyz/ineanto/nicko/language/LanguageKey.java b/src/main/java/xyz/ineanto/nicko/language/LanguageKey.java index 0dea8af..7e8fb29 100644 --- a/src/main/java/xyz/ineanto/nicko/language/LanguageKey.java +++ b/src/main/java/xyz/ineanto/nicko/language/LanguageKey.java @@ -10,8 +10,7 @@ public class LanguageKey { public static final String PERMISSION = ERROR_KEY + "permission"; public static final String CACHE = ERROR_KEY + "cache"; - 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 = ERROR_KEY + "mojang"; } public static class Event { diff --git a/src/main/java/xyz/ineanto/nicko/loader/NickoPluginLoader.java b/src/main/java/xyz/ineanto/nicko/loader/NickoPluginLoader.java index eaac594..096e9c7 100644 --- a/src/main/java/xyz/ineanto/nicko/loader/NickoPluginLoader.java +++ b/src/main/java/xyz/ineanto/nicko/loader/NickoPluginLoader.java @@ -3,8 +3,8 @@ package xyz.ineanto.nicko.loader; import io.papermc.paper.plugin.loader.PluginClasspathBuilder; import io.papermc.paper.plugin.loader.PluginLoader; import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver; -import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.repository.RemoteRepository; public class NickoPluginLoader implements PluginLoader { @@ -15,7 +15,6 @@ public class NickoPluginLoader implements PluginLoader { resolver.addRepository(new RemoteRepository.Builder("xenondevs", "default", "https://repo.xenondevs.xyz/releases/").build()); resolver.addRepository(new RemoteRepository.Builder("codemc", "default", "https://repo.codemc.io/repository/maven-snapshots/").build()); resolver.addDependency(new Dependency(new DefaultArtifact("xyz.xenondevs.invui:invui:pom:1.44"), null)); - //resolver.addDependency(new Dependency(new DefaultArtifact("net.wesjd:anvilgui:1.10.4-SNAPSHOT"), null)); pluginClasspathBuilder.addLibrary(resolver); } diff --git a/src/main/java/xyz/ineanto/nicko/mojang/MojangSkin.java b/src/main/java/xyz/ineanto/nicko/mojang/MojangSkin.java index 3e50105..0b22223 100644 --- a/src/main/java/xyz/ineanto/nicko/mojang/MojangSkin.java +++ b/src/main/java/xyz/ineanto/nicko/mojang/MojangSkin.java @@ -1,7 +1,11 @@ package xyz.ineanto.nicko.mojang; +import com.destroystokyo.paper.profile.ProfileProperty; import com.google.gson.JsonObject; +import java.util.Collection; +import java.util.Collections; + public record MojangSkin(String value, String signature) { public static MojangSkin buildFromJson(JsonObject object) { final JsonObject properties = object.get("properties").getAsJsonArray().get(0).getAsJsonObject(); @@ -9,4 +13,8 @@ public record MojangSkin(String value, String signature) { final String signature = properties.get("signature").getAsString(); return new MojangSkin(value, signature); } + + public Collection asProfileProperties() { + return Collections.singleton(new ProfileProperty("textures", value, signature)); + } } diff --git a/src/main/java/xyz/ineanto/nicko/packet/PacketSender.java b/src/main/java/xyz/ineanto/nicko/packet/PacketSender.java index ef93153..28bb695 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/PacketSender.java +++ b/src/main/java/xyz/ineanto/nicko/packet/PacketSender.java @@ -5,7 +5,9 @@ import xyz.ineanto.nicko.appearance.ActionResult; public interface PacketSender { void sendEntityRespawn(); - ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset); + ActionResult updatePlayerProfile(String name); + + ActionResult updatePlayerProfileProperties(); void sendEntityMetadataUpdate(); diff --git a/src/main/java/xyz/ineanto/nicko/packet/InternalPacketSender.java b/src/main/java/xyz/ineanto/nicko/packet/PaperPacketSender.java similarity index 72% rename from src/main/java/xyz/ineanto/nicko/packet/InternalPacketSender.java rename to src/main/java/xyz/ineanto/nicko/packet/PaperPacketSender.java index d1796cb..ded8f5e 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/InternalPacketSender.java +++ b/src/main/java/xyz/ineanto/nicko/packet/PaperPacketSender.java @@ -1,8 +1,7 @@ package xyz.ineanto.nicko.packet; -import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import com.mojang.authlib.properties.PropertyMap; +import com.destroystokyo.paper.profile.CraftPlayerProfile; +import com.destroystokyo.paper.profile.PlayerProfile; import it.unimi.dsi.fastutil.ints.IntList; import net.minecraft.Optionull; import net.minecraft.network.chat.MutableComponent; @@ -39,11 +38,11 @@ import java.util.concurrent.ExecutionException; * I want you to really stare at this code. * You made me do this. */ -public class InternalPacketSender implements PacketSender { +public class PaperPacketSender implements PacketSender { private final Player player; private final NickoProfile profile; - public InternalPacketSender(Player player, NickoProfile profile) { + public PaperPacketSender(Player player, NickoProfile profile) { this.player = player; this.profile = profile; } @@ -74,41 +73,40 @@ public class InternalPacketSender implements PacketSender { } @Override - public ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset) { - final GameProfile gameProfile = new GameProfile(player.getUniqueId(), name); - - // TODO (Ineanto, 31/10/2024): Could this be refactored to get rid of the boolean? - if (skinChange) { - Optional skin; - try { - final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI(); - final Optional uuid = mojangAPI.getUUID(profile.getSkin()); - if (uuid.isPresent()) { - skin = reset ? mojangAPI.getSkinWithoutCaching(uuid.get()) : mojangAPI.getSkin(uuid.get()); - if (skin.isPresent()) { - final MojangSkin skinResult = skin.get(); - final PropertyMap properties = gameProfile.getProperties(); - properties.get("textures").clear(); - properties.put("textures", new Property("textures", skinResult.value(), skinResult.signature())); - ((CraftPlayer) player).getHandle().gameProfile = gameProfile; - } else { - return ActionResult.error(LanguageKey.Error.MOJANG_SKIN); - } - } else { - return ActionResult.error(LanguageKey.Error.MOJANG_NAME); - } - return ActionResult.ok(); - } catch (ExecutionException e) { - return ActionResult.error(LanguageKey.Error.CACHE); - } catch (IOException e) { - return ActionResult.error(LanguageKey.Error.MOJANG_NAME); - } catch (InterruptedException e) { - return ActionResult.error("Unknown error"); - } - } + public ActionResult updatePlayerProfile(String name) { + final PlayerProfile playerProfile = new CraftPlayerProfile(player.getUniqueId(), name); + // Copy previous properties to preserve skin + playerProfile.setProperties(playerProfile.getProperties()); + player.setPlayerProfile(playerProfile); return ActionResult.ok(); } + @Override + public ActionResult updatePlayerProfileProperties() { + final PlayerProfile playerProfile = new CraftPlayerProfile(player.getUniqueId(), profile.getName() == null ? player.getName() : profile.getName()); + + try { + final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI(); + + final Optional uuid = mojangAPI.getUUID(profile.getSkin()); + if (uuid.isEmpty()) { + return ActionResult.error(LanguageKey.Error.MOJANG); + } + + final Optional skin = mojangAPI.getSkin(uuid.get()); + if (skin.isEmpty()) { + return ActionResult.error(LanguageKey.Error.MOJANG); + } + + final MojangSkin skinResult = skin.get(); + playerProfile.setProperties(skinResult.asProfileProperties()); + player.setPlayerProfile(playerProfile); + return ActionResult.ok(); + } catch (ExecutionException | IOException e) { + return ActionResult.error(LanguageKey.Error.CACHE); + } + } + @Override public void sendEntityMetadataUpdate() { final SynchedEntityData.DataValue dataValueComponent = diff --git a/src/main/java/xyz/ineanto/nicko/packet/WrapperPacketSender.java b/src/main/java/xyz/ineanto/nicko/packet/WrapperPacketSender.java deleted file mode 100644 index fc2b140..0000000 --- a/src/main/java/xyz/ineanto/nicko/packet/WrapperPacketSender.java +++ /dev/null @@ -1,139 +0,0 @@ -package xyz.ineanto.nicko.packet; - -import com.comphenix.protocol.wrappers.*; -import com.google.common.collect.Multimap; -import it.unimi.dsi.fastutil.ints.IntList; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.entity.Player; -import xyz.ineanto.nicko.Nicko; -import xyz.ineanto.nicko.appearance.ActionResult; -import xyz.ineanto.nicko.language.LanguageKey; -import xyz.ineanto.nicko.mojang.MojangAPI; -import xyz.ineanto.nicko.mojang.MojangSkin; -import xyz.ineanto.nicko.packet.wrapper.*; -import xyz.ineanto.nicko.profile.NickoProfile; - -import java.io.IOException; -import java.util.EnumSet; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.ExecutionException; - -public class WrapperPacketSender implements PacketSender { - private final Player player; - private final NickoProfile profile; - - private WrappedGameProfile gameProfile; - - public WrapperPacketSender(Player player, NickoProfile profile) { - this.player = player; - this.profile = profile; - } - - @Override - public void sendEntityRespawn() { - if (!profile.hasData()) return; - - final WrapperPlayServerEntityDestroy destroy = new WrapperPlayServerEntityDestroy(); - final WrapperPlayServerSpawnEntity spawn = new WrapperPlayServerSpawnEntity(); - destroy.setEntityIds(IntList.of(player.getEntityId())); - spawn.setEntityId(player.getEntityId()); - spawn.setLocation(player.getLocation()); - spawn.setPlayerId(player.getUniqueId()); - Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> { - destroy.sendPacket(receiver); - spawn.sendPacket(receiver); - }); - } - - @Override - public ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset) { - this.gameProfile = WrappedGameProfile.fromPlayer(player).withName(name); - - // TODO (Ineanto, 31/10/2024): Could get refactored to omit this boolean? - if (skinChange) { - Optional skin; - try { - final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI(); - final Optional uuid = mojangAPI.getUUID(profile.getSkin()); - if (uuid.isPresent()) { - skin = reset ? mojangAPI.getSkinWithoutCaching(uuid.get()) : mojangAPI.getSkin(uuid.get()); - if (skin.isPresent()) { - final MojangSkin skinResult = skin.get(); - final Multimap properties = gameProfile.getProperties(); - properties.get("textures").clear(); - properties.put("textures", new WrappedSignedProperty("textures", skinResult.value(), skinResult.signature())); - } else { - return ActionResult.error(LanguageKey.Error.MOJANG_SKIN); - } - } else { - return ActionResult.error(LanguageKey.Error.MOJANG_NAME); - } - return ActionResult.ok(); - } catch (ExecutionException e) { - return ActionResult.error(LanguageKey.Error.CACHE); - } catch (IOException e) { - return ActionResult.error(LanguageKey.Error.MOJANG_NAME); - } catch (InterruptedException e) { - return ActionResult.error("Unknown error"); - } - } - return ActionResult.ok(); - } - - - @Override - public void sendEntityMetadataUpdate() { - final WrappedDataWatcher entityWatcher = WrappedDataWatcher.getEntityWatcher(player); - entityWatcher.setObject(17, (byte) 0x7f, true); - } - - @Override - public void sendPlayerRespawn() { - final World world = player.getWorld(); - - final WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn(); - respawn.setDimension(world); - respawn.setSeed(world.getSeed()); - respawn.setGameMode(player.getGameMode()); - respawn.setPreviousGameMode(player.getGameMode()); - respawn.setCopyMetadata(true); - respawn.sendPacket(player); - } - - @Override - public void sendTabListUpdate(String displayName) { - if (gameProfile == null) { - Nicko.getInstance().getLogger().warning("Hello. I sincerely hope you're doing great out there."); - Nicko.getInstance().getLogger().warning("If you see this message, I've failed at my task and I'm a terrible programmer."); - Nicko.getInstance().getLogger().warning("Report this issue on https://git.ineanto.xyz/ineanto/nicko, thank you!"); - return; - } - - final WrapperPlayerServerPlayerInfo add = new WrapperPlayerServerPlayerInfo(); - final WrapperPlayerServerPlayerInfoRemove remove = new WrapperPlayerServerPlayerInfoRemove(); - final EnumSet actions = EnumSet.of( - EnumWrappers.PlayerInfoAction.ADD_PLAYER, - EnumWrappers.PlayerInfoAction.INITIALIZE_CHAT, - EnumWrappers.PlayerInfoAction.UPDATE_LISTED, - EnumWrappers.PlayerInfoAction.UPDATE_DISPLAY_NAME, - EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE, - EnumWrappers.PlayerInfoAction.UPDATE_LATENCY); - remove.setUUIDs(List.of(player.getUniqueId())); - remove.broadcastPacket(); - add.setActions(actions); - - add.setData(List.of(new PlayerInfoData( - player.getUniqueId(), - player.getPing(), - true, - EnumWrappers.NativeGameMode.fromBukkit(player.getGameMode()), - gameProfile, - WrappedChatComponent.fromText(displayName), - WrappedRemoteChatSessionData.fromPlayer(player) - ))); - - add.broadcastPacket(); - } -} diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml index 887ebce..888ff59 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.2.0" +version: "1.3.0" prefix: "NICKO" whoosh: "WHOOSH!" @@ -10,8 +10,7 @@ oops: "OOPS!" error: permission: "You're missing the permission to do that." invalid_username: "This is an invalid Minecraft username." - mojang_name: "There's is not Minecraft account with this username." - mojang_skin: "This Minecraft account has no skin." + mojang: "Something went wrong while fetching data from Mojang." cache: "Unable to get data from the cache." event: diff --git a/src/main/resources/fr.yml b/src/main/resources/fr.yml index eb92b7b..68df92e 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.2.0" +version: "1.3.0" prefix: "NICKO" whoosh: "WHOOSH!" @@ -10,8 +10,7 @@ oops: "OOPS!" error: permission: "Vous n'avez pas la permission de faire cela." invalid_username: "Nom d'utilisateur Minecraft invalide." - mojang_name: "Aucun compte Minecraft associé à ce nom d'utilisateur." - mojang_skin: "Ce compte Minecraft n'a pas de skin." + mojang: "Une erreur est surevenue en récupérant les information depuis Mojang." cache: "Impossible de récupérer les données depuis le cache." event: diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml index 048a12e..f515c80 100644 --- a/src/main/resources/paper-plugin.yml +++ b/src/main/resources/paper-plugin.yml @@ -9,10 +9,11 @@ softdepend: [ PlaceholderAPI ] depend: - ProtocolLib -# Suppose we require ProtocolLib to be loaded for our plugin -AnvilGUI: - join-classpath: true - required: true +dependencies: + server: + ProtocolLib: + load: BEFORE + join-classpath: true permissions: nicko.*: