Skip to content

Commit d81aee9

Browse files
committed
Add 1.21 support
1 parent b91e443 commit d81aee9

File tree

10 files changed

+359
-2
lines changed

10 files changed

+359
-2
lines changed

nms/all/pom.xml

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<modelVersion>4.0.0</modelVersion>
1111

1212
<artifactId>shopchest-nms-all</artifactId>
13-
<version>1.0.3</version>
13+
<version>1.0.4</version>
1414

1515
<packaging>pom</packaging>
1616

@@ -72,6 +72,10 @@
7272
<groupId>de.epiceric</groupId>
7373
<artifactId>shopchest-nms-v1_20_R4</artifactId>
7474
</dependency>
75+
<dependency>
76+
<groupId>de.epiceric</groupId>
77+
<artifactId>shopchest-nms-v1_21_R1</artifactId>
78+
</dependency>
7579
</dependencies>
7680

7781
<build>

nms/pom.xml

+7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<module>v1_20_R2</module>
2828
<module>v1_20_R3</module>
2929
<module>v1_20_R4</module>
30+
<module>v1_21_R1</module>
3031
<module>all</module>
3132
</modules>
3233

@@ -118,6 +119,12 @@
118119
<version>1.0.0</version>
119120
<scope>provided</scope>
120121
</dependency>
122+
<dependency>
123+
<groupId>de.epiceric</groupId>
124+
<artifactId>shopchest-nms-v1_21_R1</artifactId>
125+
<version>1.0.0</version>
126+
<scope>provided</scope>
127+
</dependency>
121128
</dependencies>
122129
</dependencyManagement>
123130

nms/v1_21_R1/pom.xml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>shopchest-nms</artifactId>
7+
<groupId>de.epiceric</groupId>
8+
<version>1.0.1</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>shopchest-nms-v1_21_R1</artifactId>
13+
<version>1.0.0</version>
14+
15+
<properties>
16+
<spigot.version>1.21-R0.1-SNAPSHOT</spigot.version>
17+
</properties>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>org.spigotmc</groupId>
22+
<artifactId>spigot</artifactId>
23+
<classifier>remapped-mojang</classifier>
24+
</dependency>
25+
<dependency>
26+
<groupId>de.epiceric</groupId>
27+
<artifactId>shopchest-nms-interface</artifactId>
28+
<scope>provided</scope>
29+
</dependency>
30+
</dependencies>
31+
32+
<build>
33+
<plugins>
34+
<plugin>
35+
<groupId>net.md-5</groupId>
36+
<artifactId>specialsource-maven-plugin</artifactId>
37+
</plugin>
38+
</plugins>
39+
</build>
40+
41+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package de.epiceric.shopchest.nms.v1_21_R1;
2+
3+
import de.epiceric.shopchest.nms.FakeArmorStand;
4+
import io.netty.buffer.Unpooled;
5+
import net.minecraft.network.FriendlyByteBuf;
6+
import net.minecraft.network.chat.Component;
7+
import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket;
8+
import net.minecraft.network.syncher.EntityDataAccessor;
9+
import net.minecraft.network.syncher.SynchedEntityData;
10+
import net.minecraft.world.entity.Entity;
11+
import net.minecraft.world.entity.EntityType;
12+
import net.minecraft.world.entity.decoration.ArmorStand;
13+
import org.bukkit.Location;
14+
import org.bukkit.craftbukkit.v1_21_R1.util.CraftChatMessage;
15+
import org.bukkit.entity.Player;
16+
17+
import java.lang.reflect.Field;
18+
import java.util.List;
19+
import java.util.Optional;
20+
21+
public class FakeArmorStandImpl extends FakeEntityImpl<String> implements FakeArmorStand {
22+
23+
private final static byte INVISIBLE_FLAG = 0b100000;
24+
private final static byte MARKER_FLAG = 0b10000;
25+
private final static EntityDataAccessor<Byte> DATA_SHARED_FLAGS_ID;
26+
private final static EntityDataAccessor<Optional<Component>> DATA_CUSTOM_NAME;
27+
private final static EntityDataAccessor<Boolean> DATA_CUSTOM_NAME_VISIBLE;
28+
private final static float MARKER_ARMOR_STAND_OFFSET = 1.975f;
29+
30+
static {
31+
try {
32+
final Field dataSharedFlagsId = Entity.class.getDeclaredField(ObfuscatedFieldNames.DATA_SHARED_FLAGS_ID);
33+
dataSharedFlagsId.setAccessible(true);
34+
DATA_SHARED_FLAGS_ID = forceCast(dataSharedFlagsId.get(null));
35+
final Field dataCustomNameField = Entity.class.getDeclaredField(ObfuscatedFieldNames.DATA_CUSTOM_NAME);
36+
dataCustomNameField.setAccessible(true);
37+
DATA_CUSTOM_NAME = forceCast(dataCustomNameField.get(null));
38+
final Field dataCustomNameVisibleField = Entity.class.getDeclaredField(ObfuscatedFieldNames.DATA_CUSTOM_NAME_VISIBLE);
39+
dataCustomNameVisibleField.setAccessible(true);
40+
DATA_CUSTOM_NAME_VISIBLE = forceCast(dataCustomNameVisibleField.get(null));
41+
} catch (ReflectiveOperationException e) {
42+
throw new RuntimeException(e);
43+
}
44+
}
45+
46+
public FakeArmorStandImpl() {
47+
super();
48+
}
49+
50+
@Override
51+
public void sendData(String name, Iterable<Player> receivers) {
52+
sendData(receivers, name);
53+
}
54+
55+
@Override
56+
protected EntityType<?> getEntityType() {
57+
return EntityType.ARMOR_STAND;
58+
}
59+
60+
@Override
61+
protected float getSpawnOffSet() {
62+
return MARKER_ARMOR_STAND_OFFSET;
63+
}
64+
65+
@Override
66+
protected int getDataItemCount() {
67+
return 4;
68+
}
69+
70+
@Override
71+
protected void addSpecificData(List<SynchedEntityData.DataValue<?>> packedItems, String name) {
72+
packedItems.add(SynchedEntityData.DataValue.create(DATA_SHARED_FLAGS_ID, INVISIBLE_FLAG));
73+
packedItems.add(SynchedEntityData.DataValue.create(DATA_CUSTOM_NAME, Optional.ofNullable(
74+
CraftChatMessage.fromStringOrNull(name)
75+
)));
76+
packedItems.add(SynchedEntityData.DataValue.create(DATA_CUSTOM_NAME_VISIBLE, true));
77+
packedItems.add(SynchedEntityData.DataValue.create(ArmorStand.DATA_CLIENT_FLAGS, MARKER_FLAG));
78+
}
79+
80+
@Override
81+
public void setLocation(Location location, Iterable<Player> receivers) {
82+
final FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer());
83+
buffer.writeVarInt(entityId);
84+
buffer.writeDouble(location.getX());
85+
buffer.writeDouble(location.getY() + MARKER_ARMOR_STAND_OFFSET);
86+
buffer.writeDouble(location.getZ());
87+
buffer.writeByte(0);
88+
buffer.writeByte(0);
89+
buffer.writeBoolean(false);
90+
final ClientboundTeleportEntityPacket positionPacket = ClientboundTeleportEntityPacket.STREAM_CODEC.decode(buffer);
91+
sendPacket(positionPacket, receivers);
92+
}
93+
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package de.epiceric.shopchest.nms.v1_21_R1;
2+
3+
import de.epiceric.shopchest.nms.FakeEntity;
4+
import net.minecraft.network.protocol.Packet;
5+
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
6+
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
7+
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
8+
import net.minecraft.network.syncher.EntityDataAccessor;
9+
import net.minecraft.network.syncher.SynchedEntityData;
10+
import net.minecraft.world.entity.Entity;
11+
import net.minecraft.world.entity.EntityType;
12+
import net.minecraft.world.phys.Vec3;
13+
import org.bukkit.Location;
14+
import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer;
15+
import org.bukkit.entity.Player;
16+
17+
import java.lang.reflect.Field;
18+
import java.util.LinkedList;
19+
import java.util.List;
20+
import java.util.UUID;
21+
import java.util.concurrent.atomic.AtomicInteger;
22+
23+
public abstract class FakeEntityImpl<T> implements FakeEntity {
24+
25+
private final static AtomicInteger ENTITY_COUNTER;
26+
private final static EntityDataAccessor<Boolean> DATA_NO_GRAVITY;
27+
private final static EntityDataAccessor<Boolean> DATA_SILENT;
28+
29+
static {
30+
try {
31+
final Field entityCounterField = Entity.class.getDeclaredField(ObfuscatedFieldNames.ENTITY_COUNTER);
32+
entityCounterField.setAccessible(true);
33+
ENTITY_COUNTER = (AtomicInteger) entityCounterField.get(null);
34+
final Field dataNoGravityField = Entity.class.getDeclaredField(ObfuscatedFieldNames.DATA_NO_GRAVITY);
35+
dataNoGravityField.setAccessible(true);
36+
DATA_NO_GRAVITY = forceCast(dataNoGravityField.get(null));
37+
final Field dataSilentField = Entity.class.getDeclaredField(ObfuscatedFieldNames.DATA_SILENT);
38+
dataSilentField.setAccessible(true);
39+
DATA_SILENT = forceCast(dataSilentField.get(null));
40+
} catch (ReflectiveOperationException e) {
41+
throw new RuntimeException(e);
42+
}
43+
}
44+
45+
protected final int entityId;
46+
47+
public FakeEntityImpl() {
48+
entityId = ENTITY_COUNTER.incrementAndGet();
49+
}
50+
51+
@SuppressWarnings("unchecked")
52+
protected static <T> T forceCast(Object o) {
53+
return (T) o;
54+
}
55+
56+
@Override
57+
public int getEntityId() {
58+
return entityId;
59+
}
60+
61+
protected void sendPacket(Packet<?> packet, Iterable<Player> receivers) {
62+
for (Player receiver : receivers) {
63+
((CraftPlayer) receiver).getHandle().connection.send(packet);
64+
}
65+
}
66+
67+
@Override
68+
public void spawn(UUID uuid, Location location, Iterable<Player> receivers) {
69+
final ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket(
70+
entityId,
71+
uuid,
72+
location.getX(),
73+
location.getY() + getSpawnOffSet(),
74+
location.getZ(),
75+
0f,
76+
0f,
77+
getEntityType(),
78+
0,
79+
Vec3.ZERO,
80+
0d
81+
);
82+
sendPacket(spawnPacket, receivers);
83+
}
84+
85+
@Override
86+
public void remove(Iterable<Player> receivers) {
87+
final ClientboundRemoveEntitiesPacket removePacket = new ClientboundRemoveEntitiesPacket(entityId);
88+
sendPacket(removePacket, receivers);
89+
}
90+
91+
protected void sendData(Iterable<Player> receivers, T data) {
92+
// Create packet
93+
final List<SynchedEntityData.DataValue<?>> packedItems = new LinkedList<>();
94+
final ClientboundSetEntityDataPacket dataPacket = new ClientboundSetEntityDataPacket(entityId, packedItems);
95+
96+
// Setup data
97+
packedItems.add(SynchedEntityData.DataValue.create(DATA_NO_GRAVITY, true));
98+
packedItems.add(SynchedEntityData.DataValue.create(DATA_SILENT, true));
99+
addSpecificData(packedItems, data);
100+
101+
// Send packet
102+
sendPacket(dataPacket, receivers);
103+
}
104+
105+
protected abstract EntityType<?> getEntityType();
106+
107+
protected float getSpawnOffSet() {
108+
return 0f;
109+
}
110+
111+
protected abstract int getDataItemCount();
112+
113+
protected abstract void addSpecificData(List<SynchedEntityData.DataValue<?>> packedItems, T data);
114+
115+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package de.epiceric.shopchest.nms.v1_21_R1;
2+
3+
import de.epiceric.shopchest.nms.FakeItem;
4+
import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket;
5+
import net.minecraft.network.syncher.EntityDataAccessor;
6+
import net.minecraft.network.syncher.SynchedEntityData;
7+
import net.minecraft.world.entity.EntityType;
8+
import net.minecraft.world.entity.item.ItemEntity;
9+
import net.minecraft.world.phys.Vec3;
10+
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack;
11+
import org.bukkit.entity.Player;
12+
import org.bukkit.inventory.ItemStack;
13+
14+
import java.lang.reflect.Field;
15+
import java.util.List;
16+
17+
public class FakeItemImpl extends FakeEntityImpl<ItemStack> implements FakeItem {
18+
19+
private final static EntityDataAccessor<net.minecraft.world.item.ItemStack> DATA_ITEM;
20+
21+
static {
22+
try {
23+
final Field dataItemField = ItemEntity.class.getDeclaredField(ObfuscatedFieldNames.DATA_ITEM);
24+
dataItemField.setAccessible(true);
25+
DATA_ITEM = forceCast(dataItemField.get(null));
26+
} catch (ReflectiveOperationException e) {
27+
throw new RuntimeException(e);
28+
}
29+
}
30+
31+
public FakeItemImpl() {
32+
super();
33+
}
34+
35+
@Override
36+
public void sendData(ItemStack item, Iterable<Player> receivers) {
37+
sendData(receivers, item);
38+
}
39+
40+
@Override
41+
public void resetVelocity(Iterable<Player> receivers) {
42+
final ClientboundSetEntityMotionPacket velocityPacket = new ClientboundSetEntityMotionPacket(entityId, Vec3.ZERO);
43+
sendPacket(velocityPacket, receivers);
44+
}
45+
46+
@Override
47+
protected EntityType<?> getEntityType() {
48+
return EntityType.ITEM;
49+
}
50+
51+
@Override
52+
protected int getDataItemCount() {
53+
return 1;
54+
}
55+
56+
@Override
57+
protected void addSpecificData(List<SynchedEntityData.DataValue<?>> packedItems, ItemStack data) {
58+
packedItems.add(SynchedEntityData.DataValue.create(DATA_ITEM, CraftItemStack.asNMSCopy(data)));
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package de.epiceric.shopchest.nms.v1_21_R1;
2+
3+
public class ObfuscatedFieldNames {
4+
5+
// Entity
6+
public static final String ENTITY_COUNTER = "c";
7+
public static final String DATA_NO_GRAVITY = "aT";
8+
public static final String DATA_SILENT = "aS";
9+
public static final String DATA_SHARED_FLAGS_ID = "ap";
10+
public static final String DATA_CUSTOM_NAME = "aQ";
11+
public static final String DATA_CUSTOM_NAME_VISIBLE = "aR";
12+
// ItemEntity
13+
public static final String DATA_ITEM = "d";
14+
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package de.epiceric.shopchest.nms.v1_21_R1;
2+
3+
import de.epiceric.shopchest.nms.FakeArmorStand;
4+
import de.epiceric.shopchest.nms.FakeItem;
5+
import de.epiceric.shopchest.nms.Platform;
6+
7+
public class PlatformImpl implements Platform {
8+
9+
@Override
10+
public FakeArmorStand createFakeArmorStand() {
11+
return new FakeArmorStandImpl();
12+
}
13+
14+
@Override
15+
public FakeItem createFakeItem() {
16+
return new FakeItemImpl();
17+
}
18+
19+
}

plugin/src/main/java/de/epiceric/shopchest/nms/PlatformLoader.java

+2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ private Platform getSpecificPlatform(String mappingsVersion) {
100100
case "ad1a88fd7eaf2277f2507bf34d7b994c": // 1.20.5 (Replaced by 1.20.6)
101101
case "ee13f98a43b9c5abffdcc0bb24154460": // 1.20.6 (v1_20_R4)
102102
return new de.epiceric.shopchest.nms.v1_20_R4.PlatformImpl();
103+
case "229d7afc75b70a6c388337687ac4da1f": // 1.21 (v1_21_R1)
104+
return new de.epiceric.shopchest.nms.v1_21_R1.PlatformImpl();
103105
default:
104106
return null;
105107
}

0 commit comments

Comments
 (0)