From 45b399ccfec2a96f1164e89ac2ddc55ec5e1154b Mon Sep 17 00:00:00 2001 From: smeths Date: Sun, 8 Oct 2023 11:56:02 +0100 Subject: [PATCH 1/2] 1.20.2 support (#21) * start 1.20.2 support /unfinished * add 1.20.2 to PlatformLoader and update some import /unfinished * correct field mappings for 1.20.2 --- nms/all/pom.xml | 4 + nms/pom.xml | 7 ++ nms/v1_20_R2/pom.xml | 41 +++++++ .../nms/v1_20_R2/FakeArmorStandImpl.java | 99 +++++++++++++++ .../nms/v1_20_R2/FakeEntityImpl.java | 115 ++++++++++++++++++ .../shopchest/nms/v1_20_R2/FakeItemImpl.java | 60 +++++++++ .../shopchest/nms/v1_20_R2/PlatformImpl.java | 25 ++++ .../nms/v1_20_R2/TextComponentHelperImpl.java | 15 +++ .../shopchest/nms/PlatformLoader.java | 2 + 9 files changed, 368 insertions(+) create mode 100644 nms/v1_20_R2/pom.xml create mode 100644 nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeArmorStandImpl.java create mode 100644 nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeEntityImpl.java create mode 100644 nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeItemImpl.java create mode 100644 nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/PlatformImpl.java create mode 100644 nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/TextComponentHelperImpl.java diff --git a/nms/all/pom.xml b/nms/all/pom.xml index aee41c8..ca0237b 100644 --- a/nms/all/pom.xml +++ b/nms/all/pom.xml @@ -60,6 +60,10 @@ de.epiceric shopchest-nms-v1_20_R1 + + de.epiceric + shopchest-nms-v1_20_R2 + diff --git a/nms/pom.xml b/nms/pom.xml index 6982786..7bd0394 100644 --- a/nms/pom.xml +++ b/nms/pom.xml @@ -24,6 +24,7 @@ v1_19_R2 v1_19_R3 v1_20_R1 + v1_20_R2 all @@ -97,6 +98,12 @@ 1.0.0 provided + + de.epiceric + shopchest-nms-v1_20_R2 + 1.0.0 + provided + diff --git a/nms/v1_20_R2/pom.xml b/nms/v1_20_R2/pom.xml new file mode 100644 index 0000000..3502ebd --- /dev/null +++ b/nms/v1_20_R2/pom.xml @@ -0,0 +1,41 @@ + + + + shopchest-nms + de.epiceric + 1.0.1 + + 4.0.0 + + shopchest-nms-v1_20_R2 + 1.0.0 + + + 1.20.2-R0.1-SNAPSHOT + + + + + org.spigotmc + spigot + remapped-mojang + + + de.epiceric + shopchest-nms-interface + provided + + + + + + + net.md-5 + specialsource-maven-plugin + + + + + diff --git a/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeArmorStandImpl.java b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeArmorStandImpl.java new file mode 100644 index 0000000..3bcd904 --- /dev/null +++ b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeArmorStandImpl.java @@ -0,0 +1,99 @@ +package de.epiceric.shopchest.nms.v1_20_R2; + +import de.epiceric.shopchest.nms.FakeArmorStand; +import io.netty.buffer.Unpooled; +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.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.entity.decoration.ArmorStand; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Optional; + +public class FakeArmorStandImpl extends FakeEntityImpl implements FakeArmorStand { + + private final static byte INVISIBLE_FLAG = 0b100000; + private final static byte MARKER_FLAG = 0b10000; + private final static EntityDataAccessor DATA_SHARED_FLAGS_ID; + private final static EntityDataAccessor> DATA_CUSTOM_NAME; + private final static EntityDataAccessor DATA_CUSTOM_NAME_VISIBLE; + private final static float MARKER_ARMOR_STAND_OFFSET = 1.975f; + + static { + try { + final Field dataSharedFlagsId = Entity.class.getDeclaredField("ao"); // DATA_SHARED_FLAGS_ID + dataSharedFlagsId.setAccessible(true); + DATA_SHARED_FLAGS_ID = forceCast(dataSharedFlagsId.get(null)); + final Field dataCustomNameField = Entity.class.getDeclaredField("aU"); // DATA_CUSTOM_NAME + dataCustomNameField.setAccessible(true); + DATA_CUSTOM_NAME = forceCast(dataCustomNameField.get(null)); + final Field dataCustomNameVisibleField = Entity.class.getDeclaredField("aV"); // DATA_CUSTOM_NAME_VISIBLE + dataCustomNameVisibleField.setAccessible(true); + DATA_CUSTOM_NAME_VISIBLE = forceCast(dataCustomNameVisibleField.get(null)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public FakeArmorStandImpl() { + super(); + } + + @Override + public void sendData(String name, Iterable receivers) { + sendData(receivers, name); + } + + @Override + 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(SynchedEntityData.DataValue.create(DATA_SHARED_FLAGS_ID, INVISIBLE_FLAG)); + packedItems.add(SynchedEntityData.DataValue.create(DATA_CUSTOM_NAME, Optional.ofNullable( + Component.Serializer.fromJson( + ComponentSerializer.toString( + TextComponent.fromLegacyText(name) + ) + ) + ))); + packedItems.add(SynchedEntityData.DataValue.create(DATA_CUSTOM_NAME_VISIBLE, true)); + packedItems.add(SynchedEntityData.DataValue.create(ArmorStand.DATA_CLIENT_FLAGS, MARKER_FLAG)); + } + + @Override + public void setLocation(Location location, Iterable receivers) { + final FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer()); + buffer.writeVarInt(entityId); + buffer.writeDouble(location.getX()); + buffer.writeDouble(location.getY() + MARKER_ARMOR_STAND_OFFSET); + buffer.writeDouble(location.getZ()); + buffer.writeByte(0); + buffer.writeByte(0); + buffer.writeBoolean(false); + final ClientboundTeleportEntityPacket positionPacket = new ClientboundTeleportEntityPacket(buffer); + sendPacket(positionPacket, receivers); + } + +} diff --git a/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeEntityImpl.java b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeEntityImpl.java new file mode 100644 index 0000000..3bd62f1 --- /dev/null +++ b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeEntityImpl.java @@ -0,0 +1,115 @@ +package de.epiceric.shopchest.nms.v1_20_R2; + +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.ClientboundRemoveEntitiesPacket; +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_20_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.lang.reflect.Field; +import java.util.LinkedList; +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; + + static { + try { + final Field entityCounterField = Entity.class.getDeclaredField("d"); // ENTITY_COUNTER + entityCounterField.setAccessible(true); + ENTITY_COUNTER = (AtomicInteger) entityCounterField.get(null); + final Field dataNoGravityField = Entity.class.getDeclaredField("aX"); // DATA_NO_GRAVITY + dataNoGravityField.setAccessible(true); + DATA_NO_GRAVITY = forceCast(dataNoGravityField.get(null)); + final Field dataSilentField = Entity.class.getDeclaredField("aW"); // DATA_SILENT + dataSilentField.setAccessible(true); + DATA_SILENT = forceCast(dataSilentField.get(null)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + protected final int entityId; + + public FakeEntityImpl() { + entityId = ENTITY_COUNTER.incrementAndGet(); + } + + @SuppressWarnings("unchecked") + protected static T forceCast(Object o) { + return (T) o; + } + + @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, + 0d + ); + sendPacket(spawnPacket, receivers); + } + + @Override + public void remove(Iterable receivers) { + final ClientboundRemoveEntitiesPacket removePacket = new ClientboundRemoveEntitiesPacket(entityId); + sendPacket(removePacket, receivers); + } + + protected void sendData(Iterable receivers, T data) { + // Create packet + final List> packedItems = new LinkedList<>(); + final ClientboundSetEntityDataPacket dataPacket = new ClientboundSetEntityDataPacket(entityId, packedItems); + + // Setup data + packedItems.add(SynchedEntityData.DataValue.create(DATA_NO_GRAVITY, true)); + packedItems.add(SynchedEntityData.DataValue.create(DATA_SILENT, true)); + addSpecificData(packedItems, data); + + // 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_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeItemImpl.java b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeItemImpl.java new file mode 100644 index 0000000..651c7e5 --- /dev/null +++ b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/FakeItemImpl.java @@ -0,0 +1,60 @@ +package de.epiceric.shopchest.nms.v1_20_R2; + +import de.epiceric.shopchest.nms.FakeItem; +import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.phys.Vec3; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Field; +import java.util.List; + +public class FakeItemImpl extends FakeEntityImpl implements FakeItem { + + private final static EntityDataAccessor DATA_ITEM; + + static { + try { + final Field dataItemField = ItemEntity.class.getDeclaredField("c"); // DATA_ITEM + dataItemField.setAccessible(true); + DATA_ITEM = forceCast(dataItemField.get(null)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public FakeItemImpl() { + super(); + } + + @Override + public void sendData(ItemStack item, Iterable receivers) { + sendData(receivers, item); + } + + @Override + public void resetVelocity(Iterable receivers) { + final ClientboundSetEntityMotionPacket velocityPacket = new ClientboundSetEntityMotionPacket(entityId, Vec3.ZERO); + sendPacket(velocityPacket, receivers); + } + + @Override + protected EntityType getEntityType() { + return EntityType.ITEM; + } + + @Override + protected int getDataItemCount() { + return 1; + } + + @Override + protected void addSpecificData(List> packedItems, ItemStack data) { + packedItems.add(SynchedEntityData.DataValue.create(DATA_ITEM, CraftItemStack.asNMSCopy(data))); + } +} diff --git a/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/PlatformImpl.java b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/PlatformImpl.java new file mode 100644 index 0000000..0a2af9c --- /dev/null +++ b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/PlatformImpl.java @@ -0,0 +1,25 @@ +package de.epiceric.shopchest.nms.v1_20_R2; + +import de.epiceric.shopchest.nms.FakeArmorStand; +import de.epiceric.shopchest.nms.FakeItem; +import de.epiceric.shopchest.nms.Platform; +import de.epiceric.shopchest.nms.TextComponentHelper; + +public class PlatformImpl implements Platform { + + @Override + public FakeArmorStand createFakeArmorStand() { + return new FakeArmorStandImpl(); + } + + @Override + public FakeItem createFakeItem() { + return new FakeItemImpl(); + } + + @Override + public TextComponentHelper getTextComponentHelper() { + return new TextComponentHelperImpl(); + } + +} diff --git a/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/TextComponentHelperImpl.java b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/TextComponentHelperImpl.java new file mode 100644 index 0000000..fccb377 --- /dev/null +++ b/nms/v1_20_R2/src/main/java/de/epiceric/shopchest/nms/v1_20_R2/TextComponentHelperImpl.java @@ -0,0 +1,15 @@ +package de.epiceric.shopchest.nms.v1_20_R2; + +import de.epiceric.shopchest.nms.TextComponentHelper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.inventory.ItemStack; + +public class TextComponentHelperImpl implements TextComponentHelper { + @Override + public String getNbt(ItemStack itemStack) { + final Tag tag = CraftItemStack.asNMSCopy(itemStack).save(new CompoundTag()).get("tag"); + return tag == null ? null : tag.getAsString(); + } +} diff --git a/plugin/src/main/java/de/epiceric/shopchest/nms/PlatformLoader.java b/plugin/src/main/java/de/epiceric/shopchest/nms/PlatformLoader.java index 7c713dd..9b3ea57 100644 --- a/plugin/src/main/java/de/epiceric/shopchest/nms/PlatformLoader.java +++ b/plugin/src/main/java/de/epiceric/shopchest/nms/PlatformLoader.java @@ -93,6 +93,8 @@ public class PlatformLoader { case "34f399b4f2033891290b7f0700e9e47b": // 1.20 case "bcf3dcb22ad42792794079f9443df2c0": // 1.20.1 (v1_20_R1) return new de.epiceric.shopchest.nms.v1_20_R1.PlatformImpl(); + case "3478a65bfd04b15b431fe107b3617dfc": //1.20.2 + return new de.epiceric.shopchest.nms.v1_20_R2.PlatformImpl(); default: return null; } From 8a549ac58f9b2eaa666a1c0551eb4101d8ecdf2b Mon Sep 17 00:00:00 2001 From: Flowsqy <47575244+Flowsqy@users.noreply.github.com> Date: Mon, 9 Oct 2023 21:06:24 +0200 Subject: [PATCH 2/2] Add 1.20.2 to nms/README.md --- nms/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/nms/README.md b/nms/README.md index ed2cbf5..7d03067 100644 --- a/nms/README.md +++ b/nms/README.md @@ -15,3 +15,4 @@ You need to run the BuildTools for the following versions: - 1.19.3 - 1.19.4 - 1.20.1 +- 1.20.2