Skip to content

Commit 40ac36d

Browse files
authored
Add v1_21_R6 NMS for Spigot and Paper (#357)
1 parent 853462d commit 40ac36d

37 files changed

+1992
-37
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
plugins {
2+
id("io.papermc.paperweight.userdev") version "2.0.0-beta.18"
3+
}
4+
5+
dependencies {
6+
paperweight.paperDevBundle("1.21.9-R0.1-SNAPSHOT")
7+
}
8+
9+
compileJava {
10+
sourceCompatibility = JavaVersion.VERSION_21
11+
targetCompatibility = JavaVersion.VERSION_21
12+
}
13+
14+
java {
15+
toolchain {
16+
languageVersion = JavaLanguageVersion.of(21)
17+
}
18+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package eu.decentsoftware.holograms.nms.paper_v1_21_R6;
2+
3+
import eu.decentsoftware.holograms.nms.api.renderer.NmsClickableHologramRenderer;
4+
import eu.decentsoftware.holograms.shared.DecentPosition;
5+
import org.bukkit.entity.EntityType;
6+
import org.bukkit.entity.Player;
7+
8+
class ClickableHologramRenderer implements NmsClickableHologramRenderer {
9+
10+
private final int entityId;
11+
12+
ClickableHologramRenderer(EntityIdGenerator entityIdGenerator) {
13+
this.entityId = entityIdGenerator.getFreeEntityId();
14+
}
15+
16+
@Override
17+
public void display(Player player, DecentPosition position) {
18+
EntityPacketsBuilder.create()
19+
.withSpawnEntity(entityId, EntityType.ARMOR_STAND, position)
20+
.withEntityMetadata(entityId, EntityMetadataBuilder.create()
21+
.withInvisible()
22+
.withNoGravity()
23+
.withArmorStandProperties(false, false)
24+
.toWatchableObjects())
25+
.sendTo(player);
26+
}
27+
28+
@Override
29+
public void move(Player player, DecentPosition position) {
30+
EntityPacketsBuilder.create()
31+
.withTeleportEntity(entityId, position)
32+
.sendTo(player);
33+
}
34+
35+
@Override
36+
public void hide(Player player) {
37+
EntityPacketsBuilder.create()
38+
.withRemoveEntity(entityId)
39+
.sendTo(player);
40+
}
41+
42+
@Override
43+
public int getEntityId() {
44+
return entityId;
45+
}
46+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package eu.decentsoftware.holograms.nms.paper_v1_21_R6;
2+
3+
import eu.decentsoftware.holograms.nms.api.NmsHologramPartData;
4+
import eu.decentsoftware.holograms.nms.api.renderer.NmsEntityHologramRenderer;
5+
import eu.decentsoftware.holograms.shared.DecentPosition;
6+
import org.bukkit.entity.EntityType;
7+
import org.bukkit.entity.Player;
8+
9+
class EntityHologramRenderer implements NmsEntityHologramRenderer {
10+
11+
private final int entityId;
12+
13+
EntityHologramRenderer(EntityIdGenerator entityIdGenerator) {
14+
this.entityId = entityIdGenerator.getFreeEntityId();
15+
}
16+
17+
@Override
18+
public void display(Player player, NmsHologramPartData<EntityType> data) {
19+
DecentPosition position = data.getPosition();
20+
EntityType content = data.getContent();
21+
DecentPosition offsetPosition = offsetPosition(position);
22+
EntityPacketsBuilder.create()
23+
.withSpawnEntity(entityId, content, offsetPosition)
24+
.withEntityMetadata(entityId, EntityMetadataBuilder.create()
25+
.withSilent()
26+
.withNoGravity()
27+
.toWatchableObjects())
28+
.sendTo(player);
29+
}
30+
31+
@Override
32+
public void updateContent(Player player, NmsHologramPartData<EntityType> data) {
33+
hide(player);
34+
display(player, data);
35+
}
36+
37+
@Override
38+
public void move(Player player, NmsHologramPartData<EntityType> data) {
39+
hide(player);
40+
display(player, data);
41+
}
42+
43+
@Override
44+
public void hide(Player player) {
45+
EntityPacketsBuilder.create()
46+
.withRemoveEntity(entityId)
47+
.sendTo(player);
48+
}
49+
50+
@Override
51+
public double getHeight(NmsHologramPartData<EntityType> data) {
52+
return EntityTypeRegistry.getEntityTypeHeight(data.getContent());
53+
}
54+
55+
@Override
56+
public int[] getEntityIds() {
57+
return new int[]{entityId};
58+
}
59+
60+
private DecentPosition offsetPosition(DecentPosition position) {
61+
return position.subtractY(0.25d);
62+
}
63+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package eu.decentsoftware.holograms.nms.paper_v1_21_R6;
2+
3+
import eu.decentsoftware.holograms.nms.api.DecentHologramsNmsException;
4+
import eu.decentsoftware.holograms.shared.reflect.ReflectField;
5+
import net.minecraft.world.entity.Entity;
6+
7+
import java.util.concurrent.atomic.AtomicInteger;
8+
9+
class EntityIdGenerator {
10+
11+
private static final ReflectField<AtomicInteger> ENTITY_COUNT_FIELD = new ReflectField<>(Entity.class,"ENTITY_COUNTER");
12+
13+
int getFreeEntityId() {
14+
try {
15+
/*
16+
* We are getting the new entity ids the same way as the server does. This is to ensure
17+
* that the ids are unique and don't conflict with any other entities.
18+
*/
19+
AtomicInteger entityCount = ENTITY_COUNT_FIELD.get(null);
20+
return entityCount.incrementAndGet();
21+
} catch (Exception e) {
22+
throw new DecentHologramsNmsException("Failed to get new entity ID", e);
23+
}
24+
}
25+
26+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package eu.decentsoftware.holograms.nms.paper_v1_21_R6;
2+
3+
import com.google.common.base.Strings;
4+
import net.minecraft.network.chat.Component;
5+
import net.minecraft.network.syncher.SynchedEntityData;
6+
import org.bukkit.craftbukkit.inventory.CraftItemStack;
7+
import org.bukkit.craftbukkit.util.CraftChatMessage;
8+
import org.bukkit.inventory.ItemStack;
9+
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
import java.util.Optional;
13+
14+
class EntityMetadataBuilder {
15+
16+
private final List<SynchedEntityData.DataItem<?>> watchableObjects;
17+
18+
private EntityMetadataBuilder() {
19+
this.watchableObjects = new ArrayList<>();
20+
}
21+
22+
List<SynchedEntityData.DataItem<?>> toWatchableObjects() {
23+
return watchableObjects;
24+
}
25+
26+
EntityMetadataBuilder withInvisible() {
27+
/*
28+
* Entity Properties:
29+
* 0x01 - On Fire
30+
* 0x02 - Crouched
31+
* 0x08 - Sprinting
32+
* 0x10 - Swimming
33+
* 0x20 - Invisible
34+
* 0x40 - Has glowing effect
35+
* 0x80 - If flying with an elytra
36+
*/
37+
38+
watchableObjects.add(EntityMetadataType.ENTITY_PROPERTIES.construct((byte) 0x20));
39+
return this;
40+
}
41+
42+
EntityMetadataBuilder withArmorStandProperties(boolean small, boolean marker) {
43+
/*
44+
* Armor Stand Properties:
45+
* 0x01 - Small
46+
* 0x02 - Unused
47+
* 0x04 - Has Arms
48+
* 0x08 - Remove Baseplate
49+
* 0x10 - Marker (Zero bounding box)
50+
*/
51+
52+
byte data = 0x08; // Always Remove Baseplate
53+
if (small) {
54+
data |= 0x01;
55+
}
56+
if (marker) {
57+
data |= 0x10;
58+
}
59+
60+
watchableObjects.add(EntityMetadataType.ARMOR_STAND_PROPERTIES.construct(data));
61+
return this;
62+
}
63+
64+
EntityMetadataBuilder withCustomName(String customName) {
65+
Component Component = CraftChatMessage.fromStringOrNull(customName);
66+
Optional<Component> optionalComponent = Optional.ofNullable(Component);
67+
watchableObjects.add(EntityMetadataType.ENTITY_CUSTOM_NAME.construct(optionalComponent));
68+
boolean visible = !Strings.isNullOrEmpty(customName);
69+
watchableObjects.add(EntityMetadataType.ENTITY_CUSTOM_NAME_VISIBLE.construct(visible));
70+
return this;
71+
}
72+
73+
EntityMetadataBuilder withItemStack(ItemStack itemStack) {
74+
watchableObjects.add(EntityMetadataType.ITEM_STACK.construct(CraftItemStack.asNMSCopy(itemStack)));
75+
return this;
76+
}
77+
78+
EntityMetadataBuilder withSilent() {
79+
watchableObjects.add(EntityMetadataType.ENTITY_SILENT.construct(true));
80+
return this;
81+
}
82+
83+
EntityMetadataBuilder withNoGravity() {
84+
watchableObjects.add(EntityMetadataType.ENTITY_HAS_NO_GRAVITY.construct(true));
85+
return this;
86+
}
87+
88+
static EntityMetadataBuilder create() {
89+
return new EntityMetadataBuilder();
90+
}
91+
92+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package eu.decentsoftware.holograms.nms.paper_v1_21_R6;
2+
3+
import eu.decentsoftware.holograms.shared.reflect.ReflectUtil;
4+
import net.minecraft.network.chat.Component;
5+
import net.minecraft.network.syncher.EntityDataAccessor;
6+
import net.minecraft.network.syncher.SynchedEntityData;
7+
import net.minecraft.world.entity.Entity;
8+
import net.minecraft.world.entity.decoration.ArmorStand;
9+
import net.minecraft.world.entity.item.ItemEntity;
10+
import net.minecraft.world.item.ItemStack;
11+
12+
import java.util.Optional;
13+
14+
class EntityMetadataType<T> {
15+
16+
private static final EntityDataAccessor<Byte> ENTITY_PROPERTIES_OBJECT
17+
= ReflectUtil.getFieldValue(Entity.class, "DATA_SHARED_FLAGS_ID");
18+
private static final EntityDataAccessor<Optional<Component>> ENTITY_CUSTOM_NAME_OBJECT
19+
= ReflectUtil.getFieldValue(Entity.class, "DATA_CUSTOM_NAME");
20+
private static final EntityDataAccessor<Boolean> ENTITY_CUSTOM_NAME_VISIBLE_OBJECT
21+
= ReflectUtil.getFieldValue(Entity.class, "DATA_CUSTOM_NAME_VISIBLE");
22+
private static final EntityDataAccessor<Boolean> ENTITY_SILENT_OBJECT
23+
= ReflectUtil.getFieldValue(Entity.class, "DATA_SILENT");
24+
private static final EntityDataAccessor<Boolean> ENTITY_HAS_NO_GRAVITY_OBJECT
25+
= ReflectUtil.getFieldValue(Entity.class, "DATA_NO_GRAVITY");
26+
private static final EntityDataAccessor<Byte> ARMOR_STAND_PROPERTIES_OBJECT
27+
= ReflectUtil.getFieldValue(ArmorStand.class, "DATA_CLIENT_FLAGS");
28+
private static final EntityDataAccessor<ItemStack> ITEM_STACK_OBJECT
29+
= ReflectUtil.getFieldValue(ItemEntity.class, "DATA_ITEM");
30+
31+
static final EntityMetadataType<Byte> ENTITY_PROPERTIES = new EntityMetadataType<>(ENTITY_PROPERTIES_OBJECT);
32+
static final EntityMetadataType<Optional<Component>> ENTITY_CUSTOM_NAME = new EntityMetadataType<>(ENTITY_CUSTOM_NAME_OBJECT);
33+
static final EntityMetadataType<Boolean> ENTITY_CUSTOM_NAME_VISIBLE = new EntityMetadataType<>(ENTITY_CUSTOM_NAME_VISIBLE_OBJECT);
34+
static final EntityMetadataType<Boolean> ENTITY_SILENT = new EntityMetadataType<>(ENTITY_SILENT_OBJECT);
35+
static final EntityMetadataType<Boolean> ENTITY_HAS_NO_GRAVITY = new EntityMetadataType<>(ENTITY_HAS_NO_GRAVITY_OBJECT);
36+
static final EntityMetadataType<Byte> ARMOR_STAND_PROPERTIES = new EntityMetadataType<>(ARMOR_STAND_PROPERTIES_OBJECT);
37+
static final EntityMetadataType<ItemStack> ITEM_STACK = new EntityMetadataType<>(ITEM_STACK_OBJECT);
38+
39+
private final EntityDataAccessor<T> EntityDataAccessor;
40+
41+
private EntityMetadataType(EntityDataAccessor<T> EntityDataAccessor) {
42+
this.EntityDataAccessor = EntityDataAccessor;
43+
}
44+
45+
SynchedEntityData.DataItem<T> construct(T value) {
46+
return new SynchedEntityData.DataItem<>(EntityDataAccessor, value);
47+
}
48+
49+
}

0 commit comments

Comments
 (0)