diff --git a/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java b/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java index daea6e1..9fc2ccd 100644 --- a/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java +++ b/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java @@ -27,6 +27,7 @@ import org.bukkit.inventory.meta.SkullMeta; import java.util.HashMap; import java.util.Map; +import java.util.Optional; public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper { @@ -307,4 +308,9 @@ public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper public void setNamedSpawnPacketDataWatcher(Object packet) { // field not present } + + @Override + public Object formatDisplayName(String displayName) { + return displayName != null ? Optional.of(ChatWrapper.impl.stringToChatComponent(displayName)) : Optional.empty(); + } } diff --git a/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java b/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java index 14b605d..0a3caba 100644 --- a/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java +++ b/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java @@ -79,4 +79,9 @@ public class FlatteningWrapper8 implements FlatteningWrapper.IFlatteningWrapper public void setNamedSpawnPacketDataWatcher(Object packet) { namedSpawnDataWatcher.set(packet, dataWatcherConstructor.invoke((Object) null)); } + + @Override + public Object formatDisplayName(String displayName) { + return displayName != null ? displayName : ""; + } } diff --git a/SpigotCore_Main/src/de/steamwar/core/FlatteningWrapper.java b/SpigotCore_Main/src/de/steamwar/core/FlatteningWrapper.java index 0042207..b307106 100644 --- a/SpigotCore_Main/src/de/steamwar/core/FlatteningWrapper.java +++ b/SpigotCore_Main/src/de/steamwar/core/FlatteningWrapper.java @@ -41,5 +41,6 @@ public class FlatteningWrapper { Object getPose(boolean sneaking); void setNamedSpawnPacketDataWatcher(Object packet); + Object formatDisplayName(String displayName); } } diff --git a/SpigotCore_Main/src/de/steamwar/entity/REntity.java b/SpigotCore_Main/src/de/steamwar/entity/REntity.java index dac3e7f..2053cb1 100644 --- a/SpigotCore_Main/src/de/steamwar/entity/REntity.java +++ b/SpigotCore_Main/src/de/steamwar/entity/REntity.java @@ -20,54 +20,36 @@ package de.steamwar.entity; import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; import de.steamwar.core.*; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.util.*; import java.util.function.Consumer; +import java.util.function.Function; public class REntity { private static final Object entityStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(0, Byte.class); private static final Object sneakingDataWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 6 : 0, FlatteningWrapper.impl.getPose(true).getClass()); private static final Object bowDrawnWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 7 : 6, Byte.class); - private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(16, Byte.class); //TODO multiversioning - private static final Object nameWatcher = BountifulWrapper.impl.getDataWatcherObject(2, Optional.class); // Optional, first optional //TODO multiversioning (dataWatcherRegistry.getFields()[fieldIndex].get(null)) - private static final Object nameVisibleWatcher = BountifulWrapper.impl.getDataWatcherObject(3, Boolean.class); //TODO multiversioning - private static final Object sizeWatcher = BountifulWrapper.impl.getDataWatcherObject(14, Byte.class); //TODO multiversioning - - /* - private static final String SCOREBOARD_TEAMNAME = "Replay"; - private static final Team team; - - static { - if(FightScoreboard.getBukkit().getTeam(SCOREBOARD_TEAMNAME) == null) - team = FightScoreboard.getBukkit().registerNewTeam(SCOREBOARD_TEAMNAME); - else - team = FightScoreboard.getBukkit().getTeam(SCOREBOARD_TEAMNAME); - team.setNameTagVisibility(NameTagVisibility.NEVER); - } - */ + private static final Object nameWatcher = BountifulWrapper.impl.getDataWatcherObject(2, Core.getVersion() > 12 ? Optional.class : String.class); // Optional + private static final Object nameVisibleWatcher = BountifulWrapper.impl.getDataWatcherObject(3, Boolean.class); private static int entityIdCounter = -1; private static final Random random = new Random(); private final REntityServer server; private final EntityType entityType; - private final int entityId; - private final UUID uuid; - private final String name; + protected final int entityId; + protected final UUID uuid; - private double x; - private double y; - private double z; + protected double x; + protected double y; + protected double z; private byte yaw; private byte pitch; private byte headYaw; @@ -77,24 +59,17 @@ public class REntity { private boolean bowDrawn; private int fireTick; private String displayName; - private final Map itemSlots; - - //TODO packet caching - public REntity(REntityServer server, UUID uuid, String name, Location location) { - this(server, EntityType.PLAYER, uuid, name, location); - //team.addEntry(name); - } + protected final Map itemSlots; public REntity(REntityServer server, EntityType entityType, Location location) { - this(server, entityType, new UUID(random.nextLong() & -61441L | 16384L, random.nextLong() & 4611686018427387903L | -9223372036854775808L), null, location); + this(server, entityType, new UUID(random.nextLong() & -61441L | 16384L, random.nextLong() & 4611686018427387903L | -9223372036854775808L), location); } - private REntity(REntityServer server, EntityType entityType, UUID uuid, String name, Location location) { + protected REntity(REntityServer server, EntityType entityType, UUID uuid, Location location) { this.server = server; this.entityType = entityType; this.entityId = entityIdCounter--; this.uuid = uuid; - this.name = name; this.x = location.getX(); this.y = location.getY(); @@ -116,9 +91,11 @@ public class REntity { this.z = locZ; this.yaw = rotToByte(yaw); this.pitch = rotToByte(pitch); - this.headYaw = headYaw; server.updateEntity(this, getTeleportPacket()); - server.updateEntity(this, getHeadRotationPacket()); + if(this.headYaw != headYaw) { + this.headYaw = headYaw; + server.updateEntity(this, getHeadRotationPacket()); + } server.postEntityMove(this, fromX, fromZ); } @@ -186,36 +163,10 @@ public class REntity { public void setDisplayName(String displayName) { this.displayName = displayName; - server.updateEntity(this, getDataWatcherPacket(nameWatcher, displayName != null ? Optional.of(ChatWrapper.impl.stringToChatComponent(displayName)) : Optional.empty())); - server.updateEntity(this, getDataWatcherPacket(nameVisibleWatcher, displayName != null)); - } - - @Deprecated - public void setItem(String item, boolean enchanted, String slot) { - ItemStack stack = new ItemStack(Material.valueOf(item.replace("minecraft:", "").toUpperCase()), 1); - if(enchanted) - stack.addUnsafeEnchantment(Enchantment.DURABILITY, 1); - - switch(slot){ - case "HEAD": - setItem(ProtocolWrapper.itemSlots[5], stack); - break; - case "CHEST": - setItem(ProtocolWrapper.itemSlots[4], stack); - break; - case "LEGS": - setItem(ProtocolWrapper.itemSlots[3], stack); - break; - case "FEET": - setItem(ProtocolWrapper.itemSlots[2], stack); - break; - case "OFFHAND": - setItem(ProtocolWrapper.itemSlots[1], stack); - break; - case "MAINHAND": - default: - setItem(ProtocolWrapper.itemSlots[0], stack); - } + server.updateEntity(this, getDataWatcherPacket( + nameWatcher, FlatteningWrapper.impl.formatDisplayName(displayName), + nameVisibleWatcher, displayName != null + )); } public void setItem(Object slot, ItemStack stack) { @@ -227,27 +178,22 @@ public class REntity { server.removeEntity(this); } + private static final Function livingSpawnPacketGenerator = entitySpawnPacketGenerator(ProtocolWrapper.spawnLivingPacket, 2); + private static final Function spawnPacketGenerator = entitySpawnPacketGenerator(ProtocolWrapper.spawnPacket, 1); void spawn(Consumer packetSink) { - if(entityType == EntityType.PLAYER){ - packetSink.accept(getPlayerInfoPacket(addPlayer)); - packetSink.accept(getNamedSpawnPacket()); - for (Map.Entry entry : itemSlots.entrySet()) { - packetSink.accept(getEquipmentPacket(entry.getKey(), entry.getValue())); - } - packetSink.accept(getDataWatcherPacket(skinPartsDataWatcher, (byte) 0x7F)); //TODO multiversioning - } else if(entityType.isAlive()) { - packetSink.accept(getSpawnLivingEntityPacket()); - packetSink.accept(getDataWatcherPacket(sizeWatcher, (byte) 0x10)); // small size //TODO multiversioning TODO only on ArmorStands - for (Map.Entry entry : itemSlots.entrySet()) { - packetSink.accept(getEquipmentPacket(entry.getKey(), entry.getValue())); - } + if(entityType.isAlive()) { + packetSink.accept(livingSpawnPacketGenerator.apply(this)); } else { - packetSink.accept(getSpawnEntityPacket()); + packetSink.accept(spawnPacketGenerator.apply(this)); } - //packetSink.accept(getTeleportPacket()); - packetSink.accept(getHeadRotationPacket()); //TODO head rotation for all types? - //TODO merge MetadataPacket (DataWatcherPackets) + postSpawn(packetSink); + } + + protected void postSpawn(Consumer packetSink) { + if(headYaw != 0) { + packetSink.accept(getHeadRotationPacket()); + } if(Core.getVersion() > 12 && sneaks) { packetSink.accept(getDataWatcherPacket(sneakingDataWatcher, FlatteningWrapper.impl.getPose(true))); @@ -259,8 +205,7 @@ public class REntity { } if(displayName != null) { - packetSink.accept(getDataWatcherPacket(nameWatcher, Optional.of(ChatWrapper.impl.stringToChatComponent(displayName)))); - packetSink.accept(getDataWatcherPacket(nameVisibleWatcher, true)); + packetSink.accept(getDataWatcherPacket(nameWatcher, FlatteningWrapper.impl.formatDisplayName(displayName), nameVisibleWatcher, true)); } } @@ -282,11 +227,6 @@ public class REntity { destroyEntities = Reflection.getField(destroyPacket, int[].class, 0); } void despawn(Consumer packetSink){ - if(entityType == EntityType.PLAYER){ - packetSink.accept(getPlayerInfoPacket(removePlayer)); - //team.removeEntry(name); - } - Object packet = Reflection.newInstance(destroyPacket); destroyEntities.set(packet, Core.getVersion() > 15 ? new IntArrayList(new int[]{entityId}) : new int[]{entityId}); packetSink.accept(packet); @@ -305,7 +245,7 @@ public class REntity { if(fireTick != 0) status |= 1; - if(Core.getVersion() <= 12 && sneaks) + if(sneaks) status |= 2; if(Core.getVersion() == 8 && bowDrawn) status |= 0x10; @@ -319,7 +259,7 @@ public class REntity { private static final Reflection.FieldAccessor metadataEntity = Reflection.getField(metadataPacket, int.class, 0); private static final Reflection.FieldAccessor metadataMetadata = Reflection.getField(metadataPacket, List.class, 0); - private Object getDataWatcherPacket(Object... dataWatcherKeyValues) { + protected Object getDataWatcherPacket(Object... dataWatcherKeyValues) { Object packet = Reflection.newInstance(metadataPacket); metadataEntity.set(packet, entityId); @@ -360,63 +300,35 @@ public class REntity { private static final Class craftItemStack = Reflection.getClass("{obc}.inventory.CraftItemStack"); private static final Reflection.MethodInvoker asNMSCopy = Reflection.getTypedMethod(REntity.craftItemStack, "asNMSCopy", ProtocolWrapper.itemStack, ItemStack.class); - private Object getEquipmentPacket(Object slot, ItemStack stack){ + protected Object getEquipmentPacket(Object slot, ItemStack stack){ Object packet = Reflection.newInstance(ProtocolWrapper.equipmentPacket); equipmentEntity.set(packet, entityId); ProtocolWrapper.impl.setEquipmentPacketStack(packet, slot, asNMSCopy.invoke(null, stack)); return packet; } - private static final Class playerInfoPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo"); - private static final Class playerInfoActionClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo$EnumPlayerInfoAction"); - private static final Object addPlayer = playerInfoActionClass.getEnumConstants()[0]; - private static final Reflection.FieldAccessor playerInfoAction = Reflection.getField(playerInfoPacket, playerInfoActionClass, 0); - private static final Object removePlayer = playerInfoActionClass.getEnumConstants()[4]; - private static final Reflection.FieldAccessor playerInfoData = Reflection.getField(playerInfoPacket, List.class, 0); - private static final Class enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "{nms.world.level}.EnumGamemode" : "{nms}.WorldSettings$EnumGamemode"); - private static final Object creative = enumGamemode.getEnumConstants()[Core.getVersion() > 15 ? 1 : 2]; - private Object getPlayerInfoPacket(Object action){ - Object packet = Reflection.newInstance(playerInfoPacket); - playerInfoAction.set(packet, action); - playerInfoData.set(packet, Collections.singletonList(ProtocolWrapper.impl.playerInfoDataConstructor(packet, new GameProfile(uuid, name), creative))); - return packet; + private static Function entitySpawnPacketGenerator(Class spawnPacket, int posOffset8) { + BountifulWrapper.UUIDSetter uuid = BountifulWrapper.impl.getUUIDSetter(spawnPacket); + Function packetGenerator = spawnPacketGenerator(spawnPacket, posOffset8); + + return entity -> { + Object packet = packetGenerator.apply(entity); + uuid.set(packet, entity.uuid); + ProtocolWrapper.impl.setSpawnPacketType(packet, entity.entityType); + return packet; + }; } - private static final Class namedSpawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutNamedEntitySpawn"); - private static final Reflection.FieldAccessor namedSpawnEntity = Reflection.getField(namedSpawnPacket, int.class, 0); - private static final Reflection.FieldAccessor namedSpawnUUID = Reflection.getField(namedSpawnPacket, UUID.class, 0); - private static final BountifulWrapper.PositionSetter namedSpawnPosition = BountifulWrapper.impl.getPositionSetter(namedSpawnPacket, 1); - private Object getNamedSpawnPacket() { - Object packet = Reflection.newInstance(namedSpawnPacket); - namedSpawnEntity.set(packet, entityId); - namedSpawnUUID.set(packet, uuid); - namedSpawnPosition.set(packet, x, y, z); - FlatteningWrapper.impl.setNamedSpawnPacketDataWatcher(packet); - return packet; - } + protected static Function spawnPacketGenerator(Class spawnPacket, int posOffset8) { + Reflection.FieldAccessor entityId = Reflection.getField(spawnPacket, int.class, 0); + BountifulWrapper.PositionSetter position = BountifulWrapper.impl.getPositionSetter(spawnPacket, posOffset8); - private static final Reflection.FieldAccessor spawnLivingEntityId = Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 0); - private static final BountifulWrapper.UUIDSetter livingSpawnUUID = BountifulWrapper.impl.getUUIDSetter(ProtocolWrapper.spawnLivingPacket); - private static final BountifulWrapper.PositionSetter livingSpawnPosition = BountifulWrapper.impl.getPositionSetter(ProtocolWrapper.spawnLivingPacket, 2); //TODO only diff to spawnEntity, simplify code - private Object getSpawnLivingEntityPacket() { - Object packet = Reflection.newInstance(ProtocolWrapper.spawnLivingPacket); - spawnLivingEntityId.set(packet, entityId); - livingSpawnUUID.set(packet, uuid); - ProtocolWrapper.impl.setSpawnPacketType(packet, entityType); - livingSpawnPosition.set(packet, x, y, z); - return packet; - } - - private static final Reflection.FieldAccessor spawnEntity = Reflection.getField(ProtocolWrapper.spawnPacket, int.class, 0); - private static final BountifulWrapper.UUIDSetter spawnUUID = BountifulWrapper.impl.getUUIDSetter(ProtocolWrapper.spawnPacket); - private static final BountifulWrapper.PositionSetter spawnPosition = BountifulWrapper.impl.getPositionSetter(ProtocolWrapper.spawnPacket, 1); - private Object getSpawnEntityPacket() { - Object packet = Reflection.newInstance(ProtocolWrapper.spawnPacket); - spawnEntity.set(packet, entityId); - spawnUUID.set(packet, uuid); - ProtocolWrapper.impl.setSpawnPacketType(packet, entityType); - spawnPosition.set(packet, x, y, z); - return packet; + return entity -> { + Object packet = Reflection.newInstance(spawnPacket); + entityId.set(packet, entity.entityId); + position.set(packet, entity.x, entity.y, entity.z); + return packet; + }; } private byte rotToByte(float rot) { diff --git a/SpigotCore_Main/src/de/steamwar/entity/RHologram.java b/SpigotCore_Main/src/de/steamwar/entity/RHologram.java new file mode 100644 index 0000000..de5f3c5 --- /dev/null +++ b/SpigotCore_Main/src/de/steamwar/entity/RHologram.java @@ -0,0 +1,62 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.entity; + +import de.steamwar.core.BountifulWrapper; +import de.steamwar.core.Core; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; + +import java.util.function.Consumer; + +public class RHologram extends REntity { + + private static int sizeIndex() { + switch(Core.getVersion()) { + case 8: + case 9: + return 10; + case 10: + case 12: + return 11; + case 14: + return 13; + case 15: + return 14; + case 18: + case 19: + default: + return 15; + } + } + + private static final Object sizeWatcher = BountifulWrapper.impl.getDataWatcherObject(sizeIndex(), Byte.class); + + public RHologram(REntityServer server, Location location) { + super(server, EntityType.ARMOR_STAND, location); + setInvisible(true); + } + + @Override + void spawn(Consumer packetSink) { + super.spawn(packetSink); + packetSink.accept(getDataWatcherPacket(sizeWatcher, (byte) 0x10)); + } +} diff --git a/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java b/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java new file mode 100644 index 0000000..079250d --- /dev/null +++ b/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java @@ -0,0 +1,128 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.entity; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import de.steamwar.core.BountifulWrapper; +import de.steamwar.core.Core; +import de.steamwar.core.FlatteningWrapper; +import de.steamwar.core.ProtocolWrapper; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Function; + +public class RPlayer extends REntity { + + /* + private static final String SCOREBOARD_TEAMNAME = "Replay"; + private static final Team team; + + static { + if(FightScoreboard.getBukkit().getTeam(SCOREBOARD_TEAMNAME) == null) + team = FightScoreboard.getBukkit().registerNewTeam(SCOREBOARD_TEAMNAME); + else + team = FightScoreboard.getBukkit().getTeam(SCOREBOARD_TEAMNAME); + team.setNameTagVisibility(NameTagVisibility.NEVER); + } + */ + + private static int skinPartsIndex() { + switch(Core.getVersion()) { + case 8: + return 10; + case 9: + return 12; + case 10: + case 12: + return 13; + case 14: + return 15; + case 15: + return 16; + case 18: + case 19: + default: + return 17; + } + } + + private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(skinPartsIndex(), Byte.class); + + private final String name; + + public RPlayer(REntityServer server, UUID uuid, String name, Location location) { + super(server, EntityType.PLAYER, uuid, location); + this.name = name; + //team.addEntry(name); + } + + @Override + void spawn(Consumer packetSink) { + packetSink.accept(getPlayerInfoPacket(addPlayer)); + packetSink.accept(getNamedSpawnPacket()); + packetSink.accept(getDataWatcherPacket(skinPartsDataWatcher, (byte) 0x7F)); + + for (Map.Entry entry : itemSlots.entrySet()) { + packetSink.accept(getEquipmentPacket(entry.getKey(), entry.getValue())); + } + + postSpawn(packetSink); + } + + @Override + void despawn(Consumer packetSink) { + //team.removeEntry(name); + super.despawn(packetSink); + packetSink.accept(getPlayerInfoPacket(removePlayer)); + } + + private static final Class playerInfoPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo"); + private static final Class playerInfoActionClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo$EnumPlayerInfoAction"); + private static final Object addPlayer = playerInfoActionClass.getEnumConstants()[0]; + private static final Reflection.FieldAccessor playerInfoAction = Reflection.getField(playerInfoPacket, playerInfoActionClass, 0); + private static final Object removePlayer = playerInfoActionClass.getEnumConstants()[4]; + private static final Reflection.FieldAccessor playerInfoData = Reflection.getField(playerInfoPacket, List.class, 0); + private static final Class enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "{nms.world.level}.EnumGamemode" : "{nms}.WorldSettings$EnumGamemode"); + private static final Object creative = enumGamemode.getEnumConstants()[Core.getVersion() > 15 ? 1 : 2]; + private Object getPlayerInfoPacket(Object action){ + Object packet = Reflection.newInstance(playerInfoPacket); + playerInfoAction.set(packet, action); + playerInfoData.set(packet, Collections.singletonList(ProtocolWrapper.impl.playerInfoDataConstructor(packet, new GameProfile(uuid, name), creative))); + return packet; + } + + private static final Class namedSpawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutNamedEntitySpawn"); + private static final Function namedSpawnPacketGenerator = spawnPacketGenerator(namedSpawnPacket, 1); + private static final Reflection.FieldAccessor namedSpawnUUID = Reflection.getField(namedSpawnPacket, UUID.class, 0); + private Object getNamedSpawnPacket() { + Object packet = namedSpawnPacketGenerator.apply(this); + namedSpawnUUID.set(packet, uuid); + FlatteningWrapper.impl.setNamedSpawnPacketDataWatcher(packet); + return packet; + } +}