From d81aee90685b3012d1a9798cd2cefc10a12dc47e Mon Sep 17 00:00:00 2001
From: Flowsqy <47575244+Flowsqy@users.noreply.github.com>
Date: Thu, 13 Jun 2024 22:36:51 +0200
Subject: [PATCH] Add 1.21 support
---
nms/all/pom.xml | 6 +-
nms/pom.xml | 7 ++
nms/v1_21_R1/pom.xml | 41 +++++++
.../nms/v1_21_R1/FakeArmorStandImpl.java | 94 ++++++++++++++
.../nms/v1_21_R1/FakeEntityImpl.java | 115 ++++++++++++++++++
.../shopchest/nms/v1_21_R1/FakeItemImpl.java | 60 +++++++++
.../nms/v1_21_R1/ObfuscatedFieldNames.java | 15 +++
.../shopchest/nms/v1_21_R1/PlatformImpl.java | 19 +++
.../shopchest/nms/PlatformLoader.java | 2 +
pom.xml | 2 +-
10 files changed, 359 insertions(+), 2 deletions(-)
create mode 100644 nms/v1_21_R1/pom.xml
create mode 100644 nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeArmorStandImpl.java
create mode 100644 nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeEntityImpl.java
create mode 100644 nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeItemImpl.java
create mode 100644 nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/ObfuscatedFieldNames.java
create mode 100644 nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/PlatformImpl.java
diff --git a/nms/all/pom.xml b/nms/all/pom.xml
index 2bfd344..8766b63 100644
--- a/nms/all/pom.xml
+++ b/nms/all/pom.xml
@@ -10,7 +10,7 @@
4.0.0
shopchest-nms-all
- 1.0.3
+ 1.0.4
pom
@@ -72,6 +72,10 @@
de.epiceric
shopchest-nms-v1_20_R4
+
+ de.epiceric
+ shopchest-nms-v1_21_R1
+
diff --git a/nms/pom.xml b/nms/pom.xml
index 21d6160..d0a8752 100644
--- a/nms/pom.xml
+++ b/nms/pom.xml
@@ -27,6 +27,7 @@
v1_20_R2
v1_20_R3
v1_20_R4
+ v1_21_R1
all
@@ -118,6 +119,12 @@
1.0.0
provided
+
+ de.epiceric
+ shopchest-nms-v1_21_R1
+ 1.0.0
+ provided
+
diff --git a/nms/v1_21_R1/pom.xml b/nms/v1_21_R1/pom.xml
new file mode 100644
index 0000000..59643c0
--- /dev/null
+++ b/nms/v1_21_R1/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+ shopchest-nms
+ de.epiceric
+ 1.0.1
+
+ 4.0.0
+
+ shopchest-nms-v1_21_R1
+ 1.0.0
+
+
+ 1.21-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_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeArmorStandImpl.java b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeArmorStandImpl.java
new file mode 100644
index 0000000..549936c
--- /dev/null
+++ b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeArmorStandImpl.java
@@ -0,0 +1,94 @@
+package de.epiceric.shopchest.nms.v1_21_R1;
+
+import de.epiceric.shopchest.nms.FakeArmorStand;
+import io.netty.buffer.Unpooled;
+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.craftbukkit.v1_21_R1.util.CraftChatMessage;
+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(ObfuscatedFieldNames.DATA_SHARED_FLAGS_ID);
+ dataSharedFlagsId.setAccessible(true);
+ DATA_SHARED_FLAGS_ID = forceCast(dataSharedFlagsId.get(null));
+ final Field dataCustomNameField = Entity.class.getDeclaredField(ObfuscatedFieldNames.DATA_CUSTOM_NAME);
+ dataCustomNameField.setAccessible(true);
+ DATA_CUSTOM_NAME = forceCast(dataCustomNameField.get(null));
+ final Field dataCustomNameVisibleField = Entity.class.getDeclaredField(ObfuscatedFieldNames.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(
+ CraftChatMessage.fromStringOrNull(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 = ClientboundTeleportEntityPacket.STREAM_CODEC.decode(buffer);
+ sendPacket(positionPacket, receivers);
+ }
+
+}
diff --git a/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeEntityImpl.java b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeEntityImpl.java
new file mode 100644
index 0000000..b6ee555
--- /dev/null
+++ b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeEntityImpl.java
@@ -0,0 +1,115 @@
+package de.epiceric.shopchest.nms.v1_21_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.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_21_R1.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(ObfuscatedFieldNames.ENTITY_COUNTER);
+ entityCounterField.setAccessible(true);
+ ENTITY_COUNTER = (AtomicInteger) entityCounterField.get(null);
+ final Field dataNoGravityField = Entity.class.getDeclaredField(ObfuscatedFieldNames.DATA_NO_GRAVITY);
+ dataNoGravityField.setAccessible(true);
+ DATA_NO_GRAVITY = forceCast(dataNoGravityField.get(null));
+ final Field dataSilentField = Entity.class.getDeclaredField(ObfuscatedFieldNames.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_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeItemImpl.java b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeItemImpl.java
new file mode 100644
index 0000000..2ee22f3
--- /dev/null
+++ b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/FakeItemImpl.java
@@ -0,0 +1,60 @@
+package de.epiceric.shopchest.nms.v1_21_R1;
+
+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_21_R1.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(ObfuscatedFieldNames.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_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/ObfuscatedFieldNames.java b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/ObfuscatedFieldNames.java
new file mode 100644
index 0000000..31afadc
--- /dev/null
+++ b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/ObfuscatedFieldNames.java
@@ -0,0 +1,15 @@
+package de.epiceric.shopchest.nms.v1_21_R1;
+
+public class ObfuscatedFieldNames {
+
+ // Entity
+ public static final String ENTITY_COUNTER = "c";
+ public static final String DATA_NO_GRAVITY = "aT";
+ public static final String DATA_SILENT = "aS";
+ public static final String DATA_SHARED_FLAGS_ID = "ap";
+ public static final String DATA_CUSTOM_NAME = "aQ";
+ public static final String DATA_CUSTOM_NAME_VISIBLE = "aR";
+ // ItemEntity
+ public static final String DATA_ITEM = "d";
+
+}
diff --git a/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/PlatformImpl.java b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/PlatformImpl.java
new file mode 100644
index 0000000..9f01e5b
--- /dev/null
+++ b/nms/v1_21_R1/src/main/java/de/epiceric/shopchest/nms/v1_21_R1/PlatformImpl.java
@@ -0,0 +1,19 @@
+package de.epiceric.shopchest.nms.v1_21_R1;
+
+import de.epiceric.shopchest.nms.FakeArmorStand;
+import de.epiceric.shopchest.nms.FakeItem;
+import de.epiceric.shopchest.nms.Platform;
+
+public class PlatformImpl implements Platform {
+
+ @Override
+ public FakeArmorStand createFakeArmorStand() {
+ return new FakeArmorStandImpl();
+ }
+
+ @Override
+ public FakeItem createFakeItem() {
+ return new FakeItemImpl();
+ }
+
+}
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 f438c2c..3398a3c 100644
--- a/plugin/src/main/java/de/epiceric/shopchest/nms/PlatformLoader.java
+++ b/plugin/src/main/java/de/epiceric/shopchest/nms/PlatformLoader.java
@@ -100,6 +100,8 @@ public class PlatformLoader {
case "ad1a88fd7eaf2277f2507bf34d7b994c": // 1.20.5 (Replaced by 1.20.6)
case "ee13f98a43b9c5abffdcc0bb24154460": // 1.20.6 (v1_20_R4)
return new de.epiceric.shopchest.nms.v1_20_R4.PlatformImpl();
+ case "229d7afc75b70a6c388337687ac4da1f": // 1.21 (v1_21_R1)
+ return new de.epiceric.shopchest.nms.v1_21_R1.PlatformImpl();
default:
return null;
}
diff --git a/pom.xml b/pom.xml
index 01ca1f0..d87119f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -317,7 +317,7 @@
de.epiceric
shopchest-nms-all
- 1.0.3
+ 1.0.4
${nms-classifier}