From cee168e225a9c539e31815a5cd6ac9084c0fd389 Mon Sep 17 00:00:00 2001 From: ineanto Date: Tue, 25 Apr 2023 23:25:14 +0200 Subject: [PATCH] feat: wrappers --- .../net/artelnatif/nicko/NickoBukkit.java | 24 +++++ .../nicko/disguise/AppearanceManager.java | 49 +++++++--- .../wrapper/WrapperPlayServerRespawn.java | 94 +++++++++++++++++-- .../WrapperPlayerServerPlayerInfo.java | 46 +++++++++ .../WrapperPlayerServerPlayerInfoRemove.java | 35 +++++++ src/main/resources/plugin.yml | 2 + 6 files changed, 228 insertions(+), 22 deletions(-) create mode 100644 src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayerServerPlayerInfo.java create mode 100644 src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayerServerPlayerInfoRemove.java diff --git a/src/main/java/net/artelnatif/nicko/NickoBukkit.java b/src/main/java/net/artelnatif/nicko/NickoBukkit.java index 8310406..7f94730 100644 --- a/src/main/java/net/artelnatif/nicko/NickoBukkit.java +++ b/src/main/java/net/artelnatif/nicko/NickoBukkit.java @@ -1,7 +1,9 @@ package net.artelnatif.nicko; +import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.*; import net.artelnatif.nicko.command.NickoCommand; import net.artelnatif.nicko.config.Configuration; import net.artelnatif.nicko.config.ConfigurationManager; @@ -27,6 +29,7 @@ import xyz.xenondevs.invui.item.impl.SimpleItem; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; public class NickoBukkit extends JavaPlugin { private static NickoBukkit plugin; @@ -104,6 +107,27 @@ public class NickoBukkit extends JavaPlugin { getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this); getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this); + protocolManager.addPacketListener(new PacketAdapter( + this, + ListenerPriority.NORMAL, + PacketType.Play.Server.PLAYER_INFO) { + @Override + public void onPacketReceiving(PacketEvent event) { + } + + @Override + public void onPacketSending(PacketEvent event) { + final PacketContainer packet = event.getPacket(); + packet.getStructures().getFields().forEach(fieldAccessor -> { + final Field field = fieldAccessor.getField(); + getLogger().info("field=[" + + "name=" + field.getName() + "," + + "type=" + field.getType().getSimpleName() + + "]"); + }); + } + }); + getLogger().info("Nicko (Bukkit) has been enabled."); } } diff --git a/src/main/java/net/artelnatif/nicko/disguise/AppearanceManager.java b/src/main/java/net/artelnatif/nicko/disguise/AppearanceManager.java index 2cde36d..afaf82e 100644 --- a/src/main/java/net/artelnatif/nicko/disguise/AppearanceManager.java +++ b/src/main/java/net/artelnatif/nicko/disguise/AppearanceManager.java @@ -1,20 +1,23 @@ package net.artelnatif.nicko.disguise; -import com.comphenix.protocol.wrappers.WrappedGameProfile; -import com.comphenix.protocol.wrappers.WrappedSignedProperty; +import com.comphenix.protocol.wrappers.*; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimap; import net.artelnatif.nicko.NickoBukkit; import net.artelnatif.nicko.i18n.I18NDict; import net.artelnatif.nicko.mojang.MojangAPI; import net.artelnatif.nicko.mojang.MojangSkin; import net.artelnatif.nicko.storage.PlayerDataStore; import net.artelnatif.nicko.storage.name.PlayerNameStore; +import net.artelnatif.nicko.wrapper.WrapperPlayServerRespawn; +import net.artelnatif.nicko.wrapper.WrapperPlayerServerPlayerInfo; +import net.artelnatif.nicko.wrapper.WrapperPlayerServerPlayerInfoRemove; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerTeleportEvent; import java.io.IOException; -import java.util.Collection; +import java.util.EnumSet; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ExecutionException; @@ -95,9 +98,9 @@ public class AppearanceManager { public ActionResult updatePlayer(boolean skinChange) { final String displayName = profile.getName() == null ? player.getName() : profile.getName(); - Bukkit.broadcastMessage("Building UserProfile"); - final WrappedGameProfile gameProfile = new WrappedGameProfile(player.getUniqueId(), displayName); + Bukkit.broadcastMessage("Building UserProfile"); + final WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player).withName(displayName); final ActionResult result = updateGameProfileSkin(gameProfile, skinChange); if (!result.isError()) { updateTabList(gameProfile, displayName); @@ -118,9 +121,9 @@ public class AppearanceManager { skin = mojang.getSkin(uuid.get()); if (skin.isPresent()) { final MojangSkin skinResult = skin.get(); - final Collection properties = gameProfile.getProperties().values(); - properties.clear(); - properties.add(new WrappedSignedProperty("textures", skinResult.getValue(), skinResult.getSignature())); + final Multimap properties = gameProfile.getProperties(); + properties.get("textures").clear(); + properties.put("textures", new WrappedSignedProperty("textures", skinResult.getValue(), skinResult.getSignature())); Bukkit.broadcastMessage("Modified properties"); } } @@ -137,14 +140,32 @@ public class AppearanceManager { private void respawnPlayer() { Bukkit.broadcastMessage("Respawning player"); final World world = player.getWorld(); - // TODO (Ineanto, 4/23/23): Respawn Packet - player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); + final WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn(); + respawn.setGameMode(player.getGameMode()); + respawn.setDifficulty(world.getDifficulty()); + respawn.setDimension(world); + respawn.setSeed(world.getSeed()); + respawn.sendPacket(player); } private void updateTabList(WrappedGameProfile gameProfile, String displayName) { - // TODO (Ineanto, 4/23/23): Update player info packet - // TODO (Ineanto, 4/23/23): Remove player info packet Bukkit.broadcastMessage("Updating tablist"); - // TODO (Ineanto, 4/23/23): Send packets + final WrapperPlayerServerPlayerInfoRemove remove = new WrapperPlayerServerPlayerInfoRemove(); + remove.setUUIDs(ImmutableList.of(player.getUniqueId())); + + final WrapperPlayerServerPlayerInfo update = new WrapperPlayerServerPlayerInfo(); + update.setActions(EnumSet.of(EnumWrappers.PlayerInfoAction.ADD_PLAYER, + EnumWrappers.PlayerInfoAction.UPDATE_LISTED, + EnumWrappers.PlayerInfoAction.UPDATE_DISPLAY_NAME, + EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE, + EnumWrappers.PlayerInfoAction.UPDATE_LATENCY)); + update.setData(ImmutableList.of(new PlayerInfoData( + gameProfile, + player.getPing(), + EnumWrappers.NativeGameMode.fromBukkit(player.getGameMode()), + WrappedChatComponent.fromText(displayName) + ))); + remove.sendPacket(player); + update.sendPacket(player); } } diff --git a/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayServerRespawn.java b/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayServerRespawn.java index c0cbf97..26a1321 100644 --- a/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayServerRespawn.java +++ b/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayServerRespawn.java @@ -2,12 +2,17 @@ package net.artelnatif.nicko.wrapper; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.utility.MinecraftVersion; +import com.comphenix.protocol.wrappers.BukkitConverters; +import com.comphenix.protocol.wrappers.EnumWrappers; +import org.bukkit.Difficulty; +import org.bukkit.GameMode; import org.bukkit.World; -import java.util.Optional; - /** - * 1.19.4 compliant version of the WrapperPlayServerRespawn. + * Up-to-date version of the Wrapper class + * for the PacketPlayServerRespawn. * * @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland */ @@ -19,19 +24,92 @@ public class WrapperPlayServerRespawn extends AbstractPacket { handle.getModifier().writeDefaults(); } - public Optional getDimension() { - return handle.getDimensionTypes().optionRead(0); + //............. + // Dimension Field (1.8 - Present) + // The dimension field has changed types, + // numerous times. Version 1.8 through 1.15 need an integer, + // 1.15 through 1.18 need a (NBT Tag) Identifier and + // 1.19.2 and beyond require a Holder of a DimensionManager Identifier (???). + // (Wiki.vg still refers this as an Identifier) + // + // n.b.: this field is a nightmare please mojang stop refactoring + // your code to change things that were working perfectly fine before + //............. + + public World getDimension() { + if (MinecraftVersion.WILD_UPDATE.atOrAbove()) { + // 1.19 and above + return handle.getHolders( + MinecraftReflection.getDimensionManager(), + BukkitConverters.getDimensionConverter() + ).read(0); + } + + return handle.getDimensionTypes().read(0); } public void setDimension(World value) { + if (MinecraftVersion.WILD_UPDATE.atOrAbove()) { + // 1.19 and above + handle.getWorldKeys().withParamType( + MinecraftReflection.getResourceKey(), + BukkitConverters.getWorldKeyConverter() + ).write(0, value); + return; + } + // 1.18 and below handle.getDimensionTypes().write(0, value); } - public Optional getSeed() { - return handle.getLongs().optionRead(0); + //............. + // GameMode Field + //............. + + public void getGameMode() { + // Present since 1.8, we're good! + handle.getGameModes().read(0); + } + + public void setGameMode(GameMode value) { + // Present since 1.8, we're good! + handle.getGameModes().write(0, EnumWrappers.NativeGameMode.fromBukkit(value)); + } + + //............. + // Seed Field + // Added in 1.15. + //............. + + public long getSeed() { + if (MinecraftVersion.BEE_UPDATE.atOrAbove()) { + return handle.getLongs().read(0); + } + return -1; } public void setSeed(long value) { - handle.getLongs().write(0, value); + if (MinecraftVersion.BEE_UPDATE.atOrAbove()) { + handle.getLongs().write(0, value); + } + } + + //............. + // Difficulty Field + // Removed in 1.14. + //............. + + public Difficulty getDifficulty() { + if (MinecraftVersion.VILLAGE_UPDATE.atOrAbove()) { + return null; + } + + final EnumWrappers.Difficulty difficulty = handle.getDifficulties().read(0); + return difficulty == null ? null : Difficulty.valueOf(difficulty.name()); + } + + public void setDifficulty(Difficulty difficulty) { + if (difficulty != null && !MinecraftVersion.VILLAGE_UPDATE.atOrAbove()) { + handle.getDifficulties().write(0, EnumWrappers.Difficulty.valueOf(difficulty.name())); + } } } diff --git a/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayerServerPlayerInfo.java b/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayerServerPlayerInfo.java new file mode 100644 index 0000000..fc64027 --- /dev/null +++ b/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayerServerPlayerInfo.java @@ -0,0 +1,46 @@ +package net.artelnatif.nicko.wrapper; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.EnumWrappers; +import com.comphenix.protocol.wrappers.PlayerInfoData; + +import java.util.List; +import java.util.Set; + +/** + * Up-to-date version of the Wrapper class + * for the PlayerServerPlayerInfo. + * + * @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland + */ + +public class WrapperPlayerServerPlayerInfo extends AbstractPacket { + public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO; + + public WrapperPlayerServerPlayerInfo() { + super(new PacketContainer(TYPE), TYPE); + handle.getModifier().writeDefaults(); + } + + public WrapperPlayerServerPlayerInfo(PacketContainer packet) { + super(packet, TYPE); + } + + public Set getActions() { + return handle.getPlayerInfoActions().read(0); + } + + public void setActions(Set value) { + handle.getPlayerInfoActions().write(0, value); + } + + public List getData() { + return handle.getPlayerInfoDataLists().read(0); + } + + public void setData(List value) { + //handle.getSets(PlayerInfoData.getConverter()).write(0, value); + handle.getPlayerInfoDataLists().write(1, value); + } +} diff --git a/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayerServerPlayerInfoRemove.java b/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayerServerPlayerInfoRemove.java new file mode 100644 index 0000000..bc6e912 --- /dev/null +++ b/src/main/java/net/artelnatif/nicko/wrapper/WrapperPlayerServerPlayerInfoRemove.java @@ -0,0 +1,35 @@ +package net.artelnatif.nicko.wrapper; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketContainer; + +import java.util.List; +import java.util.UUID; + +/** + * Up-to-date version of the Wrapper class + * for the PlayerServerPlayerInfoRemove. + * + * @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland + */ + +public class WrapperPlayerServerPlayerInfoRemove extends AbstractPacket { + public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO_REMOVE; + + public WrapperPlayerServerPlayerInfoRemove() { + super(new PacketContainer(TYPE), TYPE); + handle.getModifier().writeDefaults(); + } + + public WrapperPlayerServerPlayerInfoRemove(PacketContainer packet) { + super(packet, TYPE); + } + + public List getUUIDs() { + return handle.getUUIDLists().read(0); + } + + public void setUUIDs(List value) { + handle.getUUIDLists().write(0, value); + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 26ba4b9..66cda8f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,6 +4,8 @@ version: 1.0-SNAPSHOT author: Ineanto api-version: 1.13 softdepend: [ PlaceholderAPI ] +depend: + - ProtocolLib load: POSTWORLD commands: nicko: