diff --git a/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeArmorStand.java b/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeArmorStand.java index cb4f9cf..4b10bbd 100644 --- a/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeArmorStand.java +++ b/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeArmorStand.java @@ -3,18 +3,10 @@ package de.epiceric.shopchest.nms; import org.bukkit.Location; import org.bukkit.entity.Player; -import java.util.UUID; - -public interface FakeArmorStand { - - int getEntityId(); +public interface FakeArmorStand extends FakeEntity { void sendData(String name, Iterable receivers); - void remove(Iterable receivers); - void setLocation(Location location, Iterable receivers); - void spawn(UUID uuid, Location location, Iterable receivers); - } diff --git a/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeEntity.java b/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeEntity.java new file mode 100644 index 0000000..b696761 --- /dev/null +++ b/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeEntity.java @@ -0,0 +1,16 @@ +package de.epiceric.shopchest.nms; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.util.UUID; + +public interface FakeEntity { + + int getEntityId(); + + void spawn(UUID uuid, Location location, Iterable receivers); + + void remove(Iterable receivers); + +} diff --git a/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeItem.java b/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeItem.java new file mode 100644 index 0000000..9e5b1c8 --- /dev/null +++ b/nms/interface/src/main/java/de/epiceric/shopchest/nms/FakeItem.java @@ -0,0 +1,10 @@ +package de.epiceric.shopchest.nms; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public interface FakeItem extends FakeEntity{ + + void sendData(ItemStack item, Iterable receivers); + +} diff --git a/nms/interface/src/main/java/de/epiceric/shopchest/nms/Platform.java b/nms/interface/src/main/java/de/epiceric/shopchest/nms/Platform.java index 52fa4ce..20275ac 100644 --- a/nms/interface/src/main/java/de/epiceric/shopchest/nms/Platform.java +++ b/nms/interface/src/main/java/de/epiceric/shopchest/nms/Platform.java @@ -4,4 +4,6 @@ public interface Platform { FakeArmorStand createFakeArmorStand(); + FakeItem createFakeItem(); + } diff --git a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeArmorStandImpl.java b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeArmorStandImpl.java index 3ff01f3..5f9f6e5 100644 --- a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeArmorStandImpl.java +++ b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeArmorStandImpl.java @@ -6,115 +6,75 @@ import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; -import net.minecraft.network.protocol.game.ClientboundRemoveEntityPacket; -import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.phys.Vec3; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; import org.bukkit.entity.Player; import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; -public class FakeArmorStandImpl implements FakeArmorStand { +public class FakeArmorStandImpl extends FakeEntityImpl implements FakeArmorStand { private final static byte INVISIBLE_FLAG = 0b100000; - private final static AtomicInteger ENTITY_COUNTER; protected static final EntityDataAccessor DATA_SHARED_FLAGS_ID; - private static final EntityDataAccessor DATA_NO_GRAVITY; private static final EntityDataAccessor> DATA_CUSTOM_NAME; private static final EntityDataAccessor DATA_CUSTOM_NAME_VISIBLE; - private static final EntityDataAccessor DATA_SILENT; - private final static Field packedItemField; private final static float MARKER_ARMOR_STAND_OFFSET = 1.975f; static { try { - final Field entityCounterField = Entity.class.getDeclaredField("b"); // ENTITY_COUNTER - ENTITY_COUNTER = (AtomicInteger) entityCounterField.get(null); final Field dataSharedFlagsId = Entity.class.getDeclaredField("Z"); // DATA_SHARED_FLAGS_ID - DATA_SHARED_FLAGS_ID = forceCast(dataSharedFlagsId.get(null)); - final Field dataNoGravityField = Entity.class.getDeclaredField("aM"); // DATA_NO_GRAVITY - DATA_NO_GRAVITY = forceCast(dataNoGravityField.get(null)); + DATA_SHARED_FLAGS_ID = FakeEntityImpl.forceCast(dataSharedFlagsId.get(null)); final Field dataCustomNameField = Entity.class.getDeclaredField("aJ"); // DATA_CUSTOM_NAME - DATA_CUSTOM_NAME = forceCast(dataCustomNameField.get(null)); + DATA_CUSTOM_NAME = FakeEntityImpl.forceCast(dataCustomNameField.get(null)); final Field dataCustomNameVisibleField = Entity.class.getDeclaredField("aK"); // DATA_CUSTOM_NAME_VISIBLE - DATA_CUSTOM_NAME_VISIBLE = forceCast(dataCustomNameVisibleField.get(null)); - final Field dataSilentField = Entity.class.getDeclaredField("aL"); // DATA_SILENT - DATA_SILENT = forceCast(dataSilentField.get(null)); - packedItemField = ClientboundSetEntityDataPacket.class.getDeclaredField("b"); // packedItems + DATA_CUSTOM_NAME_VISIBLE = FakeEntityImpl.forceCast(dataCustomNameVisibleField.get(null)); } catch (ReflectiveOperationException e){ throw new RuntimeException(e); } } - @SuppressWarnings("unchecked") - private static T forceCast(Object o){ - return (T) o; - } - - private final int entityId; - public FakeArmorStandImpl() { - entityId = ENTITY_COUNTER.incrementAndGet(); - } - - @Override - public int getEntityId() { - return entityId; - } - - private void sendPacket(Packet packet, Iterable receivers){ - for(Player receiver : receivers){ - ((CraftPlayer)receiver).getHandle().connection.send(packet); - } + super(); } @Override public void sendData(String name, Iterable receivers) { - // Create packet - final SynchedEntityData entityData = new SynchedEntityData(null); - final ClientboundSetEntityDataPacket dataPacket = new ClientboundSetEntityDataPacket(entityId, entityData, false); - final List> packedItems = new ArrayList<>(5); - - // Setup data - packedItems.add(new SynchedEntityData.DataItem<>(DATA_SHARED_FLAGS_ID, INVISIBLE_FLAG)); - packedItems.add(new SynchedEntityData.DataItem<>(DATA_NO_GRAVITY, true)); - packedItems.add(new SynchedEntityData.DataItem<>(DATA_CUSTOM_NAME, Optional.ofNullable( - Component.Serializer.fromJson( - ComponentSerializer.toString( - TextComponent.fromLegacyText(name) - ) - ) - ))); - packedItems.add(new SynchedEntityData.DataItem<>(DATA_CUSTOM_NAME_VISIBLE, true)); - packedItems.add(new SynchedEntityData.DataItem<>(DATA_SILENT, true)); - - try { - packedItemField.set(dataPacket, packedItems); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - - // Send packet - sendPacket(dataPacket, receivers); + sendData(receivers, name); } @Override - public void remove(Iterable receivers) { - final ClientboundRemoveEntityPacket removePacket = new ClientboundRemoveEntityPacket(entityId); - sendPacket(removePacket, receivers); + protected EntityType getEntityType() { + return EntityType.ARMOR_STAND; + } + + @Override + protected float getSpawnOffSet() { + return MARKER_ARMOR_STAND_OFFSET; + } + + @Override + protected int getDataItemCount() { + return 4; + } + + @Override + protected void addSpecificData(List> packedItems, String name) { + packedItems.add(new SynchedEntityData.DataItem<>(DATA_SHARED_FLAGS_ID, INVISIBLE_FLAG)); + packedItems.add(new SynchedEntityData.DataItem<>(DATA_CUSTOM_NAME, Optional.ofNullable( + Component.Serializer.fromJson( + ComponentSerializer.toString( + TextComponent.fromLegacyText(name) + ) + ) + ))); + packedItems.add(new SynchedEntityData.DataItem<>(DATA_CUSTOM_NAME_VISIBLE, true)); + // TODO Add Marker (specific to ArmorStand) } @Override @@ -131,20 +91,4 @@ public class FakeArmorStandImpl implements FakeArmorStand { sendPacket(positionPacket, receivers); } - @Override - public void spawn(UUID uuid, Location location, Iterable receivers) { - final ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket( - entityId, - uuid, - location.getX(), - location.getY() + MARKER_ARMOR_STAND_OFFSET, - location.getZ(), - 0f, - 0f, - EntityType.ARMOR_STAND, - 0, - Vec3.ZERO - ); - sendPacket(spawnPacket, receivers); - } } diff --git a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeEntityImpl.java b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeEntityImpl.java new file mode 100644 index 0000000..221b582 --- /dev/null +++ b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeEntityImpl.java @@ -0,0 +1,120 @@ +package de.epiceric.shopchest.nms.v1_17_R1; + +import de.epiceric.shopchest.nms.FakeEntity; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntityPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +public abstract class FakeEntityImpl implements FakeEntity { + + private final static AtomicInteger ENTITY_COUNTER; + private final static EntityDataAccessor DATA_NO_GRAVITY; + private final static EntityDataAccessor DATA_SILENT; + private final static Field packedItemField; + + static { + try { + final Field entityCounterField = Entity.class.getDeclaredField("b"); // ENTITY_COUNTER + ENTITY_COUNTER = (AtomicInteger) entityCounterField.get(null); + final Field dataNoGravityField = Entity.class.getDeclaredField("aM"); // DATA_NO_GRAVITY + DATA_NO_GRAVITY = forceCast(dataNoGravityField.get(null)); + final Field dataSilentField = Entity.class.getDeclaredField("aL"); // DATA_SILENT + DATA_SILENT = forceCast(dataSilentField.get(null)); + packedItemField = ClientboundSetEntityDataPacket.class.getDeclaredField("b"); // packedItems + }catch (ReflectiveOperationException e){ + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + protected static T forceCast(Object o){ + return (T) o; + } + + protected final int entityId; + + public FakeEntityImpl() { + entityId = ENTITY_COUNTER.incrementAndGet(); + } + + @Override + public int getEntityId() { + return entityId; + } + + protected void sendPacket(Packet packet, Iterable receivers){ + for(Player receiver : receivers){ + ((CraftPlayer)receiver).getHandle().connection.send(packet); + } + } + + @Override + public void spawn(UUID uuid, Location location, Iterable receivers) { + final ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket( + entityId, + uuid, + location.getX(), + location.getY() + getSpawnOffSet(), + location.getZ(), + 0f, + 0f, + getEntityType(), + 0, + Vec3.ZERO + ); + sendPacket(spawnPacket, receivers); + } + + @Override + public void remove(Iterable receivers) { + final ClientboundRemoveEntityPacket removePacket = new ClientboundRemoveEntityPacket(entityId); + sendPacket(removePacket, receivers); + } + + protected void sendData(Iterable receivers, T data){ + // Create packet + final SynchedEntityData entityData = new SynchedEntityData(null); + final ClientboundSetEntityDataPacket dataPacket = new ClientboundSetEntityDataPacket(entityId, entityData, false); + final List> packedItems = new ArrayList<>(2 + getDataItemCount()); + + // Setup data + packedItems.add(new SynchedEntityData.DataItem<>(DATA_NO_GRAVITY, true)); + packedItems.add(new SynchedEntityData.DataItem<>(DATA_SILENT, true)); + addSpecificData(packedItems, data); + + try { + packedItemField.set(dataPacket, packedItems); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + + // Send packet + sendPacket(dataPacket, receivers); + } + + protected abstract EntityType getEntityType(); + + protected float getSpawnOffSet(){ + return 0f; + } + + protected abstract int getDataItemCount(); + + protected abstract void addSpecificData(List> packedItems, T data); + +} diff --git a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeItemImpl.java b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeItemImpl.java new file mode 100644 index 0000000..d09c7f0 --- /dev/null +++ b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/FakeItemImpl.java @@ -0,0 +1,36 @@ +package de.epiceric.shopchest.nms.v1_17_R1; + +import de.epiceric.shopchest.nms.FakeItem; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class FakeItemImpl extends FakeEntityImpl implements FakeItem { + + public FakeItemImpl() { + super(); + } + + @Override + public void sendData(ItemStack item, Iterable receivers) { + + } + + @Override + protected EntityType getEntityType() { + return EntityType.ITEM; + } + + @Override + protected int getDataItemCount() { + return 0; + } + + @Override + protected void addSpecificData(List> packedItems, ItemStack data) { + + } +} diff --git a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/PlatformImpl.java b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/PlatformImpl.java index 542ad99..f929f7b 100644 --- a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/PlatformImpl.java +++ b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/PlatformImpl.java @@ -1,6 +1,7 @@ package de.epiceric.shopchest.nms.v1_17_R1; import de.epiceric.shopchest.nms.FakeArmorStand; +import de.epiceric.shopchest.nms.FakeItem; import de.epiceric.shopchest.nms.Platform; public class PlatformImpl implements Platform { @@ -10,4 +11,9 @@ public class PlatformImpl implements Platform { return new FakeArmorStandImpl(); } + @Override + public FakeItem createFakeItem() { + return new FakeItemImpl(); + } + }