diff --git a/build.gradle.kts b/build.gradle.kts index 8a6d329..0823cc1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,6 @@ 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 "1.7.4" } group = "xyz.ineanto" @@ -39,13 +38,12 @@ repositories { } dependencies { - paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT") - - compileOnly("com.github.dmulloy2:ProtocolLib:5.3.0") + compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT") + compileOnly("com.github.dmulloy2:ProtocolLib:-SNAPSHOT") compileOnly("me.clip:placeholderapi:2.11.5") compileOnly("net.kyori:adventure-api:4.17.0") - implementation("xyz.xenondevs.invui:invui:1.39") + implementation("xyz.xenondevs.invui:invui:1.36") implementation("net.wesjd:anvilgui:1.10.2-SNAPSHOT") implementation("com.github.jsixface:yamlconfig:1.2") implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2") @@ -56,7 +54,7 @@ dependencies { implementation("com.google.code.gson:gson:2.10.1") implementation("org.bstats:bstats-bukkit:3.0.2") - testImplementation("com.github.MockBukkit:MockBukkit:v3.133.2") + testImplementation("com.github.MockBukkit:MockBukkit:v3.99.1") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.2") testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.2") testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") diff --git a/src/main/java/xyz/ineanto/nicko/Nicko.java b/src/main/java/xyz/ineanto/nicko/Nicko.java index a0621bb..40c6fb5 100644 --- a/src/main/java/xyz/ineanto/nicko/Nicko.java +++ b/src/main/java/xyz/ineanto/nicko/Nicko.java @@ -1,5 +1,6 @@ package xyz.ineanto.nicko; +import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.utility.MinecraftVersion; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; @@ -10,6 +11,7 @@ import xyz.ineanto.nicko.appearance.random.RandomNameFetcher; import xyz.ineanto.nicko.command.NickoCommand; import xyz.ineanto.nicko.config.Configuration; import xyz.ineanto.nicko.config.ConfigurationManager; +import xyz.ineanto.nicko.debug.RespawnPacketListener; import xyz.ineanto.nicko.event.PlayerJoinListener; import xyz.ineanto.nicko.event.PlayerQuitListener; import xyz.ineanto.nicko.language.CustomLanguage; @@ -132,6 +134,8 @@ public class Nicko extends JavaPlugin { getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this); getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this); metrics = new Metrics(this, 20483); + + ProtocolLibrary.getProtocolManager().addPacketListener(new RespawnPacketListener()); } getLogger().info("Nicko has been enabled."); diff --git a/src/main/java/xyz/ineanto/nicko/anvil/AnvilManager.java b/src/main/java/xyz/ineanto/nicko/anvil/AnvilManager.java index db7a7cd..38c7f73 100644 --- a/src/main/java/xyz/ineanto/nicko/anvil/AnvilManager.java +++ b/src/main/java/xyz/ineanto/nicko/anvil/AnvilManager.java @@ -114,7 +114,7 @@ public class AnvilManager { Bukkit.getPluginManager().callEvent(event); if (event.isCancelled()) { return Collections.singletonList(AnvilGUI.ResponseAction.close()); } - final ActionResult actionResult = appearanceManager.update(skinChange, false); + final ActionResult actionResult = appearanceManager.updatePlayer(skinChange, false); if (!actionResult.isError()) { player.sendMessage(playerLanguage.translate(LanguageKey.Event.Appearance.Set.OK, true)); } else { diff --git a/src/main/java/xyz/ineanto/nicko/appearance/AppearanceManager.java b/src/main/java/xyz/ineanto/nicko/appearance/AppearanceManager.java index fba9286..94ca38f 100644 --- a/src/main/java/xyz/ineanto/nicko/appearance/AppearanceManager.java +++ b/src/main/java/xyz/ineanto/nicko/appearance/AppearanceManager.java @@ -1,27 +1,36 @@ package xyz.ineanto.nicko.appearance; +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 org.bukkit.event.player.PlayerTeleportEvent; import xyz.ineanto.nicko.Nicko; -import xyz.ineanto.nicko.packet.InternalPacketSender; -import xyz.ineanto.nicko.packet.PacketSender; +import xyz.ineanto.nicko.language.LanguageKey; +import xyz.ineanto.nicko.mojang.MojangAPI; +import xyz.ineanto.nicko.mojang.MojangSkin; import xyz.ineanto.nicko.profile.NickoProfile; import xyz.ineanto.nicko.storage.PlayerDataStore; import xyz.ineanto.nicko.storage.name.PlayerNameStore; +import xyz.ineanto.nicko.wrapper.*; +import java.io.IOException; +import java.util.EnumSet; +import java.util.List; import java.util.Optional; +import java.util.concurrent.ExecutionException; public class AppearanceManager { private final Nicko instance = Nicko.getInstance(); private final PlayerDataStore dataStore = instance.getDataStore(); private final PlayerNameStore nameStore = instance.getNameStore(); - private final PacketSender packetSender; private final Player player; public AppearanceManager(Player player) { this.player = player; - this.packetSender = new InternalPacketSender(player, getNickoProfile()); } public ActionResult reset() { @@ -31,7 +40,7 @@ public class AppearanceManager { profile.setSkin(defaultName); dataStore.getCache().cache(player.getUniqueId(), profile); - final ActionResult result = update(true, true); + final ActionResult result = updatePlayer(true, true); if (!result.isError()) { profile.setName(null); profile.setSkin(null); @@ -40,29 +49,108 @@ public class AppearanceManager { return result; } - public ActionResult update(boolean skinChange, boolean reset) { + public ActionResult updatePlayer(boolean skinChange, boolean reset) { final NickoProfile profile = getNickoProfile(); final String displayName = profile.getName() == null ? player.getName() : profile.getName(); - - final ActionResult result = packetSender.sendGameProfileUpdate(displayName, skinChange, reset); - - if (result.isError()) { reset(); } - - packetSender.sendEntityMetadataUpdate(); - packetSender.sendTabListUpdate(displayName); - respawnPlayer(); - packetSender.sendEntityRespawn(); - + final WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player).withName(displayName); + final ActionResult result = updateGameProfileSkin(gameProfile, skinChange, reset); + if (!result.isError()) { + updateMetadata(); + updateTabList(gameProfile, displayName); + respawnPlayer(); + respawnEntityForOthers(); + } return result; } + public ActionResult updateForOthers(boolean skinChange, boolean reset) { + final NickoProfile profile = getNickoProfile(); + final String displayName = profile.getName() == null ? player.getName() : profile.getName(); + final WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player).withName(displayName); + final ActionResult result = updateGameProfileSkin(gameProfile, skinChange, reset); + if (!result.isError()) { + updateMetadata(); + updateTabList(gameProfile, displayName); + respawnEntityForOthers(); + } + return result; + } + + private NickoProfile getNickoProfile() { + final Optional optionalProfile = dataStore.getData(player.getUniqueId()); + return optionalProfile.orElse(NickoProfile.EMPTY_PROFILE.clone()); + } + + public void respawnEntityForOthers() { + final NickoProfile nickoProfile = getNickoProfile(); + if (!nickoProfile.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); + }); + } + + + private ActionResult updateGameProfileSkin(WrappedGameProfile gameProfile, boolean skinChange, boolean reset) { + final NickoProfile profile = getNickoProfile(); + + 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 { + reset(); + return ActionResult.error(LanguageKey.Error.MOJANG_SKIN); + } + } else { + reset(); + return ActionResult.error(LanguageKey.Error.MOJANG_NAME); + } + return ActionResult.ok(); + } catch (ExecutionException e) { + return ActionResult.error(LanguageKey.Error.CACHE); + } catch (IOException e) { + reset(); + return ActionResult.error(LanguageKey.Error.MOJANG_NAME); + } catch (InterruptedException e) { + return ActionResult.error("Unknown error"); + } + } + return ActionResult.ok(); + } + + private void updateMetadata() { + final WrappedDataWatcher entityWatcher = WrappedDataWatcher.getEntityWatcher(player); + entityWatcher.setObject(17, (byte) 0x7f, true); + } + private void respawnPlayer() { + final World world = player.getWorld(); final boolean wasFlying = player.isFlying(); final boolean wasAllowedToFly = player.getAllowFlight(); final int foodLevel = player.getFoodLevel(); - - packetSender.sendPlayerRespawn(); - + 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); player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); player.setAllowFlight(wasAllowedToFly); player.setFlying(wasFlying); @@ -71,8 +159,29 @@ public class AppearanceManager { player.setFoodLevel(foodLevel); } - private NickoProfile getNickoProfile() { - final Optional optionalProfile = dataStore.getData(player.getUniqueId()); - return optionalProfile.orElse(NickoProfile.EMPTY_PROFILE.clone()); + private void updateTabList(WrappedGameProfile gameProfile, String displayName) { + 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(); } } \ No newline at end of file diff --git a/src/main/java/xyz/ineanto/nicko/packet/debug/RespawnPacketListener.java b/src/main/java/xyz/ineanto/nicko/debug/RespawnPacketListener.java similarity index 98% rename from src/main/java/xyz/ineanto/nicko/packet/debug/RespawnPacketListener.java rename to src/main/java/xyz/ineanto/nicko/debug/RespawnPacketListener.java index 5222dd0..653c178 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/debug/RespawnPacketListener.java +++ b/src/main/java/xyz/ineanto/nicko/debug/RespawnPacketListener.java @@ -1,4 +1,4 @@ -package xyz.ineanto.nicko.packet.debug; +package xyz.ineanto.nicko.debug; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.ListeningWhitelist; diff --git a/src/main/java/xyz/ineanto/nicko/event/PlayerJoinListener.java b/src/main/java/xyz/ineanto/nicko/event/PlayerJoinListener.java index 28171f5..b7e4408 100644 --- a/src/main/java/xyz/ineanto/nicko/event/PlayerJoinListener.java +++ b/src/main/java/xyz/ineanto/nicko/event/PlayerJoinListener.java @@ -50,7 +50,7 @@ public class PlayerJoinListener implements Listener { if (profile.hasData()) { final AppearanceManager appearanceManager = new AppearanceManager(player); final boolean needsASkinChange = profile.getSkin() != null && !profile.getSkin().equals(player.getName()); - final ActionResult actionResult = appearanceManager.update(needsASkinChange, false); + final ActionResult actionResult = appearanceManager.updatePlayer(needsASkinChange, false); if (!actionResult.isError()) { player.sendMessage(playerLanguage.translateWithWhoosh(LanguageKey.Event.Appearance.Restore.OK)); } else { @@ -68,7 +68,7 @@ public class PlayerJoinListener implements Listener { optionalOnlinePlayerProfile.ifPresent(profile -> { final AppearanceManager appearanceManager = new AppearanceManager(online); final boolean needsASkinChange = profile.getSkin() != null && !profile.getSkin().equals(online.getName()); - final ActionResult actionResult = appearanceManager.update(needsASkinChange, false); + final ActionResult actionResult = appearanceManager.updateForOthers(needsASkinChange, false); if (actionResult.isError()) { logger.warning("Something wrong happened while updating players to joining player (" + actionResult.getErrorKey() + ")"); } diff --git a/src/main/java/xyz/ineanto/nicko/gui/items/home/RandomSkinItem.java b/src/main/java/xyz/ineanto/nicko/gui/items/home/RandomSkinItem.java index 9753c3c..0306017 100644 --- a/src/main/java/xyz/ineanto/nicko/gui/items/home/RandomSkinItem.java +++ b/src/main/java/xyz/ineanto/nicko/gui/items/home/RandomSkinItem.java @@ -40,7 +40,7 @@ public class RandomSkinItem { instance.getDataStore().updateCache(player.getUniqueId(), profile); final AppearanceManager appearanceManager = new AppearanceManager(player); - final ActionResult result = appearanceManager.update(true, false); + final ActionResult result = appearanceManager.updatePlayer(true, false); if (!result.isError()) { player.sendMessage(playerLanguage.translate(LanguageKey.Event.Appearance.Set.OK, true)); } else { diff --git a/src/main/java/xyz/ineanto/nicko/packet/InternalPacketSender.java b/src/main/java/xyz/ineanto/nicko/packet/InternalPacketSender.java deleted file mode 100644 index 3fb5bd3..0000000 --- a/src/main/java/xyz/ineanto/nicko/packet/InternalPacketSender.java +++ /dev/null @@ -1,125 +0,0 @@ -package xyz.ineanto.nicko.packet; - -import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import com.mojang.authlib.properties.PropertyMap; -import it.unimi.dsi.fastutil.ints.IntList; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; -import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; -import net.minecraft.network.protocol.game.ClientboundRespawnPacket; -import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; -import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.network.syncher.EntityDataSerializers; -import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import org.bukkit.Bukkit; -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.profile.NickoProfile; - -import java.io.IOException; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.ExecutionException; - -/** - * Look at this Mojang. - * I want you to really stare at this code. - * You made me do this. - */ -public class InternalPacketSender implements PacketSender { - private final Player player; - private final NickoProfile profile; - - public InternalPacketSender(Player player, NickoProfile profile) { - this.player = player; - this.profile = profile; - } - - @Override - public void sendEntityRespawn() { - if (!profile.hasData()) return; - - final Entity entityPlayer = (Entity) player; - - final ClientboundRemoveEntitiesPacket destroy = new ClientboundRemoveEntitiesPacket(IntList.of(player.getEntityId())); - final ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(entityPlayer, 0, entityPlayer.getOnPos()); - - Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> { - sendPacket(destroy, player); - sendPacket(add, player); - }); - } - - @Override - public ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset) { - final GameProfile gameProfile = ((ServerPlayer) player).gameProfile; - - // 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())); - } 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 SynchedEntityData.DataValue dataValueComponent = - new SynchedEntityData.DataItem<>( - new EntityDataAccessor<>(17, EntityDataSerializers.BYTE), - (byte) 0x7f - ).value(); - - final ClientboundSetEntityDataPacket data = new ClientboundSetEntityDataPacket(player.getEntityId(), List.of(dataValueComponent)); - sendPacket(data, player); - } - - @Override - public void sendPlayerRespawn() { - final ServerPlayer serverPlayer = (ServerPlayer) player; - final ServerLevel world = (ServerLevel) player.getWorld(); - - final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(world), (byte) 0x03); - sendPacket(respawn, player); - } - - @Override - public void sendTabListUpdate(String displayName) { - - } - - private void sendPacket(Packet packet, Player player) { - ((ServerPlayer) player).connection.send(packet); - } -} diff --git a/src/main/java/xyz/ineanto/nicko/packet/PacketSender.java b/src/main/java/xyz/ineanto/nicko/packet/PacketSender.java deleted file mode 100644 index ef93153..0000000 --- a/src/main/java/xyz/ineanto/nicko/packet/PacketSender.java +++ /dev/null @@ -1,15 +0,0 @@ -package xyz.ineanto.nicko.packet; - -import xyz.ineanto.nicko.appearance.ActionResult; - -public interface PacketSender { - void sendEntityRespawn(); - - ActionResult sendGameProfileUpdate(String name, boolean skinChange, boolean reset); - - void sendEntityMetadataUpdate(); - - void sendPlayerRespawn(); - - void sendTabListUpdate(String displayName); -} 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/java/xyz/ineanto/nicko/profile/NickoProfile.java b/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java index 9f1460f..27c5c3c 100644 --- a/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java +++ b/src/main/java/xyz/ineanto/nicko/profile/NickoProfile.java @@ -4,19 +4,14 @@ import org.bukkit.entity.Player; import xyz.ineanto.nicko.Nicko; import xyz.ineanto.nicko.language.Language; import xyz.ineanto.nicko.storage.PlayerDataStore; -import xyz.ineanto.nicko.storage.name.PlayerNameStore; import java.util.Optional; import java.util.UUID; public class NickoProfile implements Cloneable { + public static final PlayerDataStore dataStore = Nicko.getInstance().getDataStore(); public static final NickoProfile EMPTY_PROFILE = new NickoProfile(null, null, Language.ENGLISH, true); - private static final Nicko instance = Nicko.getInstance(); - private static final PlayerDataStore dataStore = instance.getDataStore(); - - private final PlayerNameStore nameStore = instance.getNameStore(); - private String name; private String skin; private Language language; diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/AbstractPacket.java b/src/main/java/xyz/ineanto/nicko/wrapper/AbstractPacket.java similarity index 98% rename from src/main/java/xyz/ineanto/nicko/packet/wrapper/AbstractPacket.java rename to src/main/java/xyz/ineanto/nicko/wrapper/AbstractPacket.java index 42e138b..1d90240 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/AbstractPacket.java +++ b/src/main/java/xyz/ineanto/nicko/wrapper/AbstractPacket.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package xyz.ineanto.nicko.packet.wrapper; +package xyz.ineanto.nicko.wrapper; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerEntityDestroy.java b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerEntityDestroy.java similarity index 95% rename from src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerEntityDestroy.java rename to src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerEntityDestroy.java index a23f1a6..bc94876 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerEntityDestroy.java +++ b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerEntityDestroy.java @@ -1,4 +1,4 @@ -package xyz.ineanto.nicko.packet.wrapper; +package xyz.ineanto.nicko.wrapper; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketContainer; diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerRespawn.java b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerRespawn.java similarity index 89% rename from src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerRespawn.java rename to src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerRespawn.java index dc71b1f..1ed2ec8 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerRespawn.java +++ b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerRespawn.java @@ -1,4 +1,4 @@ -package xyz.ineanto.nicko.packet.wrapper; +package xyz.ineanto.nicko.wrapper; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.InternalStructure; @@ -56,20 +56,11 @@ public class WrapperPlayServerRespawn extends AbstractPacket { } else { // 1.20.5 to 1.21.1 - /* - Honestly, I've tried everything to make this work. - Fields inside the CommonPlayerSpawnInfo are Record Components and are - marked final. - - This would work with some trickery involved, but here's the - caveat: Record Components/Fields and are immutable by DESIGN. - So... here we are now, stopped right in my track by Java's language design and Mojang themselves. - */ - try { final Object spawnInfoStructureHandle = spawnInfoStructure.getHandle(); final RecordComponent[] components = spawnInfoStructureHandle.getClass().getRecordComponents(); + // Doesn't work! final Field levelKeyField = spawnInfoStructureHandle.getClass().getDeclaredField(components[1].getAccessor().getName()); levelKeyField.setAccessible(true); levelKeyField.set(spawnInfoStructureHandle, BukkitConverters.getWorldKeyConverter().getGeneric(Bukkit.getWorld("world"))); diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerSpawnEntity.java b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerSpawnEntity.java similarity index 98% rename from src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerSpawnEntity.java rename to src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerSpawnEntity.java index 0512717..7f09a16 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayServerSpawnEntity.java +++ b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayServerSpawnEntity.java @@ -1,4 +1,4 @@ -package xyz.ineanto.nicko.packet.wrapper; +package xyz.ineanto.nicko.wrapper; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketContainer; diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfo.java b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayerServerPlayerInfo.java similarity index 96% rename from src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfo.java rename to src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayerServerPlayerInfo.java index ca37dc0..3347f98 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfo.java +++ b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayerServerPlayerInfo.java @@ -1,4 +1,4 @@ -package xyz.ineanto.nicko.packet.wrapper; +package xyz.ineanto.nicko.wrapper; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketContainer; diff --git a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfoRemove.java b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayerServerPlayerInfoRemove.java similarity index 94% rename from src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfoRemove.java rename to src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayerServerPlayerInfoRemove.java index 2273c48..a619249 100644 --- a/src/main/java/xyz/ineanto/nicko/packet/wrapper/WrapperPlayerServerPlayerInfoRemove.java +++ b/src/main/java/xyz/ineanto/nicko/wrapper/WrapperPlayerServerPlayerInfoRemove.java @@ -1,4 +1,4 @@ -package xyz.ineanto.nicko.packet.wrapper; +package xyz.ineanto.nicko.wrapper; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketContainer;