From bad149261b59a4c33589977e38ff7e4c2f91dc4a Mon Sep 17 00:00:00 2001
From: Aya <31237389+tal5@users.noreply.github.com>
Date: Wed, 25 Mar 2026 14:19:54 +0000
Subject: [PATCH 1/7] 26.1 part 1: copy over 1.21 module
---
v26_1/pom.xml | 81 ++
.../denizen/nms/v26_1/Handler.java | 423 +++++++++
.../nms/v26_1/ReflectionMappingsInfo.java | 130 +++
.../v26_1/helpers/AdvancementHelperImpl.java | 196 ++++
.../v26_1/helpers/AnimationHelperImpl.java | 48 +
.../nms/v26_1/helpers/BlockHelperImpl.java | 253 +++++
.../nms/v26_1/helpers/ChunkHelperImpl.java | 119 +++
.../v26_1/helpers/CustomEntityHelperImpl.java | 149 +++
.../v26_1/helpers/EnchantmentHelperImpl.java | 195 ++++
.../v26_1/helpers/EntityDataNameMapper.java | 484 ++++++++++
.../nms/v26_1/helpers/EntityHelperImpl.java | 870 ++++++++++++++++++
.../nms/v26_1/helpers/FishingHelperImpl.java | 157 ++++
.../nms/v26_1/helpers/ItemHelperImpl.java | 779 ++++++++++++++++
.../denizen/nms/v26_1/helpers/NBTAdapter.java | 143 +++
.../nms/v26_1/helpers/PacketHelperImpl.java | 435 +++++++++
.../nms/v26_1/helpers/PlayerHelperImpl.java | 509 ++++++++++
.../nms/v26_1/helpers/WorldHelperImpl.java | 111 +++
.../denizen/nms/v26_1/impl/BiomeNMSImpl.java | 242 +++++
.../v26_1/impl/ImprovedOfflinePlayerImpl.java | 171 ++++
.../nms/v26_1/impl/ProfileEditorImpl.java | 169 ++++
.../denizen/nms/v26_1/impl/SidebarImpl.java | 103 +++
.../nms/v26_1/impl/blocks/BlockLightImpl.java | 264 ++++++
.../impl/entities/CraftFakeArrowImpl.java | 26 +
.../impl/entities/CraftFakePlayerImpl.java | 66 ++
.../entities/CraftItemProjectileImpl.java | 117 +++
.../impl/entities/EntityFakeArrowImpl.java | 43 +
.../impl/entities/EntityFakePlayerImpl.java | 43 +
.../entities/EntityItemProjectileImpl.java | 106 +++
.../impl/network/fakes/FakeChannelImpl.java | 80 ++
.../network/fakes/FakeNetworkManagerImpl.java | 16 +
.../fakes/FakePlayerConnectionImpl.java | 20 +
.../handlers/AbstractListenerPlayInImpl.java | 671 ++++++++++++++
.../handlers/DenizenNetworkManagerImpl.java | 580 ++++++++++++
.../handlers/DenizenPacketListenerImpl.java | 121 +++
.../network/handlers/FakeBlockHelper.java | 168 ++++
.../packet/ActionBarEventPacketHandlers.java | 39 +
.../handlers/packet/AttachPacketHandlers.java | 310 +++++++
.../packet/BlockLightPacketHandlers.java | 27 +
.../DenizenPacketHandlerPacketHandlers.java | 47 +
.../packet/DisguisePacketHandlers.java | 160 ++++
.../packet/EntityMetadataPacketHandlers.java | 92 ++
.../packet/FakeBlocksPacketHandlers.java | 112 +++
.../packet/FakeEquipmentPacketHandlers.java | 138 +++
.../packet/FakePlayerPacketHandlers.java | 29 +
.../packet/HiddenEntitiesPacketHandlers.java | 69 ++
.../packet/HideParticlesPacketHandlers.java | 31 +
.../PlayerHearsSoundEventPacketHandlers.java | 39 +
.../TablistUpdateEventPacketHandlers.java | 126 +++
.../PacketInResourcePackStatusImpl.java | 18 +
.../packets/PacketInSteerVehicleImpl.java | 33 +
.../network/packets/PacketOutChatImpl.java | 50 +
51 files changed, 9408 insertions(+)
create mode 100644 v26_1/pom.xml
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/Handler.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/ReflectionMappingsInfo.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/AdvancementHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/AnimationHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/BlockHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ChunkHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/CustomEntityHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EnchantmentHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EntityDataNameMapper.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EntityHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/NBTAdapter.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/SidebarImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakeArrowImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakePlayerImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftItemProjectileImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakeArrowImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakePlayerImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeChannelImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeNetworkManagerImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakePlayerConnectionImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenPacketListenerImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/ActionBarEventPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/BlockLightPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DisguisePacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/EntityMetadataPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakePlayerPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HideParticlesPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInResourcePackStatusImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInSteerVehicleImpl.java
create mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketOutChatImpl.java
diff --git a/v26_1/pom.xml b/v26_1/pom.xml
new file mode 100644
index 0000000000..1449c8e8a8
--- /dev/null
+++ b/v26_1/pom.xml
@@ -0,0 +1,81 @@
+
+
+ 4.0.0
+
+ com.denizenscript
+ denizen-v1_21
+ 1.3.1-SNAPSHOT
+
+
+
+ com.denizenscript
+ denizen
+ ${project.version}
+ compile
+ true
+
+
+ org.spigotmc
+ spigot-api
+ 1.21.11-R0.2-SNAPSHOT
+ provided
+
+
+ org.spigotmc
+ spigot
+ 1.21.11-R0.2-SNAPSHOT
+ remapped-mojang
+ provided
+
+
+
+
+
+
+ net.md-5
+ specialsource-maven-plugin
+ 2.0.2
+
+
+ package
+
+ remap
+
+ remap-obf
+
+ org.spigotmc:minecraft-server:1.21.11-R0.2-SNAPSHOT:txt:maps-mojang
+ true
+ org.spigotmc:spigot:1.21.11-R0.2-SNAPSHOT:jar:remapped-mojang
+ true
+ remapped-obf
+
+
+
+ package
+
+ remap
+
+ remap-spigot
+
+ ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar
+ org.spigotmc:minecraft-server:1.21.11-R0.2-SNAPSHOT:csrg:maps-spigot
+ org.spigotmc:spigot:1.21.11-R0.2-SNAPSHOT:jar:remapped-obf
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.10.1
+
+ 16
+ 16
+
+
+
+
+
+
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/Handler.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/Handler.java
new file mode 100644
index 0000000000..01ffc5fac9
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/Handler.java
@@ -0,0 +1,423 @@
+package com.denizenscript.denizen.nms.v1_21;
+
+import com.denizenscript.denizen.Denizen;
+import com.denizenscript.denizen.nms.NMSHandler;
+import com.denizenscript.denizen.nms.abstracts.BiomeNMS;
+import com.denizenscript.denizen.nms.abstracts.BlockLight;
+import com.denizenscript.denizen.nms.abstracts.ProfileEditor;
+import com.denizenscript.denizen.nms.abstracts.Sidebar;
+import com.denizenscript.denizen.nms.util.PlayerProfile;
+import com.denizenscript.denizen.nms.v1_21.helpers.*;
+import com.denizenscript.denizen.nms.v1_21.impl.BiomeNMSImpl;
+import com.denizenscript.denizen.nms.v1_21.impl.ProfileEditorImpl;
+import com.denizenscript.denizen.nms.v1_21.impl.SidebarImpl;
+import com.denizenscript.denizen.nms.v1_21.impl.blocks.BlockLightImpl;
+import com.denizenscript.denizen.objects.ItemTag;
+import com.denizenscript.denizen.objects.LocationTag;
+import com.denizenscript.denizen.objects.MaterialTag;
+import com.denizenscript.denizen.objects.properties.item.ItemRawNBT;
+import com.denizenscript.denizen.utilities.FormattedTextHelper;
+import com.denizenscript.denizen.utilities.PaperAPITools;
+import com.denizenscript.denizencore.objects.ObjectTag;
+import com.denizenscript.denizencore.objects.core.ElementTag;
+import com.denizenscript.denizencore.objects.core.MapTag;
+import com.denizenscript.denizencore.objects.core.QuaternionTag;
+import com.denizenscript.denizencore.scripts.commands.core.ReflectionSetCommand;
+import com.denizenscript.denizencore.utilities.CoreConfiguration;
+import com.denizenscript.denizencore.utilities.CoreUtilities;
+import com.denizenscript.denizencore.utilities.ReflectionHelper;
+import com.denizenscript.denizencore.utilities.debugging.Debug;
+import com.denizenscript.denizencore.utilities.debugging.DebugInternals;
+import com.google.common.collect.Iterables;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.serialization.DynamicOps;
+import net.kyori.adventure.nbt.CompoundBinaryTag;
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.chat.BaseComponent;
+import net.minecraft.SharedConstants;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.Rotations;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.nbt.ByteArrayTag;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.NbtOps;
+import net.minecraft.nbt.StringTag;
+import net.minecraft.network.chat.Component;
+import net.minecraft.resources.Identifier;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.util.ProblemReporter;
+import net.minecraft.world.BossEvent;
+import net.minecraft.world.Container;
+import net.minecraft.world.Nameable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.inventory.AbstractContainerMenu;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.biome.Biome;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.storage.TagValueInput;
+import net.minecraft.world.level.storage.TagValueOutput;
+import net.minecraft.world.level.storage.ValueInput;
+import net.minecraft.world.level.storage.ValueOutput;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.NamespacedKey;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.boss.BossBar;
+import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry;
+import org.bukkit.craftbukkit.v1_21_R7.CraftServer;
+import org.bukkit.craftbukkit.v1_21_R7.CraftWorld;
+import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData;
+import org.bukkit.craftbukkit.v1_21_R7.boss.CraftBossBar;
+import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer;
+import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventory;
+import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventoryCustom;
+import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventoryView;
+import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.v1_21_R7.legacy.FieldRename;
+import org.bukkit.craftbukkit.v1_21_R7.persistence.CraftPersistentDataContainer;
+import org.bukkit.craftbukkit.v1_21_R7.util.*;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryView;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.joml.Quaternionf;
+import org.joml.Vector3f;
+import org.spigotmc.AsyncCatcher;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class Handler extends NMSHandler {
+
+ public Handler() {
+ advancementHelper = new AdvancementHelperImpl();
+ animationHelper = new AnimationHelperImpl();
+ blockHelper = new BlockHelperImpl();
+ chunkHelper = new ChunkHelperImpl();
+ customEntityHelper = new CustomEntityHelperImpl();
+ entityHelper = new EntityHelperImpl();
+ fishingHelper = new FishingHelperImpl();
+ itemHelper = new ItemHelperImpl();
+ packetHelper = new PacketHelperImpl();
+ playerHelper = new PlayerHelperImpl();
+ worldHelper = new WorldHelperImpl();
+ enchantmentHelper = new EnchantmentHelperImpl();
+
+ registerConversion(ItemTag.class, ItemStack.class, item -> CraftItemStack.asNMSCopy(item.getItemStack()));
+ registerConversion(ElementTag.class, Component.class, element -> componentToNMS(FormattedTextHelper.parse(element.asString(), ChatColor.WHITE)));
+ registerConversion(MaterialTag.class, BlockState.class, material -> ((CraftBlockData) material.getModernData()).getState());
+ registerConversion(LocationTag.class, Rotations.class, location -> new Rotations((float) location.getX(), (float) location.getY(), (float) location.getZ()));
+ registerConversion(LocationTag.class, BlockPos.class, CraftLocation::toBlockPosition);
+ registerConversion(MapTag.class, CompoundTag.class, map -> {
+ CompoundBinaryTag compoundTag = (CompoundBinaryTag) ItemRawNBT.convertObjectToNbt(map, CoreUtilities.noDebugContext, "(item).");
+ return compoundTag != null ? NBTAdapter.toNMS(compoundTag) : null;
+ });
+ registerConversion(LocationTag.class, Vector3f.class, location -> new Vector3f((float) location.getX(), (float) location.getY(), (float) location.getZ()));
+ registerConversion(QuaternionTag.class, Quaternionf.class, quaternion -> new Quaternionf(quaternion.x, quaternion.y, quaternion.z, quaternion.w));
+ }
+
+ public static
void registerConversion(Class denizenType, Class javaType, Function convertor) {
+ ReflectionSetCommand.typeConverters.put(javaType, objectTag -> {
+ DT denizenObject = objectTag.asType(denizenType, CoreUtilities.noDebugContext);
+ return denizenObject != null ? convertor.apply(denizenObject) : null;
+ });
+ }
+
+ private final ProfileEditor profileEditor = new ProfileEditorImpl();
+
+ private boolean wasAsyncCatcherEnabled;
+
+ @Override
+ public void disableAsyncCatcher() {
+ wasAsyncCatcherEnabled = AsyncCatcher.enabled;
+ AsyncCatcher.enabled = false;
+ }
+
+ @Override
+ public void undisableAsyncCatcher() {
+ AsyncCatcher.enabled = wasAsyncCatcherEnabled;
+ }
+
+ @Override
+ public boolean isExactServerVersionMatch() {
+ return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("1.21.11") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e3cd927e07e6ff434793a0474c51b2b9");
+ }
+
+ @Override
+ public double[] getRecentTps() {
+ return ((CraftServer) Bukkit.getServer()).getServer().recentTps;
+ }
+
+ @Override
+ public Sidebar createSidebar(Player player) {
+ return new SidebarImpl(player);
+ }
+
+ @Override
+ public BlockLight createBlockLight(Location location, int lightLevel, long ticks) {
+ return BlockLightImpl.createLight(location, lightLevel, ticks);
+ }
+
+ @Override
+ public PlayerProfile fillPlayerProfile(PlayerProfile playerProfile) {
+ if (playerProfile == null) {
+ return null;
+ }
+ if (playerProfile.getName() == null && playerProfile.getUniqueId() == null) {
+ return playerProfile; // Cannot fill without lookup data
+ }
+ if (playerProfile.hasTexture() && playerProfile.hasTextureSignature() && playerProfile.getName() != null && playerProfile.getUniqueId() != null) {
+ return playerProfile; // Already filled
+ }
+ try {
+ GameProfile profile = null;
+ MinecraftServer minecraftServer = ((CraftServer) Bukkit.getServer()).getServer();
+ if (playerProfile.getUniqueId() != null) {
+ profile = minecraftServer.services().nameToIdCache().get(playerProfile.getUniqueId()).map(result -> new GameProfile(result.id(), result.name())).orElse(null);
+ }
+ if (profile == null && playerProfile.getName() != null) {
+ profile = minecraftServer.services().nameToIdCache().get(playerProfile.getName()).map(result -> new GameProfile(result.id(), result.name())).orElse(null);
+ }
+ if (profile == null) {
+ profile = ProfileEditorImpl.getGameProfileNoProperties(playerProfile);
+ }
+ Property textures = profile.properties().containsKey("textures") ? Iterables.getFirst(profile.properties().get("textures"), null) : null;
+ if (textures == null || !textures.hasSignature() || profile.name() == null || profile.id() == null) {
+ profile = minecraftServer.services().profileResolver().fetchById(profile.id()).orElse(null);
+ if (profile == null) {
+ return null;
+ }
+ textures = profile.properties().containsKey("textures") ? Iterables.getFirst(profile.properties().get("textures"), null) : null;
+ }
+ return new PlayerProfile(profile.name(), profile.id(), textures == null ? null : textures.value(), textures == null ? null : textures.signature());
+ }
+ catch (Exception e) {
+ if (CoreConfiguration.debugVerbose) {
+ Debug.echoError(e);
+ }
+ }
+ return null;
+ }
+
+ public static MethodHandle PAPER_INVENTORY_TITLE_GETTER;
+
+ @Override
+ public String getTitle(Inventory inventory) {
+ Container nms = ((CraftInventory) inventory).getInventory();
+ if (inventory instanceof CraftInventoryCustom && Denizen.supportsPaper) {
+ try {
+ if (PAPER_INVENTORY_TITLE_GETTER == null) {
+ PAPER_INVENTORY_TITLE_GETTER = ReflectionHelper.getMethodHandle(nms.getClass(), "title");
+ }
+ return PaperAPITools.instance.parseComponent(PAPER_INVENTORY_TITLE_GETTER.invoke(nms));
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+ if (nms instanceof Nameable) {
+ return CraftChatMessage.fromComponent(((Nameable) nms).getDisplayName());
+ }
+ else if (MINECRAFT_INVENTORY.isInstance(nms)) {
+ try {
+ return (String) INVENTORY_TITLE.get(nms);
+ }
+ catch (IllegalAccessException e) {
+ Debug.echoError(e);
+ }
+ }
+ return "Chest";
+ }
+
+ public static MethodHandle AbstractContainerMenu_title_SETTER = ReflectionHelper.getFinalSetter(AbstractContainerMenu.class, "title");
+
+ @Override
+ public void setInventoryTitle(InventoryView view, String title) {
+ AbstractContainerMenu menu = ((CraftInventoryView) view).getHandle();
+ try {
+ AbstractContainerMenu_title_SETTER.invoke(menu, componentToNMS(FormattedTextHelper.parse(title, ChatColor.DARK_GRAY)));
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ public static final Class MINECRAFT_INVENTORY;
+ public static final Field INVENTORY_TITLE;
+ public static final Field ENTITY_BUKKITYENTITY = ReflectionHelper.getFields(Entity.class).get("bukkitEntity");
+
+ static {
+ Class minecraftInv = null;
+ Field title = null;
+ try {
+ for (Class clzz : CraftInventoryCustom.class.getDeclaredClasses()) {
+ if (CoreUtilities.toLowerCase(clzz.getName()).contains("minecraftinventory")) { // MinecraftInventory.
+ minecraftInv = clzz;
+ title = clzz.getDeclaredField("title");
+ title.setAccessible(true);
+ break;
+ }
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ MINECRAFT_INVENTORY = minecraftInv;
+ INVENTORY_TITLE = title;
+ }
+
+ @Override
+ public PlayerProfile getPlayerProfile(Player player) {
+ GameProfile gameProfile = ((CraftPlayer) player).getProfile();
+ Property property = Iterables.getFirst(gameProfile.properties().get("textures"), null);
+ return new PlayerProfile(gameProfile.name(), gameProfile.id(),
+ property != null ? property.value() : null,
+ property != null ? property.signature() : null);
+ }
+
+ @Override
+ public ProfileEditor getProfileEditor() {
+ return profileEditor;
+ }
+
+ @Override
+ public List getBiomes(World world) {
+ ServerLevel level = ((CraftWorld) world).getHandle();
+ ArrayList output = new ArrayList<>();
+ for (Identifier key : level.registryAccess().lookupOrThrow(Registries.BIOME).keySet()) {
+ output.add(new BiomeNMSImpl(level, CraftNamespacedKey.fromMinecraft(key)));
+ }
+ return output;
+ }
+
+ @Override
+ public BiomeNMS getBiomeNMS(World world, NamespacedKey key) {
+ BiomeNMSImpl impl = new BiomeNMSImpl(((CraftWorld) world).getHandle(), key);
+ if (impl.biomeHolder == null) {
+ return null;
+ }
+ return impl;
+ }
+
+ @Override
+ public BiomeNMS getBiomeAt(Block block) {
+ // Based on CraftWorld source
+ ServerLevel level = ((CraftWorld) block.getWorld()).getHandle();
+ Holder biome = level.getNoiseBiome(block.getX() >> 2, block.getY() >> 2, block.getZ() >> 2);
+ Identifier key = level.registryAccess().lookupOrThrow(Registries.BIOME).getKey(biome.value());
+ return new BiomeNMSImpl(level, CraftNamespacedKey.fromMinecraft(key));
+ }
+
+ @Override
+ public ArrayList containerListFlags(PersistentDataContainer container, String prefix) {
+ prefix = "denizen:" + prefix;
+ ArrayList output = new ArrayList<>();
+ for (String key : ((CraftPersistentDataContainer) container).getRaw().keySet()) {
+ if (key.startsWith(prefix)) {
+ output.add(key.substring(prefix.length()));
+ }
+ }
+ return output;
+ }
+
+ @Override
+ public boolean containerHas(PersistentDataContainer container, String key) {
+ return ((CraftPersistentDataContainer) container).getRaw().containsKey(key);
+ }
+
+ @Override
+ public String containerGetString(PersistentDataContainer container, String key) {
+ net.minecraft.nbt.Tag base = ((CraftPersistentDataContainer) container).getRaw().get(key);
+ if (base instanceof StringTag) {
+ return base.asString().get();
+ }
+ else if (base instanceof ByteArrayTag) {
+ return new String(((ByteArrayTag) base).getAsByteArray(), StandardCharsets.UTF_8);
+ }
+ return null;
+ }
+
+ @Override
+ public UUID getBossbarUUID(BossBar bar) {
+ return ((CraftBossBar) bar).getHandle().getId();
+ }
+
+ public static MethodHandle BOSSBAR_ID_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(BossEvent.class, UUID.class);
+
+ @Override
+ public void setBossbarUUID(BossBar bar, UUID id) {
+ try {
+ BOSSBAR_ID_SETTER.invoke(((CraftBossBar) bar).getHandle(), id);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ public static BaseComponent[] componentToSpigot(Component nms) {
+ if (nms == null) {
+ return null;
+ }
+ return FormattedTextHelper.parseJson(CraftChatMessage.toJSON(nms));
+ }
+
+ public static Component componentToNMS(BaseComponent[] spigot) {
+ if (spigot == null) {
+ return null;
+ }
+ return CraftChatMessage.fromJSONOrNull(FormattedTextHelper.componentToJson(spigot));
+ }
+
+ public static final MethodHandle TAG_VALUE_OUTPUT_CONSTRUCTOR = ReflectionHelper.getConstructor(TagValueOutput.class, ProblemReporter.class, DynamicOps.class, CompoundTag.class);
+
+ public static CompoundTag useValueOutput(Consumer handler) {
+ ProblemReporter.Collector nmsProblemReporter = new ProblemReporter.Collector();
+ TagValueOutput nmsValueOutput = TagValueOutput.createWithContext(nmsProblemReporter, CraftRegistry.getMinecraftRegistry());
+ handler.accept(nmsValueOutput);
+ handleProblems(nmsProblemReporter);
+ return nmsValueOutput.buildResult();
+ }
+
+ public static CompoundTag useValueOutput(CompoundTag nmsExistingValue, Consumer handler) {
+ ProblemReporter.Collector nmsProblemReporter = new ProblemReporter.Collector();
+ TagValueOutput nmsValueOutput;
+ try {
+ nmsValueOutput = (TagValueOutput) TAG_VALUE_OUTPUT_CONSTRUCTOR.invoke(nmsProblemReporter, CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE), nmsExistingValue);
+ }
+ catch (Throwable e) {
+ Debug.echoError(e);
+ return nmsExistingValue;
+ }
+ handler.accept(nmsValueOutput);
+ handleProblems(nmsProblemReporter);
+ return nmsValueOutput.buildResult();
+ }
+
+ public static void useValueInput(CompoundTag nmsTag, Consumer handler) {
+ ProblemReporter.Collector nmsProblemReporter = new ProblemReporter.Collector();
+ ValueInput nmsValueInput = TagValueInput.create(nmsProblemReporter, CraftRegistry.getMinecraftRegistry(), nmsTag);
+ handler.accept(nmsValueInput);
+ handleProblems(nmsProblemReporter);
+ }
+
+ private static void handleProblems(ProblemReporter.Collector nmsProblemReporter) {
+ if (!nmsProblemReporter.isEmpty()) {
+ Debug.echoError(nmsProblemReporter.getTreeReport());
+ }
+ }
+
+ @Override
+ public String updateLegacyName(Class> type, String legacyName) {
+ return FieldRename.rename(ApiVersion.FIELD_NAME_PARITY, DebugInternals.getFullClassNameOpti(type).replace('.', '/'), legacyName);
+ }
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/ReflectionMappingsInfo.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/ReflectionMappingsInfo.java
new file mode 100644
index 0000000000..360d260ee4
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/ReflectionMappingsInfo.java
@@ -0,0 +1,130 @@
+package com.denizenscript.denizen.nms.v1_21;
+
+public class ReflectionMappingsInfo {
+
+ // Content generated by ReflectionMappingsGenerator - https://github.com/DenizenScript/ReflectionMappingsGenerator
+
+ // net.minecraft.world.level.block.state.BlockBehaviour
+ public static String BlockBehaviour_explosionResistance = "G";
+
+ // net.minecraft.core.MappedRegistry
+ public static String MappedRegistry_registrationInfos = "h";
+
+ // net.minecraft.world.entity.Entity
+ public static String Entity_onGround = "bc";
+ public static String Entity_DATA_SHARED_FLAGS_ID = "aA";
+ public static String Entity_DATA_CUSTOM_NAME = "bm";
+ public static String Entity_DATA_CUSTOM_NAME_VISIBLE = "bn";
+
+ // net.minecraft.world.entity.LivingEntity
+ public static String LivingEntity_attackStrengthTicker = "bz";
+ public static String LivingEntity_autoSpinAttackTicks = "bW";
+ public static String LivingEntity_setLivingEntityFlag_method = "c";
+
+ // net.minecraft.world.entity.player.Player
+ public static String Player_DATA_PLAYER_ABSORPTION_ID = "b";
+
+ // net.minecraft.server.level.ServerPlayer
+ public static String ServerPlayer_respawnConfig = "dr";
+
+ // net.minecraft.world.entity.monster.EnderMan
+ public static String EnderMan_DATA_CREEPY = "cx";
+
+ // net.minecraft.world.entity.monster.zombie.Zombie
+ public static String Zombie_inWaterTime = "cL";
+
+ // net.minecraft.world.item.Item
+ public static String Item_components = "c";
+
+ // net.minecraft.world.item.component.ResolvableProfile
+ public static String ResolvableProfile_unpack_method = "a";
+
+ // net.minecraft.world.item.component.ResolvableProfile$Partial
+ public static String ResolvableProfilePartial_id = "d";
+
+ // net.minecraft.world.level.Level
+ public static String Level_isClientSide = "D";
+
+ // net.minecraft.server.level.ThreadedLevelLightEngine
+ public static String ThreadedLevelLightEngine_addTask_method = "a";
+
+ // net.minecraft.server.level.ThreadedLevelLightEngine$TaskType
+ public static String ThreadedLevelLightEngineTaskType_PRE_UPDATE = "a";
+
+ // net.minecraft.world.entity.ExperienceOrb
+ public static String ExperienceOrb_age = "k";
+
+ // net.minecraft.world.entity.item.ItemEntity
+ public static String ItemEntity_DATA_ITEM = "c";
+
+ // net.minecraft.world.level.biome.Biome
+ public static String Biome_climateSettings = "i";
+ public static String Biome_attributes = "l";
+ public static String Biome_specialEffects = "m";
+
+ // net.minecraft.network.Connection
+ public static String Connection_receiving = "h";
+ public static String Connection_packetListener = "n";
+
+ // net.minecraft.server.network.ServerGamePacketListenerImpl
+ public static String ServerGamePacketListenerImpl_aboveGroundTickCount = "L";
+ public static String ServerGamePacketListenerImpl_aboveGroundVehicleTickCount = "N";
+ public static String ServerGamePacketListenerImpl_awaitingPositionFromClient = "H";
+ public static String ServerGamePacketListenerImpl_awaitingTeleport = "I";
+ public static String ServerGamePacketListenerImpl_chunkSender = "h";
+
+ // net.minecraft.server.network.ServerCommonPacketListenerImpl
+ public static String ServerCommonPacketListenerImpl_connection = "e";
+ public static String ServerCommonPacketListenerImpl_createCookie_method = "a";
+
+ // net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket
+ public static String ClientboundPlayerAbilitiesPacket_walkingSpeed = "k";
+
+ // net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket
+ public static String ClientboundSectionBlocksUpdatePacket_sectionPos = "c";
+ public static String ClientboundSectionBlocksUpdatePacket_positions = "d";
+ public static String ClientboundSectionBlocksUpdatePacket_states = "e";
+
+ // net.minecraft.network.protocol.game.ClientboundMoveEntityPacket
+ public static String ClientboundMoveEntityPacket_xa = "b";
+ public static String ClientboundMoveEntityPacket_ya = "c";
+ public static String ClientboundMoveEntityPacket_za = "d";
+ public static String ClientboundMoveEntityPacket_yRot = "e";
+ public static String ClientboundMoveEntityPacket_xRot = "f";
+
+ // net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket
+ public static String ClientboundSetEntityMotionPacket_id = "b";
+
+ // net.minecraft.network.protocol.game.ClientboundSetPassengersPacket
+ public static String ClientboundSetPassengersPacket_passengers = "c";
+
+ // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo
+ public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "c";
+ public static String ClientboundLevelChunkPacketDataBlockEntityInfo_y = "d";
+
+ // net.minecraft.network.syncher.SynchedEntityData
+ public static String SynchedEntityData_itemsById = "e";
+
+ // net.minecraft.world.entity.projectile.FishingHook
+ public static String FishingHook_nibble = "j";
+ public static String FishingHook_timeUntilLured = "k";
+ public static String FishingHook_timeUntilHooked = "l";
+
+ // net.minecraft.tags.TagNetworkSerialization$NetworkPayload
+ public static String TagNetworkSerializationNetworkPayload_tags = "b";
+
+ // net.minecraft.core.HolderSet$Named
+ public static String HolderSetNamed_bind_method = "b";
+
+ // net.minecraft.core.Holder$Reference
+ public static String HolderReference_bindTags_method = "a";
+
+ // net.minecraft.server.level.ServerLevel
+ public static String ServerLevel_sleepStatus = "O";
+
+ // net.minecraft.world.item.AdventureModePredicate
+ public static String AdventureModePredicate_predicates = "g";
+
+ // net.minecraft.stats.ServerRecipeBook
+ public static String ServerRecipeBook_addHighlight_method = "e";
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/AdvancementHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/AdvancementHelperImpl.java
new file mode 100644
index 0000000000..1c9d91c52c
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/AdvancementHelperImpl.java
@@ -0,0 +1,196 @@
+package com.denizenscript.denizen.nms.v1_21.helpers;
+
+import com.denizenscript.denizen.nms.interfaces.AdvancementHelper;
+import com.denizenscript.denizen.nms.v1_21.Handler;
+import com.denizenscript.denizen.utilities.FormattedTextHelper;
+import com.google.common.collect.ImmutableMap;
+import net.md_5.bungee.api.ChatColor;
+import net.minecraft.advancements.*;
+import net.minecraft.advancements.criterion.ImpossibleTrigger;
+import net.minecraft.core.ClientAsset;
+import net.minecraft.network.protocol.game.ClientboundUpdateAdvancementsPacket;
+import net.minecraft.resources.Identifier;
+import net.minecraft.server.PlayerAdvancements;
+import net.minecraft.server.ServerAdvancementManager;
+import net.minecraft.server.level.ServerPlayer;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_21_R7.CraftServer;
+import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer;
+import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+
+public class AdvancementHelperImpl extends AdvancementHelper {
+
+ private static final String IMPOSSIBLE_KEY = "impossible";
+ private static final Map> IMPOSSIBLE_CRITERIA = Map.of(IMPOSSIBLE_KEY, new Criterion<>(new ImpossibleTrigger(), new ImpossibleTrigger.TriggerInstance()));
+ private static final List> IMPOSSIBLE_REQUIREMENTS = List.of(List.of(IMPOSSIBLE_KEY));
+
+ public static ServerAdvancementManager getNMSAdvancementManager() {
+ return ((CraftServer) Bukkit.getServer()).getServer().getAdvancements();
+ }
+
+ @Override
+ public void register(com.denizenscript.denizen.nms.util.Advancement advancement) {
+ if (advancement.temporary || advancement.registered) {
+ return;
+ }
+ AdvancementHolder nmsAdvancementHolder = asNMSCopy(advancement);
+ Map nmsAdvancements = getNMSAdvancementManager().advancements;
+ ImmutableMap.Builder mapBuilder = ImmutableMap.builderWithExpectedSize(nmsAdvancements.size() + 1);
+ mapBuilder.putAll(nmsAdvancements);
+ mapBuilder.put(nmsAdvancementHolder.id(), nmsAdvancementHolder);
+ getNMSAdvancementManager().advancements = mapBuilder.build();
+
+ AdvancementTree tree = getNMSAdvancementManager().tree();
+ tree.addAll(List.of(nmsAdvancementHolder));
+ // recalculate advancement tree from this advancement's root
+ AdvancementNode node = tree.get(nmsAdvancementHolder.id());
+ if (node != null) {
+ AdvancementNode root = node.root();
+ if (root.holder().value().display().isPresent()) {
+ TreeNodePosition.run(root);
+ }
+ }
+ advancement.registered = true;
+ if (!advancement.hidden && advancement.parent != null) {
+ PacketHelperImpl.broadcast(new ClientboundUpdateAdvancementsPacket(false, List.of(nmsAdvancementHolder), Set.of(), Map.of(), false));
+ }
+ }
+
+ @Override
+ public void unregister(com.denizenscript.denizen.nms.util.Advancement advancement) {
+ if (advancement.temporary || !advancement.registered) {
+ return;
+ }
+ Identifier nmsKey = CraftNamespacedKey.toMinecraft(advancement.key);
+ Map nmsAdvancements = getNMSAdvancementManager().advancements;
+ ImmutableMap.Builder mapBuilder = ImmutableMap.builderWithExpectedSize(nmsAdvancements.size() - 1);
+ for (Map.Entry entry : nmsAdvancements.entrySet()) {
+ if (!entry.getKey().equals(nmsKey)) {
+ mapBuilder.put(entry);
+ }
+ }
+ getNMSAdvancementManager().advancements = mapBuilder.build();
+ getNMSAdvancementManager().tree().remove(Set.of(nmsKey));
+ advancement.registered = false;
+ PacketHelperImpl.broadcast(new ClientboundUpdateAdvancementsPacket(false, List.of(), Set.of(nmsKey), Map.of(), false));
+ }
+
+ @Override
+ public void grantPartial(com.denizenscript.denizen.nms.util.Advancement advancement, Player player, int len) {
+ if (advancement.length <= 1) {
+ grant(advancement, player);
+ return;
+ }
+ if (advancement.temporary) {
+ AdvancementHolder nmsAdvancement = asNMSCopy(advancement);
+ AdvancementProgress progress = new AdvancementProgress();
+ progress.update(new AdvancementRequirements(IMPOSSIBLE_REQUIREMENTS));
+ for (int i = 0; i < len; i++) {
+ progress.grantProgress(IMPOSSIBLE_KEY + i); // complete impossible criteria
+ }
+ PacketHelperImpl.send(player, new ClientboundUpdateAdvancementsPacket(false, List.of(nmsAdvancement), Set.of(), Map.of(nmsAdvancement.id(), progress), false));
+ }
+ else {
+ AdvancementHolder nmsAdvancement = getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.key));
+ for (int i = 0; i < len; i++) {
+ ((CraftPlayer) player).getHandle().getAdvancements().award(nmsAdvancement, IMPOSSIBLE_KEY + i);
+ }
+ }
+ }
+
+ @Override
+ public void grant(com.denizenscript.denizen.nms.util.Advancement advancement, Player player) {
+ if (advancement.length > 1) {
+ grantPartial(advancement, player, advancement.length);
+ return;
+ }
+ if (advancement.temporary) {
+ AdvancementHolder nmsAdvancement = asNMSCopy(advancement);
+ AdvancementProgress progress = new AdvancementProgress();
+ progress.update(new AdvancementRequirements(IMPOSSIBLE_REQUIREMENTS));
+ progress.grantProgress(IMPOSSIBLE_KEY); // complete impossible criteria
+ PacketHelperImpl.send(player, new ClientboundUpdateAdvancementsPacket(false, List.of(nmsAdvancement), Set.of(), Map.of(nmsAdvancement.id(), progress), true));
+ }
+ else {
+ AdvancementHolder nmsAdvancement = getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.key));
+ ((CraftPlayer) player).getHandle().getAdvancements().award(nmsAdvancement, IMPOSSIBLE_KEY);
+ }
+ }
+
+ @Override
+ public void revokePartial(com.denizenscript.denizen.nms.util.Advancement advancement, Player player, int len) {
+ if (advancement.length <= 1) {
+ revoke(advancement, player);
+ return;
+ }
+ if (advancement.temporary) {
+ AdvancementHolder nmsAdvancement = asNMSCopy(advancement);
+ AdvancementProgress progress = new AdvancementProgress();
+ progress.update(new AdvancementRequirements(IMPOSSIBLE_REQUIREMENTS));
+ for (int i = 0; i < len; i++) {
+ progress.grantProgress(IMPOSSIBLE_KEY + i); // complete impossible criteria
+ }
+ PacketHelperImpl.send(player, new ClientboundUpdateAdvancementsPacket(false, List.of(nmsAdvancement), Set.of(), Map.of(nmsAdvancement.id(), progress), false));
+ }
+ else {
+ AdvancementHolder nmsAdvancement = getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.key));
+ PlayerAdvancements advancements = ((CraftPlayer) player).getHandle().getAdvancements();
+ for (int i = len; i < advancement.length; i++) {
+ advancements.revoke(nmsAdvancement, IMPOSSIBLE_KEY + i);
+ }
+ }
+ }
+
+ @Override
+ public void revoke(com.denizenscript.denizen.nms.util.Advancement advancement, Player player) {
+ if (advancement.temporary) {
+ PacketHelperImpl.send(player, new ClientboundUpdateAdvancementsPacket(false, List.of(), Set.of(CraftNamespacedKey.toMinecraft(advancement.key)), Map.of(), false));
+ }
+ else {
+ AdvancementHolder nmsAdvancement = getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.key));
+ PlayerAdvancements advancements = ((CraftPlayer) player).getHandle().getAdvancements();
+ for (String criterion : nmsAdvancement.value().criteria().keySet()) {
+ advancements.revoke(nmsAdvancement, criterion);
+ }
+ }
+ }
+
+ @Override
+ public void update(Player player) {
+ // TODO: 1.21.5: should showAdvancements be true?
+ ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle();
+ nmsPlayer.connection.send(new ClientboundUpdateAdvancementsPacket(true, List.of(), Set.of(), Map.of(), false));
+ PlayerAdvancements data = nmsPlayer.getAdvancements();
+ data.save(); // save progress
+ data.reload(getNMSAdvancementManager()); // clear progress
+ data.flushDirty(nmsPlayer, false); // load progress and update client
+ }
+
+ private static AdvancementHolder asNMSCopy(com.denizenscript.denizen.nms.util.Advancement advancement) {
+ AdvancementHolder parent = advancement.parent != null
+ ? getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.parent))
+ : null;
+ DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSCopy(advancement.icon),
+ Handler.componentToNMS(FormattedTextHelper.parse(advancement.title, ChatColor.WHITE)), Handler.componentToNMS(FormattedTextHelper.parse(advancement.description, ChatColor.WHITE)),
+ Optional.ofNullable(advancement.background).map(CraftNamespacedKey::toMinecraft).map(ClientAsset.ResourceTexture::new), AdvancementType.valueOf(advancement.frame.name()),
+ advancement.toast, advancement.announceToChat, advancement.hidden);
+ display.setLocation(advancement.xOffset, advancement.yOffset);
+ Map> criteria = IMPOSSIBLE_CRITERIA;
+ List> requirements = IMPOSSIBLE_REQUIREMENTS;
+ if (advancement.length > 1) {
+ criteria = new HashMap<>();
+ requirements = new ArrayList<>(advancement.length);
+ for (int i = 0; i < advancement.length; i++) {
+ criteria.put(IMPOSSIBLE_KEY + i, new Criterion<>(new ImpossibleTrigger(), new ImpossibleTrigger.TriggerInstance()));
+ requirements.add(List.of(IMPOSSIBLE_KEY + i));
+ }
+ }
+ AdvancementRequirements reqs = new AdvancementRequirements(requirements);
+ Advancement adv = new Advancement(parent == null ? Optional.empty() : Optional.of(parent.id()), Optional.of(display), AdvancementRewards.EMPTY, criteria, reqs, false); // TODO: 1.20: do we want to ever enable telemetry?
+ return new AdvancementHolder(CraftNamespacedKey.toMinecraft(advancement.key), adv);
+ }
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/AnimationHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/AnimationHelperImpl.java
new file mode 100644
index 0000000000..b000df11bc
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/AnimationHelperImpl.java
@@ -0,0 +1,48 @@
+package com.denizenscript.denizen.nms.v1_21.helpers;
+
+import com.denizenscript.denizen.nms.abstracts.AnimationHelper;
+import net.minecraft.world.entity.Entity;
+import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_21_R7.entity.CraftHorse;
+import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPolarBear;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Horse;
+import org.bukkit.entity.IronGolem;
+
+public class AnimationHelperImpl extends AnimationHelper {
+
+ public AnimationHelperImpl() {
+ register("POLAR_BEAR_START_STANDING", entity -> {
+ if (entity.getType() == EntityType.POLAR_BEAR) {
+ ((CraftPolarBear) entity).getHandle().setStanding(true);
+ }
+ });
+ register("POLAR_BEAR_STOP_STANDING", entity -> {
+ if (entity.getType() == EntityType.POLAR_BEAR) {
+ ((CraftPolarBear) entity).getHandle().setStanding(false);
+ }
+ });
+ // TODO: 1.21.6: this is a tick duration now, should become a mechanism
+ register("HORSE_START_STANDING", entity -> {
+ if (entity instanceof Horse) {
+ ((CraftHorse) entity).getHandle().setStanding(Integer.MAX_VALUE);
+ }
+ });
+ register("HORSE_STOP_STANDING", entity -> {
+ if (entity instanceof Horse) {
+ ((CraftHorse) entity).getHandle().clearStanding();
+ }
+ });
+ register("HORSE_BUCK", entity -> {
+ if (entity instanceof Horse) {
+ ((CraftHorse) entity).getHandle().makeMad();
+ }
+ });
+ register("IRON_GOLEM_ATTACK", entity -> {
+ if (entity instanceof IronGolem) {
+ Entity nmsEntity = ((CraftEntity) entity).getHandle();
+ nmsEntity.level().broadcastEntityEvent(nmsEntity, (byte) 4);
+ }
+ });
+ }
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/BlockHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/BlockHelperImpl.java
new file mode 100644
index 0000000000..8a8b9188c9
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/BlockHelperImpl.java
@@ -0,0 +1,253 @@
+package com.denizenscript.denizen.nms.v1_21.helpers;
+
+import com.denizenscript.denizen.nms.interfaces.BlockHelper;
+import com.denizenscript.denizen.nms.util.PlayerProfile;
+import com.denizenscript.denizen.nms.v1_21.Handler;
+import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo;
+import com.denizenscript.denizen.nms.v1_21.impl.ProfileEditorImpl;
+import com.denizenscript.denizen.objects.EntityTag;
+import com.denizenscript.denizencore.objects.Mechanism;
+import com.denizenscript.denizencore.utilities.ReflectionHelper;
+import com.denizenscript.denizencore.utilities.debugging.Debug;
+import com.google.common.collect.Iterables;
+import com.mojang.authlib.GameProfile;
+import net.kyori.adventure.nbt.CompoundBinaryTag;
+import net.minecraft.core.BlockPos;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.util.InclusiveRange;
+import net.minecraft.util.random.WeightedList;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.item.component.ResolvableProfile;
+import net.minecraft.world.level.BaseSpawner;
+import net.minecraft.world.level.SpawnData;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
+import net.minecraft.world.level.block.state.BlockBehaviour;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import net.minecraft.world.level.material.FluidState;
+import net.minecraft.world.level.material.PushReaction;
+import org.bukkit.Instrument;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.CreatureSpawner;
+import org.bukkit.block.Skull;
+import org.bukkit.craftbukkit.v1_21_R7.CraftChunk;
+import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry;
+import org.bukkit.craftbukkit.v1_21_R7.CraftWorld;
+import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlock;
+import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockEntityState;
+import org.bukkit.craftbukkit.v1_21_R7.block.CraftCreatureSpawner;
+import org.bukkit.craftbukkit.v1_21_R7.block.CraftSkull;
+import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation;
+import org.bukkit.craftbukkit.v1_21_R7.util.CraftMagicNumbers;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Field;
+import java.util.Optional;
+
+public class BlockHelperImpl implements BlockHelper {
+
+ public static final Field craftBlockEntityState_tileEntity;
+ public static final Field craftBlockEntityState_snapshot = ReflectionHelper.getFields(CraftBlockEntityState.class).get("snapshot");
+ public static final Field craftSkull_profile = ReflectionHelper.getFields(CraftSkull.class).get("profile");
+
+ static {
+ Field blockEntityField = ReflectionHelper.getFields(CraftBlockEntityState.class).getNoCheck("blockEntity");
+ if (blockEntityField == null) {
+ blockEntityField = ReflectionHelper.getFields(CraftBlockEntityState.class).get("tileEntity");
+ }
+ craftBlockEntityState_tileEntity = blockEntityField;
+ }
+
+ @Override
+ public void applyPhysics(Location location) {
+ ((CraftWorld) location.getWorld()).getHandle().updateNeighborsAt(CraftLocation.toBlockPosition(location), CraftMagicNumbers.getBlock(location.getBlock().getType()));
+ }
+
+ public static T getTE(CraftBlockEntityState cbs) {
+ try {
+ return (T) craftBlockEntityState_tileEntity.get(cbs);
+ }
+ catch (IllegalAccessException e) {
+ Debug.echoError(e);
+ }
+ return null;
+ }
+
+ @Override
+ public PlayerProfile getPlayerProfile(Skull skull) {
+ ResolvableProfile profile = getTE(((CraftSkull) skull)).owner;
+ if (profile == null) {
+ return null;
+ }
+ com.mojang.authlib.properties.Property property = Iterables.getFirst(profile.partialProfile().properties().get("textures"), null);
+ return new PlayerProfile(profile.name().orElse(null), ProfileEditorImpl.getUUID(profile), property != null ? property.value() : null);
+ }
+
+ @Override
+ public void setPlayerProfile(Skull skull, PlayerProfile playerProfile) {
+ GameProfile gameProfile = ProfileEditorImpl.getGameProfile(playerProfile);
+ try {
+ craftSkull_profile.set(skull, ResolvableProfile.createResolved(gameProfile));
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ skull.update();
+ }
+
+ public BlockEntity getBlockEntity(Block block) {
+ CraftBlock craftBlock = ((CraftBlock) block);
+ return craftBlock.getHandle().getBlockEntity(craftBlock.getPosition());
+ }
+
+ @Override
+ public CompoundBinaryTag getNbtData(Block block) {
+ BlockEntity nmsBlockEntity = getBlockEntity(block);
+ if (nmsBlockEntity != null) {
+ CompoundTag compound = nmsBlockEntity.saveWithFullMetadata(CraftRegistry.getMinecraftRegistry());
+ return NBTAdapter.toAPI(compound);
+ }
+ return null;
+ }
+
+ @Override
+ public void setNbtData(Block block, CompoundBinaryTag ctag) {
+ CompoundTag nmsData = NBTAdapter.toNMS(ctag);
+ nmsData.putInt("x", block.getX());
+ nmsData.putInt("y", block.getY());
+ nmsData.putInt("z", block.getZ());
+ Handler.useValueInput(nmsData, getBlockEntity(block)::loadWithComponents);
+ }
+
+ @Override
+ public boolean setBlockResistance(Material material, float resistance) {
+ net.minecraft.world.level.block.Block block = CraftMagicNumbers.getBlock(material);
+ if (block == null) {
+ return false;
+ }
+ ReflectionHelper.setFieldValue(net.minecraft.world.level.block.state.BlockBehaviour.class, ReflectionMappingsInfo.BlockBehaviour_explosionResistance, block, resistance);
+ return true;
+ }
+
+ @Override
+ public float getBlockResistance(Material material) {
+ net.minecraft.world.level.block.Block block = CraftMagicNumbers.getBlock(material);
+ if (block == null) {
+ return 0;
+ }
+ return ReflectionHelper.getFieldValue(net.minecraft.world.level.block.state.BlockBehaviour.class, ReflectionMappingsInfo.BlockBehaviour_explosionResistance, block);
+ }
+
+ public static final MethodHandle MATERIAL_PUSH_REACTION_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(BlockBehaviour.BlockStateBase.class, PushReaction.class);
+
+ public static final MethodHandle BLOCK_STRENGTH_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(net.minecraft.world.level.block.state.BlockBehaviour.BlockStateBase.class, float.class); // destroySpeed
+
+ public net.minecraft.world.level.block.state.BlockState getMaterialBlockState(Material bukkitMaterial) {
+ net.minecraft.world.level.block.Block nmsBlock = CraftMagicNumbers.getBlock(bukkitMaterial);
+ return nmsBlock != null ? nmsBlock.defaultBlockState() : null;
+ }
+
+ @Override
+ public void setPushReaction(Material mat, PistonPushReaction reaction) {
+ try {
+ MATERIAL_PUSH_REACTION_SETTER.invoke(getMaterialBlockState(mat), PushReaction.values()[reaction.ordinal()]);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ @Override
+ public float getBlockStrength(Material mat) {
+ return getMaterialBlockState(mat).destroySpeed;
+ }
+
+ @Override
+ public void setBlockStrength(Material mat, float strength) {
+ try {
+ BLOCK_STRENGTH_SETTER.invoke(getMaterialBlockState(mat), strength);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ @Override
+ public void doRandomTick(Location location) {
+ BlockPos pos = CraftLocation.toBlockPosition(location);
+ ChunkAccess nmsChunk = ((CraftChunk) location.getChunk()).getHandle(ChunkStatus.FULL);
+ net.minecraft.world.level.block.state.BlockState nmsBlock = nmsChunk.getBlockState(pos);
+ ServerLevel nmsWorld = ((CraftWorld) location.getWorld()).getHandle();
+ if (nmsBlock.isRandomlyTicking()) {
+ nmsBlock.randomTick(nmsWorld, pos, nmsWorld.random);
+ }
+ FluidState fluid = nmsBlock.getFluidState();
+ if (fluid.isRandomlyTicking()) {
+ fluid.animateTick(nmsWorld, pos, nmsWorld.random);
+ }
+ }
+
+ @Override
+ public Instrument getInstrumentFor(Material mat) {
+ return Instrument.values()[getMaterialBlockState(mat).instrument().ordinal()];
+ }
+
+ @Override
+ public int getExpDrop(Block block, org.bukkit.inventory.ItemStack item) {
+ net.minecraft.world.level.block.Block blockType = CraftMagicNumbers.getBlock(block.getType());
+ if (blockType == null) {
+ return 0;
+ }
+ return blockType.getExpDrop(((CraftBlock) block).getNMS(), ((CraftBlock) block).getCraftWorld().getHandle(), ((CraftBlock) block).getPosition(),
+ item == null ? null : CraftItemStack.asNMSCopy(item), true);
+ }
+
+ @Override
+ public void setSpawnerSpawnedType(CreatureSpawner spawner, EntityTag entity) {
+ spawner.setSpawnedType(entity.getBukkitEntityType());
+ if (entity.getWaitingMechanisms() == null || entity.getWaitingMechanisms().size() == 0) {
+ return;
+ }
+ try {
+ // Wrangle a fake entity
+ // TODO: 1.21.6: seems to have a bug where the "Pos" value being set prevents it from spawning?
+ org.bukkit.entity.Entity bukkitEntity = ((CraftWorld) spawner.getWorld()).createEntity(spawner.getLocation(), entity.getBukkitEntityType().getEntityClass());
+ Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
+ EntityTag entityTag = new EntityTag(bukkitEntity);
+ entityTag.isFake = true;
+ entityTag.isFakeValid = true;
+ for (Mechanism mechanism : entity.getWaitingMechanisms()) {
+ entityTag.safeAdjustDuplicate(mechanism);
+ }
+ nmsEntity.unsetRemoved();
+ // Store it into the spawner
+ SpawnerBlockEntity nmsSnapshot = (SpawnerBlockEntity) craftBlockEntityState_snapshot.get(spawner);
+ Handler.useValueOutput(nmsSnapshot.getSpawner().nextSpawnData.getEntityToSpawn(), nmsEntity::saveWithoutId);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ @Override
+ public void setSpawnerCustomRules(CreatureSpawner spawner, int skyMin, int skyMax, int blockMin, int blockMax) {
+ try {
+ CraftCreatureSpawner bukkitSpawner = (CraftCreatureSpawner) spawner;
+ SpawnerBlockEntity nmsSnapshot = (SpawnerBlockEntity) craftBlockEntityState_snapshot.get(bukkitSpawner);
+ BaseSpawner nmsSpawner = nmsSnapshot.getSpawner();
+ SpawnData toSpawn = nmsSpawner.nextSpawnData;
+ SpawnData.CustomSpawnRules rules = skyMin == -1 ? null : new SpawnData.CustomSpawnRules(new InclusiveRange<>(skyMin, skyMax), new InclusiveRange<>(blockMin, blockMax));
+ nmsSpawner.nextSpawnData = new SpawnData(toSpawn.entityToSpawn(), Optional.ofNullable(rules), toSpawn.equipment());
+ nmsSpawner.spawnPotentials = WeightedList.of();
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ChunkHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ChunkHelperImpl.java
new file mode 100644
index 0000000000..4157cf2074
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ChunkHelperImpl.java
@@ -0,0 +1,119 @@
+package com.denizenscript.denizen.nms.v1_21.helpers;
+
+import com.denizenscript.denizen.nms.abstracts.BiomeNMS;
+import com.denizenscript.denizen.nms.interfaces.ChunkHelper;
+import com.denizenscript.denizen.nms.v1_21.impl.BiomeNMSImpl;
+import com.denizenscript.denizencore.tags.TagManager;
+import com.denizenscript.denizencore.utilities.ReflectionHelper;
+import com.denizenscript.denizencore.utilities.debugging.Debug;
+import net.minecraft.core.Holder;
+import net.minecraft.core.QuartPos;
+import net.minecraft.server.level.ServerChunkCache;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.LevelHeightAccessor;
+import net.minecraft.world.level.biome.Biome;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.LevelChunkSection;
+import net.minecraft.world.level.chunk.PalettedContainer;
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import net.minecraft.world.level.levelgen.Heightmap;
+import org.bukkit.Chunk;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_21_R7.CraftChunk;
+import org.bukkit.craftbukkit.v1_21_R7.CraftWorld;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Field;
+
+public class ChunkHelperImpl implements ChunkHelper {
+
+ public final static Field chunkProviderServerThreadField;
+ public final static MethodHandle chunkProviderServerThreadFieldSetter;
+ public final static Field worldThreadField;
+ public final static MethodHandle worldThreadFieldSetter;
+
+ static {
+ chunkProviderServerThreadField = ReflectionHelper.getFields(ServerChunkCache.class).getFirstOfType(Thread.class);
+ chunkProviderServerThreadFieldSetter = ReflectionHelper.getFinalSetterForFirstOfType(ServerChunkCache.class, Thread.class);
+ worldThreadField = ReflectionHelper.getFields(net.minecraft.world.level.Level.class).getFirstOfType(Thread.class);
+ worldThreadFieldSetter = ReflectionHelper.getFinalSetterForFirstOfType(net.minecraft.world.level.Level.class, Thread.class);
+ }
+
+ public Thread resetServerThread;
+
+ @Override
+ public void changeChunkServerThread(World world) {
+ if (TagManager.tagThread == null) {
+ return;
+ }
+ if (resetServerThread != null) {
+ return;
+ }
+ ServerLevel nmsWorld = ((CraftWorld) world).getHandle();
+ ServerChunkCache provider = nmsWorld.getChunkSource();
+ try {
+ resetServerThread = (Thread) chunkProviderServerThreadField.get(provider);
+ chunkProviderServerThreadFieldSetter.invoke(provider, Thread.currentThread());
+ worldThreadFieldSetter.invoke(nmsWorld, Thread.currentThread());
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ @Override
+ public void restoreServerThread(World world) {
+ if (TagManager.tagThread == null) {
+ return;
+ }
+ if (resetServerThread == null) {
+ return;
+ }
+ ServerLevel nmsWorld = ((CraftWorld) world).getHandle();
+ ServerChunkCache provider = nmsWorld.getChunkSource();
+ try {
+ chunkProviderServerThreadFieldSetter.invoke(provider, resetServerThread);
+ worldThreadFieldSetter.invoke(nmsWorld, resetServerThread);
+ resetServerThread = null;
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ @Override
+ public int[] getHeightMap(Chunk chunk) {
+ Heightmap map = ((CraftChunk) chunk).getHandle(ChunkStatus.FEATURES).heightmaps.get(Heightmap.Types.MOTION_BLOCKING);
+ int[] outputMap = new int[256];
+ for (int x = 0; x < 16; x++) {
+ for (int y = 0; y < 16; y++) {
+ outputMap[x * 16 + y] = map.getFirstAvailable(x, y);
+ }
+ }
+ return outputMap;
+ }
+
+ @Override
+ public void setAllBiomes(Chunk chunk, BiomeNMS biome) {
+ Holder nmsBiome = ((BiomeNMSImpl) biome).biomeHolder;
+ ChunkAccess nmsChunk = ((CraftChunk) chunk).getHandle(ChunkStatus.BIOMES);
+ ChunkPos chunkcoordintpair = nmsChunk.getPos();
+ int i = QuartPos.fromBlock(chunkcoordintpair.getMinBlockX());
+ int j = QuartPos.fromBlock(chunkcoordintpair.getMinBlockZ());
+ LevelHeightAccessor levelheightaccessor = nmsChunk.getHeightAccessorForGeneration();
+ for(int k = levelheightaccessor.getMinSectionY(); k < levelheightaccessor.getMaxSectionY(); ++k) {
+ LevelChunkSection chunksection = nmsChunk.getSection(nmsChunk.getSectionIndexFromSectionY(k));
+ PalettedContainer> datapaletteblock = (PalettedContainer>) chunksection.getBiomes();
+ datapaletteblock.acquire();
+ for(int l = 0; l < 4; ++l) {
+ for(int i1 = 0; i1 < 4; ++i1) {
+ for(int j1 = 0; j1 < 4; ++j1) {
+ datapaletteblock.getAndSetUnchecked(l, i1, j1, nmsBiome);
+ }
+ }
+ }
+ datapaletteblock.release();
+ }
+ }
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/CustomEntityHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/CustomEntityHelperImpl.java
new file mode 100644
index 0000000000..0df283220e
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/CustomEntityHelperImpl.java
@@ -0,0 +1,149 @@
+package com.denizenscript.denizen.nms.v1_21.helpers;
+
+import com.denizenscript.denizen.nms.NMSHandler;
+import com.denizenscript.denizen.nms.interfaces.CustomEntityHelper;
+import com.denizenscript.denizen.nms.interfaces.FakeArrow;
+import com.denizenscript.denizen.nms.interfaces.FakePlayer;
+import com.denizenscript.denizen.nms.interfaces.ItemProjectile;
+import com.denizenscript.denizen.nms.util.PlayerProfile;
+import com.denizenscript.denizen.nms.v1_21.impl.ProfileEditorImpl;
+import com.denizenscript.denizen.nms.v1_21.impl.entities.CraftFakePlayerImpl;
+import com.denizenscript.denizen.nms.v1_21.impl.entities.EntityFakeArrowImpl;
+import com.denizenscript.denizen.nms.v1_21.impl.entities.EntityFakePlayerImpl;
+import com.denizenscript.denizen.nms.v1_21.impl.entities.EntityItemProjectileImpl;
+import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
+import com.denizenscript.denizencore.utilities.CoreUtilities;
+import com.denizenscript.denizencore.utilities.debugging.Debug;
+import com.mojang.authlib.GameProfile;
+import net.minecraft.server.level.ClientInformation;
+import net.minecraft.server.level.ServerLevel;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_21_R7.CraftWorld;
+import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.scoreboard.Scoreboard;
+import org.bukkit.scoreboard.Team;
+
+import java.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+public class CustomEntityHelperImpl implements CustomEntityHelper {
+
+ @Override
+ public FakeArrow spawnFakeArrow(Location location) {
+ CraftWorld world = (CraftWorld) location.getWorld();
+ EntityFakeArrowImpl arrow = new EntityFakeArrowImpl(world, location);
+ return arrow.getBukkitEntity();
+ }
+
+ @Override
+ public ItemProjectile spawnItemProjectile(Location location, ItemStack itemStack) {
+ CraftWorld world = (CraftWorld) location.getWorld();
+ EntityItemProjectileImpl entity = new EntityItemProjectileImpl(world.getHandle(), location, CraftItemStack.asNMSCopy(itemStack));
+ world.getHandle().addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
+ return entity.getBukkitEntity();
+ }
+
+ public FakePlayer spawnFakePlayer(Location location, String name, String skin, String blob, boolean doAdd) throws IllegalArgumentException {
+ BukkitImplDeprecations.fakePlayer.warn();
+ String fullName = name;
+ String prefix = null;
+ String suffix = null;
+ if (name == null) {
+ Debug.echoError("FAKE_PLAYER: null name, cannot spawn");
+ return null;
+ }
+ else if (fullName.length() > 16) {
+ prefix = fullName.substring(0, 16);
+ if (fullName.length() > 30) {
+ int len = 30;
+ name = fullName.substring(16, 30);
+ if (name.matches(".*[^A-Za-z0-9_].*")) {
+ if (fullName.length() >= 32) {
+ len = 32;
+ name = fullName.substring(16, 32);
+ }
+ else if (fullName.length() == 31) {
+ len = 31;
+ name = fullName.substring(16, 31);
+ }
+ }
+ else if (name.length() > 46) {
+ throw new IllegalArgumentException("You must specify a name with no more than 46 characters for FAKE_PLAYER entities!");
+ }
+ else {
+ name = ChatColor.RESET + name;
+ }
+ suffix = fullName.substring(len);
+ }
+ else {
+ name = fullName.substring(16);
+ if (!name.matches(".*[^A-Za-z0-9_].*")) {
+ name = ChatColor.RESET + name;
+ }
+ if (name.length() > 16) {
+ suffix = name.substring(16);
+ name = name.substring(0, 16);
+ }
+ }
+ }
+ if (skin != null && skin.length() > 16) {
+ throw new IllegalArgumentException("You must specify a name with no more than 16 characters for FAKE_PLAYER entity skins!");
+ }
+ CraftWorld world = (CraftWorld) location.getWorld();
+ ServerLevel worldServer = world.getHandle();
+ PlayerProfile playerProfile = new PlayerProfile(name, null);
+ if (blob != null) {
+ int sc = blob.indexOf(';');
+ if (sc != -1) {
+ playerProfile.setTexture(blob.substring(0, sc));
+ playerProfile.setTextureSignature(blob.substring(sc + 1));
+ }
+ }
+ else if (skin == null && !name.matches(".*[^A-Za-z0-9_].*")) {
+ playerProfile = NMSHandler.instance.fillPlayerProfile(playerProfile);
+ }
+ if (skin != null) {
+ PlayerProfile skinProfile = new PlayerProfile(skin, null);
+ skinProfile = NMSHandler.instance.fillPlayerProfile(skinProfile);
+ playerProfile.setTexture(skinProfile.getTexture());
+ playerProfile.setTextureSignature(skinProfile.getTextureSignature());
+ }
+ UUID uuid = UUID.randomUUID();
+ playerProfile.setUniqueId(uuid);
+
+ GameProfile gameProfile = ProfileEditorImpl.getGameProfile(playerProfile);
+ final EntityFakePlayerImpl fakePlayer = new EntityFakePlayerImpl(worldServer.getServer(), worldServer, gameProfile, ClientInformation.createDefault(), doAdd);
+
+ fakePlayer.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(),
+ location.getYaw(), location.getPitch());
+ CraftFakePlayerImpl craftFakePlayer = fakePlayer.getBukkitEntity();
+ craftFakePlayer.fullName = fullName;
+ if (prefix != null) {
+ Scoreboard scoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
+ String teamName = "FAKE_PLAYER_TEAM_" + fullName;
+ String hash = null;
+ try {
+ hash = CoreUtilities.hash_md5(teamName.getBytes(StandardCharsets.UTF_8)).substring(0, 16);
+ }
+ catch (Exception e) {
+ Debug.echoError(e);
+ }
+ if (hash != null) {
+ Team team = scoreboard.getTeam(hash);
+ if (team == null) {
+ team = scoreboard.registerNewTeam(hash);
+ team.setPrefix(prefix);
+ if (suffix != null) {
+ team.setSuffix(suffix);
+ }
+ }
+ team.addPlayer(craftFakePlayer);
+ }
+ }
+ return craftFakePlayer;
+ }
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EnchantmentHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EnchantmentHelperImpl.java
new file mode 100644
index 0000000000..ba72802159
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EnchantmentHelperImpl.java
@@ -0,0 +1,195 @@
+package com.denizenscript.denizen.nms.v1_21.helpers;
+
+import com.denizenscript.denizen.nms.interfaces.EnchantmentHelper;
+
+public class EnchantmentHelperImpl extends EnchantmentHelper {
+ // TODO: 1.21: Enchantments were entirely reworked, need to update this
+ /*
+ public static final Field REGISTRY_FROZEN = ReflectionHelper.getFields(MappedRegistry.class).get(ReflectionMappingsInfo.MappedRegistry_frozen, boolean.class);
+ public static final Field REGISTRY_INTRUSIVE_HOLDERS = ReflectionHelper.getFields(MappedRegistry.class).get(ReflectionMappingsInfo.MappedRegistry_unregisteredIntrusiveHolders, Map.class);
+
+ @Override
+ public org.bukkit.enchantments.Enchantment registerFakeEnchantment(EnchantmentScriptContainer.EnchantmentReference script) {
+ try {
+ Map holders = (Map) REGISTRY_INTRUSIVE_HOLDERS.get(BuiltInRegistries.ENCHANTMENT);
+ if (holders == null) {
+ REGISTRY_INTRUSIVE_HOLDERS.set(BuiltInRegistries.ENCHANTMENT, new IdentityHashMap());
+ }
+ boolean wasFrozen = REGISTRY_FROZEN.getBoolean(BuiltInRegistries.ENCHANTMENT);
+ REGISTRY_FROZEN.setBoolean(BuiltInRegistries.ENCHANTMENT, false);
+ EquipmentSlot[] slots = new EquipmentSlot[script.script.slots.size()];
+ for (int i = 0; i < slots.length; i++) {
+ slots[i] = EquipmentSlot.valueOf(CoreUtilities.toUpperCase(script.script.slots.get(i)));
+ }
+ // TODO: 1.20.6: rarity is provided as an int, can make our own mirror enum; categories seemed to only over control #canEnchant(ItemStack), so can probably safely phase them out?
+ net.minecraft.world.item.enchantment.Enchantment.Rarity.valueOf(script.script.rarity), EnchantmentCategory.valueOf(script.script.category), slots
+ net.minecraft.world.item.enchantment.Enchantment nmsEnchant = new net.minecraft.world.item.enchantment.Enchantment(null) {
+ // TODO: 1.20.6: methods are final now and the values are provided by EnchantmentDefinition - would probably need to create a new one on reload and modify the existing enchantment
+ @Override
+ public int getMinLevel() {
+ return script.script.minLevel;
+ }
+ @Override
+ public int getMaxLevel() {
+ return script.script.maxLevel;
+ }
+ @Override
+ public int getMinCost(int level) {
+ return script.script.getMinCost(level);
+ }
+ @Override
+ public int getMaxCost(int level) {
+ return script.script.getMaxCost(level);
+ }
+ @Override
+ public int getDamageProtection(int level, DamageSource src) {
+ return script.script.getDamageProtection(level, src.getMsgId(), src.getEntity() == null ? null : src.getEntity().getBukkitEntity());
+ }
+ // TODO: 1.20.6: Takes an EntityType now, and MobType seems to have been removed in favor of vanilla tags - can probably use these to backsupport & properly pass the entity type
+ @Override
+ public float getDamageBonus(int level, EntityType type) {
+ String typeName = "UNDEFINED";
+ if (type == MobType.ARTHROPOD) {
+ typeName = "ARTHROPOD";
+ }
+ else if (type == MobType.ILLAGER) {
+ typeName = "ILLAGER";
+ }
+ else if (type == MobType.UNDEAD) {
+ typeName = "UNDEAD";
+ }
+ else if (type == MobType.WATER) {
+ typeName = "WATER";
+ }
+ return script.script.getDamageBonus(level, typeName);
+ }
+ @Override
+ protected boolean checkCompatibility(net.minecraft.world.item.enchantment.Enchantment nmsEnchantment) {
+ ResourceLocation nmsKey = BuiltInRegistries.ENCHANTMENT.getKey(nmsEnchantment);
+ NamespacedKey bukkitKey = CraftNamespacedKey.fromMinecraft(nmsKey);
+ org.bukkit.enchantments.Enchantment bukkitEnchant = CraftEnchantment.getByKey(bukkitKey);
+ return script.script.isCompatible(bukkitEnchant);
+ }
+ @Override
+ protected String getOrCreateDescriptionId() {
+ return script.script.descriptionId;
+ }
+ @Override
+ public String getDescriptionId() {
+ return script.script.descriptionId;
+ }
+ @Override
+ public Component getFullname(int level) {
+ return Handler.componentToNMS(script.script.getFullName(level));
+ }
+ @Override
+ public boolean canEnchant(net.minecraft.world.item.ItemStack var0) {
+ return super.canEnchant(var0) && script.script.canEnchant(CraftItemStack.asBukkitCopy(var0));
+ }
+ @Override
+ public void doPostAttack(LivingEntity attacker, Entity victim, int level) {
+ script.script.doPostAttack(attacker.getBukkitEntity(), victim.getBukkitEntity(), level);
+ }
+ @Override
+ public void doPostHurt(LivingEntity victim, Entity attacker, int level) {
+ script.script.doPostHurt(victim.getBukkitEntity(), attacker.getBukkitEntity(), level);
+ }
+ @Override
+ public boolean isTreasureOnly() {
+ return script.script.isTreasureOnly;
+ }
+ @Override
+ public boolean isCurse() {
+ return script.script.isCurse;
+ }
+ @Override
+ public boolean isTradeable() {
+ return script.script.isTradable;
+ }
+ @Override
+ public boolean isDiscoverable() {
+ return script.script.isDiscoverable;
+ }
+ };
+ NamespacedKey enchantmentKey = new NamespacedKey(Denizen.getInstance(), script.script.id);
+ Registry.register(BuiltInRegistries.ENCHANTMENT, enchantmentKey.toString(), nmsEnchant);
+ String enchName = CoreUtilities.toUpperCase(script.script.id);
+ CraftEnchantment ench = new CraftEnchantment(enchantmentKey, nmsEnchant) {
+ @Override
+ public String getName() {
+ return enchName;
+ }
+ };
+ REGISTRY_INTRUSIVE_HOLDERS.set(BuiltInRegistries.ENCHANTMENT, holders);
+ if (wasFrozen) {
+ BuiltInRegistries.ENCHANTMENT.freeze();
+ }
+ return ench;
+ }
+ catch (Throwable ex) {
+ Debug.echoError("Failed to register enchantment " + script.script.id);
+ Debug.echoError(ex);
+ return null;
+ }
+ }
+
+ // TODO: 1.20.6: rarity is just an int now (weight), can deprecate & backsupport by estimating it based on the weight
+ @Override
+ public String getRarity(Enchantment enchantment) {
+ return ((CraftEnchantment) enchantment).getHandle().getRarity().name();
+ }
+
+ @Override
+ public boolean isDiscoverable(Enchantment enchantment) {
+ return ((CraftEnchantment) enchantment).getHandle().isDiscoverable();
+ }
+
+ @Override
+ public boolean isTradable(Enchantment enchantment) {
+ return ((CraftEnchantment) enchantment).getHandle().isTradeable();
+ }
+
+ @Override
+ public boolean isCurse(Enchantment enchantment) {
+ return ((CraftEnchantment) enchantment).getHandle().isCurse();
+ }
+
+ @Override
+ public int getMinCost(Enchantment enchantment, int level) {
+ return ((CraftEnchantment) enchantment).getHandle().getMinCost(level);
+ }
+
+ @Override
+ public int getMaxCost(Enchantment enchantment, int level) {
+ return ((CraftEnchantment) enchantment).getHandle().getMaxCost(level);
+ }
+
+ @Override
+ public String getFullName(Enchantment enchantment, int level) {
+ return FormattedTextHelper.stringify(Handler.componentToSpigot(((CraftEnchantment) enchantment).getHandle().getFullname(level)));
+ }
+
+ // TODO: 1.20.6: MobType was removed in favor of using the entity type directly - deprecate + potentially backsupport with vanilla tags
+ @Override
+ public float getDamageBonus(Enchantment enchantment, int level, String type) {
+ MobType mobType = switch (type) {
+ case "illager" -> MobType.ILLAGER;
+ case "undead" -> MobType.UNDEAD;
+ case "water" -> MobType.WATER;
+ case "arthropod" -> MobType.ARTHROPOD;
+ default -> MobType.UNDEFINED;
+ };
+ return ((CraftEnchantment) enchantment).getHandle().getDamageBonus(level, mobType);
+ }
+
+ @Override
+ public int getDamageProtection(Enchantment enchantment, int level, EntityDamageEvent.DamageCause type, org.bukkit.entity.Entity attacker) {
+ Entity nmsAttacker = attacker == null ? null : ((CraftEntity) attacker).getHandle();
+ DamageSource src = EntityHelperImpl.getSourceFor(nmsAttacker, type, nmsAttacker);
+ if (src instanceof EntityHelperImpl.FakeDamageSrc fakeDamageSrc) {
+ src = fakeDamageSrc.real;
+ }
+ return ((CraftEnchantment) enchantment).getHandle().getDamageProtection(level, src);
+ }
+ */
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EntityDataNameMapper.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EntityDataNameMapper.java
new file mode 100644
index 0000000000..01b43c07ca
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EntityDataNameMapper.java
@@ -0,0 +1,484 @@
+package com.denizenscript.denizen.nms.v1_21.helpers;
+
+
+import com.denizenscript.denizencore.objects.ArgumentHelper;
+import com.denizenscript.denizencore.objects.core.ElementTag;
+import net.minecraft.world.entity.*;
+import net.minecraft.world.entity.ambient.Bat;
+import net.minecraft.world.entity.animal.axolotl.Axolotl;
+import net.minecraft.world.entity.animal.bee.Bee;
+import net.minecraft.world.entity.animal.camel.Camel;
+import net.minecraft.world.entity.animal.cow.MushroomCow;
+import net.minecraft.world.entity.animal.dolphin.Dolphin;
+import net.minecraft.world.entity.animal.equine.AbstractChestedHorse;
+import net.minecraft.world.entity.animal.equine.AbstractHorse;
+import net.minecraft.world.entity.animal.equine.Horse;
+import net.minecraft.world.entity.animal.equine.Llama;
+import net.minecraft.world.entity.animal.feline.Cat;
+import net.minecraft.world.entity.animal.feline.Ocelot;
+import net.minecraft.world.entity.animal.fish.AbstractFish;
+import net.minecraft.world.entity.animal.fish.Pufferfish;
+import net.minecraft.world.entity.animal.fish.TropicalFish;
+import net.minecraft.world.entity.animal.fox.Fox;
+import net.minecraft.world.entity.animal.frog.Frog;
+import net.minecraft.world.entity.animal.goat.Goat;
+import net.minecraft.world.entity.animal.golem.IronGolem;
+import net.minecraft.world.entity.animal.golem.SnowGolem;
+import net.minecraft.world.entity.animal.panda.Panda;
+import net.minecraft.world.entity.animal.parrot.Parrot;
+import net.minecraft.world.entity.animal.pig.Pig;
+import net.minecraft.world.entity.animal.polarbear.PolarBear;
+import net.minecraft.world.entity.animal.rabbit.Rabbit;
+import net.minecraft.world.entity.animal.sheep.Sheep;
+import net.minecraft.world.entity.animal.sniffer.Sniffer;
+import net.minecraft.world.entity.animal.turtle.Turtle;
+import net.minecraft.world.entity.animal.wolf.Wolf;
+import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
+import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
+import net.minecraft.world.entity.boss.wither.WitherBoss;
+import net.minecraft.world.entity.decoration.ArmorStand;
+import net.minecraft.world.entity.decoration.ItemFrame;
+import net.minecraft.world.entity.decoration.painting.Painting;
+import net.minecraft.world.entity.item.PrimedTnt;
+import net.minecraft.world.entity.monster.*;
+import net.minecraft.world.entity.monster.hoglin.Hoglin;
+import net.minecraft.world.entity.monster.illager.Pillager;
+import net.minecraft.world.entity.monster.illager.SpellcasterIllager;
+import net.minecraft.world.entity.monster.piglin.AbstractPiglin;
+import net.minecraft.world.entity.monster.piglin.Piglin;
+import net.minecraft.world.entity.monster.spider.Spider;
+import net.minecraft.world.entity.monster.warden.Warden;
+import net.minecraft.world.entity.monster.zombie.Zombie;
+import net.minecraft.world.entity.monster.zombie.ZombieVillager;
+import net.minecraft.world.entity.npc.villager.AbstractVillager;
+import net.minecraft.world.entity.npc.villager.Villager;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.entity.projectile.EyeOfEnder;
+import net.minecraft.world.entity.projectile.FireworkRocketEntity;
+import net.minecraft.world.entity.projectile.FishingHook;
+import net.minecraft.world.entity.projectile.ThrowableProjectile;
+import net.minecraft.world.entity.projectile.arrow.AbstractArrow;
+import net.minecraft.world.entity.projectile.arrow.Arrow;
+import net.minecraft.world.entity.projectile.arrow.ThrownTrident;
+import net.minecraft.world.entity.projectile.hurtingprojectile.Fireball;
+import net.minecraft.world.entity.projectile.hurtingprojectile.SmallFireball;
+import net.minecraft.world.entity.projectile.hurtingprojectile.WitherSkull;
+import net.minecraft.world.entity.raid.Raider;
+import net.minecraft.world.entity.vehicle.boat.Boat;
+import net.minecraft.world.entity.vehicle.minecart.AbstractMinecart;
+import net.minecraft.world.entity.vehicle.minecart.MinecartCommandBlock;
+import net.minecraft.world.entity.vehicle.minecart.MinecartFurnace;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class EntityDataNameMapper {
+
+ public static final Map, Map> entityDataNames = new HashMap<>();
+
+ public static void registerDataName(Class extends Entity> entityClass, int id, String name) {
+ entityDataNames.computeIfAbsent(entityClass, k -> new HashMap<>()).put(name, id);
+ }
+
+ static {
+ // Entity
+ registerDataName(Entity.class, 0, "entity_flags");
+ registerDataName(Entity.class, 1, "air_ticks");
+ registerDataName(Entity.class, 2, "custom_name");
+ registerDataName(Entity.class, 3, "custom_name_visible");
+ registerDataName(Entity.class, 4, "silent");
+ registerDataName(Entity.class, 5, "no_gravity");
+ registerDataName(Entity.class, 6, "pose");
+ registerDataName(Entity.class, 7, "frozen_ticks");
+
+ // Interaction
+ registerDataName(Interaction.class, 8, "width");
+ registerDataName(Interaction.class, 9, "height");
+ registerDataName(Interaction.class, 10, "responsive");
+
+ // Display
+ registerDataName(Display.class, 8, "transform_interpolation_start");
+ registerDataName(Display.class, 9, "transform_interpolation_duration");
+ registerDataName(Display.class, 10, "movement_interpolation_duration");
+ registerDataName(Display.class, 11, "translation");
+ registerDataName(Display.class, 12, "scale");
+ registerDataName(Display.class, 13, "left_rotation");
+ registerDataName(Display.class, 14, "right_rotation");
+ registerDataName(Display.class, 15, "billboard");
+ registerDataName(Display.class, 16, "brightness");
+ registerDataName(Display.class, 17, "view_range");
+ registerDataName(Display.class, 18, "shadow_radius");
+ registerDataName(Display.class, 19, "shadow_strength");
+ registerDataName(Display.class, 20, "width");
+ registerDataName(Display.class, 21, "height");
+ registerDataName(Display.class, 22, "glow_color");
+
+ // Block display
+ registerDataName(Display.BlockDisplay.class, 23, "material");
+
+ // Item display
+ registerDataName(Display.ItemDisplay.class, 23, "item");
+ registerDataName(Display.ItemDisplay.class, 24, "model_transform");
+
+ // Text display
+ registerDataName(Display.TextDisplay.class, 23, "text");
+ registerDataName(Display.TextDisplay.class, 24, "line_width");
+ registerDataName(Display.TextDisplay.class, 25, "background_color");
+ registerDataName(Display.TextDisplay.class, 26, "text_opacity");
+ registerDataName(Display.TextDisplay.class, 27, "text_display_flags");
+
+ // Thrown item projectile
+ registerDataName(ThrowableProjectile.class, 8, "item");
+
+ // Eye of ender
+ registerDataName(EyeOfEnder.class, 8, "item");
+
+ // Falling block
+ registerDataName(FireworkRocketEntity.class, 8, "spawn_position");
+
+ // Area effect cloud
+ registerDataName(AreaEffectCloud.class, 8, "radius");
+ registerDataName(AreaEffectCloud.class, 9, "color");
+ registerDataName(AreaEffectCloud.class, 10, "waiting");
+ registerDataName(AreaEffectCloud.class, 11, "particle");
+
+ // Fishing hook
+ registerDataName(FishingHook.class, 8, "hooked_entity_id");
+ registerDataName(FishingHook.class, 9, "catchable");
+
+ // Abstract arrow
+ registerDataName(AbstractArrow.class, 8, "abstract_arrow_flags");
+ registerDataName(AbstractArrow.class, 9, "piercing_level");
+
+ // Arrow
+ registerDataName(Arrow.class, 10, "color");
+
+ // Thrown trident
+ registerDataName(ThrownTrident.class, 10, "loyalty_level");
+ registerDataName(ThrownTrident.class, 11, "enchantment_glint");
+
+ // Boat
+ registerDataName(Boat.class, 8, "shaking_ticks");
+ registerDataName(Boat.class, 9, "shaking_direction");
+ registerDataName(Boat.class, 10, "damage_taken");
+ registerDataName(Boat.class, 11, "type");
+ registerDataName(Boat.class, 12, "left_paddle_moving");
+ registerDataName(Boat.class, 13, "right_paddle_moving");
+ registerDataName(Boat.class, 14, "bubble_shaking_ticks");
+
+ // End crystal
+ registerDataName(EndCrystal.class, 8, "beam_target");
+ registerDataName(EndCrystal.class, 9, "showing_bottom");
+
+ // Small fireball
+ registerDataName(SmallFireball.class, 8, "item");
+
+ // Fireball
+ registerDataName(Fireball.class, 8, "item");
+
+ // Wither skull
+ registerDataName(WitherSkull.class, 8, "invulnerable");
+
+ // Firework rocket
+ registerDataName(FireworkRocketEntity.class, 8, "item");
+ registerDataName(FireworkRocketEntity.class, 9, "shooter_id");
+ registerDataName(FireworkRocketEntity.class, 10, "shot_at_angle");
+
+ // Item frame
+ registerDataName(ItemFrame.class, 8, "item");
+ registerDataName(ItemFrame.class, 9, "rotation");
+
+ // Painting
+ registerDataName(Painting.class, 8, "painting_variant");
+
+ // Living entity
+ registerDataName(LivingEntity.class, 8, "living_entity_flags");
+ registerDataName(LivingEntity.class, 9, "health");
+ registerDataName(LivingEntity.class, 10, "potion_effect_color");
+ registerDataName(LivingEntity.class, 11, "is_potion_effect_ambient");
+ registerDataName(LivingEntity.class, 12, "arrows_in_body");
+ registerDataName(LivingEntity.class, 13, "bee_stingers_in_body");
+ registerDataName(LivingEntity.class, 14, "bed_location");
+
+ // Player
+ registerDataName(Player.class, 15, "additional_hearts");
+ registerDataName(Player.class, 16, "score");
+ registerDataName(Player.class, 17, "skin_parts");
+ registerDataName(Player.class, 18, "main_hand");
+ registerDataName(Player.class, 19, "left_shoulder_entity");
+ registerDataName(Player.class, 20, "right_shoulder_entity");
+
+ // Armor stand
+ registerDataName(ArmorStand.class, 15, "armor_stand_flags");
+ registerDataName(ArmorStand.class, 16, "head_rotation");
+ registerDataName(ArmorStand.class, 17, "body_rotation");
+ registerDataName(ArmorStand.class, 18, "left_arm_rotation");
+ registerDataName(ArmorStand.class, 19, "right_arm_rotation");
+ registerDataName(ArmorStand.class, 20, "left_leg_rotation");
+ registerDataName(ArmorStand.class, 21, "right_leg_rotation");
+
+ // Mob
+ registerDataName(Mob.class, 15, "mob_flags");
+
+ // Bat flags
+ registerDataName(Bat.class, 16, "bat_flags");
+
+ // Dolphin
+ registerDataName(Dolphin.class, 16, "treasure_location");
+ registerDataName(Dolphin.class, 17, "has_fish");
+ registerDataName(Dolphin.class, 18, "moisture_level");
+
+ // Abstract Fish
+ registerDataName(AbstractFish.class, 16, "from_bucket");
+
+ // PufferFish
+ registerDataName(Pufferfish.class, 17, "puff_state");
+
+ // Tropical fish
+ registerDataName(TropicalFish.class, 17, "variant");
+
+ // Ageable mob
+ registerDataName(AgeableMob.class, 16, "is_baby");
+
+ // Sniffer
+ registerDataName(Sniffer.class, 17, "sniffer_state");
+ registerDataName(Sniffer.class, 18, "finish_dig_time");
+
+ // Abstract horse
+ registerDataName(AbstractHorse.class, 17, "horse_flags");
+
+ // Horse
+ registerDataName(Horse.class, 18, "variant");
+
+ // Camel
+ registerDataName(Camel.class, 18, "is_dashing");
+ registerDataName(Camel.class, 19, "last_pose_change");
+
+ // Chested horse
+ registerDataName(AbstractChestedHorse.class, 18, "has_chest");
+
+ // Llama
+ registerDataName(Llama.class, 19, "strength");
+ registerDataName(Llama.class, 20, "carpet_color");
+ registerDataName(Llama.class, 21, "variant");
+
+ // Axolotl
+ registerDataName(Axolotl.class, 17, "variant");
+ registerDataName(Axolotl.class, 18, "playing_dead");
+ registerDataName(Axolotl.class, 19, "from_bucket");
+
+ // Bee
+ registerDataName(Bee.class, 17, "bee_flags");
+ registerDataName(Bee.class, 18, "anger_time");
+
+ // Fox
+ registerDataName(Fox.class, 17, "type");
+ registerDataName(Fox.class, 18, "fox_flags");
+ registerDataName(Fox.class, 19, "first_trusted_uuid");
+ registerDataName(Fox.class, 20, "second_trusted_uuid");
+
+ // Frog
+ registerDataName(Frog.class, 17, "variant");
+ registerDataName(Frog.class, 18, "target_id");
+
+ // Ocelot
+ registerDataName(Ocelot.class, 17, "is_trusting");
+
+ // Panda
+ registerDataName(Panda.class, 17, "ask_for_bamboo_timer");
+ registerDataName(Panda.class, 18, "sneeze_timer");
+ registerDataName(Panda.class, 19, "eat_timer");
+ registerDataName(Panda.class, 20, "main_gene");
+ registerDataName(Panda.class, 21, "hidden_gene");
+ registerDataName(Panda.class, 22, "panda_flags");
+
+ // Pig
+ registerDataName(Pig.class, 17, "has_saddle");
+ registerDataName(Pig.class, 18, "boost_ticks");
+
+ // Rabbit
+ registerDataName(Rabbit.class, 17, "type");
+
+ // Turtle
+ registerDataName(Turtle.class, 17, "home_location");
+ registerDataName(Turtle.class, 18, "has_egg");
+ registerDataName(Turtle.class, 19, "laying_egg");
+ registerDataName(Turtle.class, 20, "travel_location");
+ registerDataName(Turtle.class, 21, "going_home");
+ registerDataName(Turtle.class, 20, "traveling");
+
+ // Polar bear
+ registerDataName(PolarBear.class, 17, "standing_up");
+
+ // Hoglin
+ registerDataName(Hoglin.class, 17, "immune_to_zombification");
+
+ // Mooshroom
+ registerDataName(MushroomCow.class, 17, "variant");
+
+ // Sheep
+ registerDataName(Sheep.class, 17, "sheep_wool_flags");
+
+ // Strider
+ registerDataName(Strider.class, 17, "boost_ticks");
+ registerDataName(Strider.class, 18, "shaking");
+ registerDataName(Strider.class, 19, "has_saddle");
+
+ // Tamable animal
+ registerDataName(TamableAnimal.class, 17, "tamable_animal_flags");
+ registerDataName(TamableAnimal.class, 18, "owner");
+
+ // Cat
+ registerDataName(Cat.class, 19, "variant");
+ registerDataName(Cat.class, 20, "lying");
+ registerDataName(Cat.class, 20, "relaxed");
+ registerDataName(Cat.class, 21, "collar_color");
+
+ // Wolf
+ registerDataName(Wolf.class, 19, "begging");
+ registerDataName(Wolf.class, 20, "collar_color");
+ registerDataName(Wolf.class, 21, "anger_time");
+
+ // Parrot
+ registerDataName(Parrot.class, 19, "variant");
+
+ // Abstract villager
+ registerDataName(AbstractVillager.class, 17, "head_shake_ticks");
+
+ // Villager
+ registerDataName(Villager.class, 18, "villager_data");
+
+ // Iron golem
+ registerDataName(IronGolem.class, 16, "iron_golem_flags");
+
+ // Snow golem
+ registerDataName(SnowGolem.class, 16, "snow_golem_pumpkin_flags");
+
+ // Shulker
+ registerDataName(Shulker.class, 16, "attach_face");
+ registerDataName(Shulker.class, 17, "attachment_location");
+ registerDataName(Shulker.class, 18, "peek");
+ registerDataName(Shulker.class, 19, "color");
+
+ // Base piglin
+ registerDataName(AbstractPiglin.class, 16, "immune_to_zombification");
+
+ // Piglin
+ registerDataName(Piglin.class, 17, "is_baby");
+ registerDataName(Piglin.class, 18, "charging_crossbow");
+ registerDataName(Piglin.class, 19, "dancing");
+
+ // Blaze
+ registerDataName(Blaze.class, 16, "blaze_flags");
+
+ // Creeper
+ registerDataName(Creeper.class, 16, "state");
+ registerDataName(Creeper.class, 17, "charged");
+ registerDataName(Creeper.class, 18, "ignited");
+
+ // Goat
+ registerDataName(Goat.class, 17, "screaming");
+ registerDataName(Goat.class, 18, "has_left_horn");
+ registerDataName(Goat.class, 19, "has_right_horn");
+
+ // Guardian
+ registerDataName(Guardian.class, 16, "spikes_retracted");
+ registerDataName(Guardian.class, 17, "target_id");
+
+ // Raider
+ registerDataName(Raider.class, 16, "celebrating");
+
+ // Pillager
+ registerDataName(Pillager.class, 17, "charging_crossbow");
+
+ // Spellcaster illager
+ registerDataName(SpellcasterIllager.class, 17, "spell");
+
+ // Witch
+ registerDataName(Witch.class, 17, "drinking_potion");
+
+ // Vex
+ registerDataName(Vex.class, 16, "vex_flags");
+
+ // Spider
+ registerDataName(Spider.class, 16, "spider_flags");
+
+ // Warden
+ registerDataName(Warden.class, 16, "anger_level");
+
+ // Wither
+ registerDataName(WitherBoss.class, 16, "center_head_target");
+ registerDataName(WitherBoss.class, 17, "left_head_target");
+ registerDataName(WitherBoss.class, 18, "right_head_target");
+ registerDataName(WitherBoss.class, 19, "invulnerable_time");
+
+ // Zoglin
+ registerDataName(Zoglin.class, 16, "is_baby");
+
+ // Zombie
+ registerDataName(Zombie.class, 16, "is_baby");
+ registerDataName(Zombie.class, 17, "type"); // Unused
+ registerDataName(Zombie.class, 18, "converting_in_water");
+
+ // Zombie villager
+ registerDataName(ZombieVillager.class, 19, "is_converting");
+ registerDataName(ZombieVillager.class, 20, "villager_data");
+
+ // Enderman
+ registerDataName(EnderMan.class, 16, "carried_block");
+ registerDataName(EnderMan.class, 17, "screaming");
+ registerDataName(EnderMan.class, 18, "staring");
+
+ // Ender dragon
+ registerDataName(EnderDragon.class, 16, "phase");
+
+ // Ghast
+ registerDataName(Ghast.class, 16, "attacking");
+
+ // Phantom
+ registerDataName(Phantom.class, 16, "size");
+
+ // Slime
+ registerDataName(Slime.class, 16, "size");
+
+ // Abstract minecart
+ registerDataName(AbstractMinecart.class, 8, "shaking_ticks");
+ registerDataName(AbstractMinecart.class, 9, "shaking_direction");
+ registerDataName(AbstractMinecart.class, 10, "damage_taken");
+ registerDataName(AbstractMinecart.class, 11, "display_block_id");
+ registerDataName(AbstractMinecart.class, 12, "display_block_y");
+ registerDataName(AbstractMinecart.class, 13, "show_display_block");
+
+ // Minecraft furnace
+ registerDataName(MinecartFurnace.class, 14, "has_fuel");
+
+ // Minecraft command block
+ registerDataName(MinecartCommandBlock.class, 14, "command");
+ registerDataName(MinecartCommandBlock.class, 15, "last_output");
+
+ // Primed TNT
+ registerDataName(PrimedTnt.class, 8, "fuse_ticks");
+ }
+
+ public static int getIdForName(Class extends Entity> entityClass, String name) {
+ Class> currentClass = entityClass;
+ int id = getIdFromClass(currentClass, name);
+ while (id == -1) {
+ currentClass = currentClass.getSuperclass();
+ if (currentClass == Object.class) {
+ break;
+ }
+ id = getIdFromClass(currentClass, name);
+ }
+ return id;
+ }
+
+ private static int getIdFromClass(Class> entityClass, String name) {
+ Map nameToId = entityDataNames.get(entityClass);
+ int id = nameToId != null ? nameToId.getOrDefault(name, -1) : -1;
+ if (id == -1 && ArgumentHelper.matchesInteger(name)) {
+ id = new ElementTag(name).asInt();
+ }
+ return id;
+ }
+}
diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EntityHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EntityHelperImpl.java
new file mode 100644
index 0000000000..b57de3441d
--- /dev/null
+++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/EntityHelperImpl.java
@@ -0,0 +1,870 @@
+package com.denizenscript.denizen.nms.v1_21.helpers;
+
+import com.denizenscript.denizen.Denizen;
+import com.denizenscript.denizen.nms.NMSHandler;
+import com.denizenscript.denizen.nms.interfaces.EntityHelper;
+import com.denizenscript.denizen.nms.v1_21.Handler;
+import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo;
+import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl;
+import com.denizenscript.denizen.objects.EntityTag;
+import com.denizenscript.denizen.objects.properties.entity.EntityState;
+import com.denizenscript.denizen.utilities.Utilities;
+import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper;
+import com.denizenscript.denizencore.objects.ObjectTag;
+import com.denizenscript.denizencore.objects.core.MapTag;
+import com.denizenscript.denizencore.scripts.commands.core.ReflectionSetCommand;
+import com.denizenscript.denizencore.utilities.ReflectionHelper;
+import com.denizenscript.denizencore.utilities.debugging.Debug;
+import com.denizenscript.denizencore.utilities.text.StringHolder;
+import io.netty.buffer.Unpooled;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import net.kyori.adventure.nbt.CompoundBinaryTag;
+import net.minecraft.commands.arguments.EntityAnchorArgument;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket;
+import net.minecraft.network.protocol.game.ClientboundPlayerLookAtPacket;
+import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
+import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket;
+import net.minecraft.network.syncher.EntityDataAccessor;
+import net.minecraft.network.syncher.SynchedEntityData;
+import net.minecraft.server.dedicated.DedicatedPlayerList;
+import net.minecraft.server.level.ChunkMap;
+import net.minecraft.server.level.ServerEntity;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.network.CommonListenerCookie;
+import net.minecraft.server.players.PlayerList;
+import net.minecraft.util.Mth;
+import net.minecraft.world.InteractionHand;
+import net.minecraft.world.damagesource.CombatRules;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.damagesource.DamageSources;
+import net.minecraft.world.entity.Mob;
+import net.minecraft.world.entity.MoverType;
+import net.minecraft.world.entity.PositionMoveRotation;
+import net.minecraft.world.entity.ai.attributes.Attributes;
+import net.minecraft.world.entity.ai.goal.Goal;
+import net.minecraft.world.entity.ai.navigation.PathNavigation;
+import net.minecraft.world.entity.animal.armadillo.Armadillo;
+import net.minecraft.world.entity.item.FallingBlockEntity;
+import net.minecraft.world.entity.item.ItemEntity;
+import net.minecraft.world.entity.item.PrimedTnt;
+import net.minecraft.world.entity.monster.EnderMan;
+import net.minecraft.world.item.enchantment.EnchantmentHelper;
+import net.minecraft.world.level.ClipContext;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.pathfinder.Path;
+import net.minecraft.world.phys.AABB;
+import net.minecraft.world.phys.BlockHitResult;
+import net.minecraft.world.phys.HitResult;
+import net.minecraft.world.phys.Vec3;
+import net.minecraft.world.phys.shapes.CollisionContext;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.attribute.AttributeInstance;
+import org.bukkit.block.CreatureSpawner;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.craftbukkit.v1_21_R7.CraftServer;
+import org.bukkit.craftbukkit.v1_21_R7.CraftWorld;
+import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlock;
+import org.bukkit.craftbukkit.v1_21_R7.block.CraftCreatureSpawner;
+import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData;
+import org.bukkit.craftbukkit.v1_21_R7.entity.*;
+import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation;
+import org.bukkit.entity.*;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scheduler.BukkitTask;
+import org.bukkit.util.BoundingBox;
+import org.bukkit.util.Vector;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.function.BiConsumer;
+
+public class EntityHelperImpl extends EntityHelper {
+
+ public static final MethodHandle ENTITY_ONGROUND_SETTER = ReflectionHelper.getFinalSetter(net.minecraft.world.entity.Entity.class, ReflectionMappingsInfo.Entity_onGround, boolean.class);
+
+ public static final EntityDataAccessor ENDERMAN_DATA_ACCESSOR_SCREAMING = ReflectionHelper.getFieldValue(EnderMan.class, ReflectionMappingsInfo.EnderMan_DATA_CREEPY, null);
+
+ @Override
+ public void setInvisible(Entity entity, boolean invisible) {
+ ((CraftEntity) entity).getHandle().setInvisible(invisible);
+ }
+
+ @Override
+ public boolean isInvisible(Entity entity) {
+ return ((CraftEntity) entity).getHandle().isInvisible();
+ }
+
+ @Override
+ public void setPose(Entity entity, Pose pose) {
+ ((CraftEntity) entity).getHandle().setPose(net.minecraft.world.entity.Pose.values()[pose.ordinal()]);
+ }
+
+ @Override
+ public double getDamageTo(LivingEntity attacker, Entity target) {
+ double damage = 0;
+ AttributeInstance attrib = attacker.getAttribute(Attribute.ATTACK_DAMAGE);
+ if (attrib != null) {
+ damage = attrib.getValue();
+ }
+ if (damage <= 0) {
+ return 0;
+ }
+ if (target == null) {
+ // Target is required as of MC 1.21, so if unspecified just assume target is equivalent to attacker
+ target = attacker;
+ }
+ DamageSource source;
+ net.minecraft.world.entity.Entity nmsTarget = ((CraftEntity) target).getHandle();
+ ServerLevel nmsWorld = ((CraftWorld) attacker.getWorld()).getHandle();
+ if (attacker instanceof CraftPlayer playerAttacker) {
+ source = nmsTarget.level().damageSources().playerAttack(playerAttacker.getHandle());
+ }
+ else {
+ source = nmsTarget.level().damageSources().mobAttack(((CraftLivingEntity) attacker).getHandle());
+ }
+ net.minecraft.world.entity.LivingEntity nmsLivingTarget = nmsTarget instanceof net.minecraft.world.entity.LivingEntity living ? living : null;
+ if (nmsLivingTarget != null ? nmsLivingTarget.isInvulnerableTo(nmsWorld, source) : nmsTarget.isInvulnerableToBase(source)) {
+ return 0;
+ }
+ if (attacker.getEquipment() != null) {
+ damage = EnchantmentHelper.modifyDamage(nmsWorld, CraftItemStack.asNMSCopy(attacker.getEquipment().getItemInMainHand()), nmsTarget, source, (float) damage);
+ }
+ if (nmsLivingTarget == null) {
+ return damage;
+ }
+ damage = CombatRules.getDamageAfterAbsorb(nmsLivingTarget, (float) damage, source, (float) nmsLivingTarget.getArmorValue(), (float) nmsLivingTarget.getAttributeValue(Attributes.ARMOR_TOUGHNESS));
+ float enchantDamageModifier = EnchantmentHelper.getDamageProtection(nmsWorld, nmsLivingTarget, source);
+ if (enchantDamageModifier > 0) {
+ damage = CombatRules.getDamageAfterMagicAbsorb((float) damage, enchantDamageModifier);
+ }
+ return damage;
+ }
+
+ public static final MethodHandle LIVINGENTITY_AUTOSPINATTACK_SETTER = ReflectionHelper.getFinalSetter(net.minecraft.world.entity.LivingEntity.class, ReflectionMappingsInfo.LivingEntity_autoSpinAttackTicks);
+ public static final MethodHandle LIVINGENTITY_SETLIVINGENTITYFLAG = ReflectionHelper.getMethodHandle(net.minecraft.world.entity.LivingEntity.class, ReflectionMappingsInfo.LivingEntity_setLivingEntityFlag_method, int.class, boolean.class);
+
+ @Override
+ public void setRiptide(Entity entity, boolean state) {
+ try {
+ net.minecraft.world.entity.LivingEntity nmsEntity = ((CraftLivingEntity) entity).getHandle();
+ LIVINGENTITY_AUTOSPINATTACK_SETTER.invoke(nmsEntity, state ? 0 : 1);
+ LIVINGENTITY_SETLIVINGENTITYFLAG.invoke(nmsEntity, 4, true);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ @Override
+ public void forceInteraction(Player player, Location location) {
+ ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle();
+ ((CraftBlock) location.getBlock()).getNMS().useItemOn(nmsPlayer.getMainHandItem(), ((CraftWorld) location.getWorld()).getHandle(),
+ nmsPlayer, InteractionHand.MAIN_HAND,
+ new BlockHitResult(new Vec3(0, 0, 0), null, CraftLocation.toBlockPosition(location), false));
+ }
+
+ @Override
+ public CompoundBinaryTag getNbtData(Entity entity) {
+ CompoundTag nmsTag = Handler.useValueOutput(((CraftEntity) entity).getHandle()::saveAsPassenger);
+ return NBTAdapter.toAPI(nmsTag);
+ }
+
+ @Override
+ public void setNbtData(Entity entity, CompoundBinaryTag compoundTag) {
+ Handler.useValueInput(NBTAdapter.toNMS(compoundTag), ((CraftEntity) entity).getHandle()::load);
+ }
+
+ /*
+ Entity Movement
+ */
+
+ private final static Map followTasks = new HashMap<>();
+
+ @Override
+ public void stopFollowing(Entity follower) {
+ if (follower == null) {
+ return;
+ }
+ UUID uuid = follower.getUniqueId();
+ if (followTasks.containsKey(uuid)) {
+ followTasks.get(uuid).cancel();
+ }
+ }
+
+ @Override
+ public void stopWalking(Entity entity) {
+ if (((CraftEntity) entity).getHandle() instanceof Mob nmsMob) {
+ nmsMob.getNavigation().stop();
+ }
+ }
+
+ @Override
+ public void follow(final Entity target, final Entity follower, final double speed, final double lead,
+ final double maxRange, final boolean allowWander, final boolean teleport) {
+ if (target == null || follower == null) {
+ return;
+ }
+
+ final net.minecraft.world.entity.Entity nmsEntityFollower = ((CraftEntity) follower).getHandle();
+ if (!(nmsEntityFollower instanceof Mob nmsFollower)) {
+ return;
+ }
+ final PathNavigation followerNavigation = nmsFollower.getNavigation();
+
+ UUID uuid = follower.getUniqueId();
+
+ if (followTasks.containsKey(uuid)) {
+ followTasks.get(uuid).cancel();
+ }
+
+ final int locationNearInt = (int) Math.floor(lead);
+ final boolean hasMax = maxRange > lead;
+
+ followTasks.put(follower.getUniqueId(), new BukkitRunnable() {
+
+ private boolean inRadius = false;
+
+ public void run() {
+ if (!target.isValid() || !follower.isValid()) {
+ this.cancel();
+ }
+ followerNavigation.setSpeedModifier(2D);
+ Location targetLocation = target.getLocation();
+ Path path;
+
+ if (hasMax && !Utilities.checkLocation(targetLocation, follower.getLocation(), maxRange)
+ && !target.isDead() && target.isOnGround()) {
+ if (!inRadius) {
+ if (teleport) {
+ follower.teleport(Utilities.getWalkableLocationNear(targetLocation, locationNearInt));
+ }
+ else {
+ cancel();
+ }
+ }
+ else {
+ inRadius = false;
+ path = followerNavigation.createPath(targetLocation.getX(), targetLocation.getY(), targetLocation.getZ(), 0);
+ if (path != null) {
+ followerNavigation.moveTo(path, 1D);
+ followerNavigation.setSpeedModifier(2D);
+ }
+ }
+ }
+ else if (!inRadius && !Utilities.checkLocation(targetLocation, follower.getLocation(), lead)) {
+ path = followerNavigation.createPath(targetLocation.getX(), targetLocation.getY(), targetLocation.getZ(), 0);
+ if (path != null) {
+ followerNavigation.moveTo(path, 1D);
+ followerNavigation.setSpeedModifier(2D);
+ }
+ }
+ else {
+ inRadius = true;
+ }
+ if (inRadius && !allowWander) {
+ followerNavigation.stop();
+ }
+ nmsFollower.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(speed);
+ }
+ }.runTaskTimer(NMSHandler.getJavaPlugin(), 0, 10));
+ }
+
+ @Override
+ public void walkTo(final LivingEntity entity, Location location, Double speed, final Runnable callback) {
+ if (entity == null || location == null) {
+ return;
+ }
+ net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle();
+ if (!(nmsEntity instanceof final Mob nmsMob)) {
+ return;
+ }
+ final PathNavigation entityNavigation = nmsMob.getNavigation();
+ final Path path;
+ final boolean aiDisabled = !entity.hasAI();
+ if (aiDisabled) {
+ entity.setAI(true);
+ try {
+ ENTITY_ONGROUND_SETTER.invoke(nmsMob, true);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+ path = entityNavigation.createPath(location.getX(), location.getY(), location.getZ(), 1);
+ if (path != null) {
+ nmsMob.goalSelector.enableControlFlag(Goal.Flag.MOVE);
+ entityNavigation.moveTo(path, 1D);
+ final double oldSpeed = nmsMob.getAttribute(Attributes.MOVEMENT_SPEED).getBaseValue();
+ if (speed != null) {
+ nmsMob.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(speed);
+ }
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if (!entity.isValid()) {
+ if (callback != null) {
+ callback.run();
+ }
+ cancel();
+ return;
+ }
+ if (aiDisabled && entity instanceof Wolf wolf) {
+ wolf.setAngry(false);
+ }
+ if (entityNavigation.isDone() || path.isDone()) {
+ if (callback != null) {
+ callback.run();
+ }
+ if (speed != null) {
+ nmsMob.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(oldSpeed);
+ }
+ if (aiDisabled) {
+ entity.setAI(false);
+ }
+ cancel();
+ }
+ }
+ }.runTaskTimer(NMSHandler.getJavaPlugin(), 1, 1);
+ }
+ //if (!Utilities.checkLocation(location, entity.getLocation(), 20)) {
+ // TODO: generate waypoints to the target location?
+ else {
+ entity.teleport(location);
+ }
+ }
+
+ @Override
+ public void sendAllUpdatePackets(Entity entity) {
+ ChunkMap tracker = ((ServerLevel) ((CraftEntity) entity).getHandle().level()).getChunkSource().chunkMap;
+ ChunkMap.TrackedEntity entityTracker = tracker.entityMap.get(entity.getEntityId());
+ if (entityTracker == null) {
+ return;
+ }
+ try {
+ ServerEntity serverEntity = (ServerEntity) PacketHelperImpl.ENTITY_TRACKER_ENTRY_GETTER.get(entityTracker);
+ serverEntity.sendChanges();
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ /*
+ Hide Entity
+ */
+
+ @Override
+ public void sendHidePacket(Player pl, Entity entity) {
+ if (entity instanceof Player player) {
+ pl.hidePlayer(Denizen.getInstance(), player);
+ return;
+ }
+ ServerPlayer nmsPlayer = ((CraftPlayer) pl).getHandle();
+ if (nmsPlayer.connection != null && !pl.equals(entity)) {
+ ChunkMap.TrackedEntity entry = nmsPlayer.level().getChunkSource().chunkMap.entityMap.get(entity.getEntityId());
+ if (entry != null) {
+ entry.removePlayer(nmsPlayer);
+ }
+ if (Denizen.supportsPaper) { // Workaround for Paper issue
+ nmsPlayer.connection.send(new ClientboundRemoveEntitiesPacket(entity.getEntityId()));
+ }
+ }
+ }
+
+ @Override
+ public void sendShowPacket(Player pl, Entity entity) {
+ if (entity instanceof Player player) {
+ pl.showPlayer(Denizen.getInstance(), player);
+ return;
+ }
+ ServerPlayer nmsPlayer = ((CraftPlayer) pl).getHandle();
+ if (nmsPlayer.connection != null && !pl.equals(entity)) {
+ ChunkMap.TrackedEntity entry = nmsPlayer.level().getChunkSource().chunkMap.entityMap.get(entity.getEntityId());
+ if (entry != null) {
+ entry.removePlayer(nmsPlayer);
+ entry.updatePlayer(nmsPlayer);
+ }
+ }
+ }
+
+ @Override
+ public void rotate(Entity entity, float yaw, float pitch) {
+ // If this entity is a real player instead of a player type NPC,
+ // it will appear to be online
+ if (entity instanceof Player player && player.isOnline()) {
+ NetworkInterceptHelper.enable();
+ float relYaw = (yaw - entity.getLocation().getYaw()) % 360;
+ if (relYaw > 180) {
+ relYaw -= 360;
+ }
+ final float actualRelYaw = relYaw;
+ float relPitch = pitch - entity.getLocation().getPitch();
+ NMSHandler.packetHelper.sendRelativeLookPacket(player, actualRelYaw, relPitch);
+ }
+ else if (entity instanceof LivingEntity) {
+ if (entity instanceof EnderDragon) {
+ yaw = normalizeYaw(yaw - 180);
+ }
+ look(entity, yaw, pitch);
+ }
+ else {
+ net.minecraft.world.entity.Entity handle = ((CraftEntity) entity).getHandle();
+ handle.setYRot(yaw - 360);
+ handle.setXRot(pitch);
+ }
+ }
+
+ @Override
+ public float getBaseYaw(LivingEntity entity) {
+ return ((CraftLivingEntity) entity).getHandle().yBodyRot;
+ }
+
+ @Override
+ public void look(Entity entity, float yaw, float pitch) {
+ net.minecraft.world.entity.Entity handle = ((CraftEntity) entity).getHandle();
+ if (handle == null) {
+ Debug.echoError("Cannot set look direction for unspawned entity " + entity.getUniqueId());
+ return;
+ }
+ handle.setYRot(yaw);
+ if (handle instanceof net.minecraft.world.entity.LivingEntity nmsLivingEntity) {
+ while (yaw < -180.0F) {
+ yaw += 360.0F;
+ }
+ while (yaw >= 180.0F) {
+ yaw -= 360.0F;
+ }
+ nmsLivingEntity.yBodyRotO = yaw;
+ if (!(handle instanceof net.minecraft.world.entity.player.Player)) {
+ nmsLivingEntity.setYBodyRot(yaw);
+ }
+ nmsLivingEntity.setYHeadRot(yaw);
+ }
+ handle.setXRot(pitch);
+ }
+
+ private static HitResult rayTrace(World world, Vector start, Vector end) {
+ try {
+ NMSHandler.chunkHelper.changeChunkServerThread(world);
+ return ((CraftWorld) world).getHandle().clip(new ClipContext(new Vec3(start.getX(), start.getY(), start.getZ()),
+ new Vec3(end.getX(), end.getY(), end.getZ()),
+ ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, CollisionContext.empty()));
+ }
+ finally {
+ NMSHandler.chunkHelper.restoreServerThread(world);
+ }
+ }
+
+ @Override
+ public boolean canTrace(World world, Vector start, Vector end) {
+ HitResult pos = rayTrace(world, start, end);
+ if (pos == null) {
+ return true;
+ }
+ return pos.getType() == HitResult.Type.MISS;
+ }
+
+ @Override
+ public void snapPositionTo(Entity entity, Vector vector) {
+ ((CraftEntity) entity).getHandle().setPosRaw(vector.getX(), vector.getY(), vector.getZ());
+ }
+
+ @Override
+ public void move(Entity entity, Vector vector) {
+ ((CraftEntity) entity).getHandle().move(MoverType.SELF, new Vec3(vector.getX(), vector.getY(), vector.getZ()));
+ }
+
+ @Override
+ public boolean internalLook(Player player, Location at) {
+ PacketHelperImpl.send(player, new ClientboundPlayerLookAtPacket(EntityAnchorArgument.Anchor.EYES, at.getX(), at.getY(), at.getZ()));
+ return true;
+ }
+
+ public static long entityToPacket(double x) {
+ return Mth.lfloor(x * 4096.0D);
+ }
+
+ @Override
+ public void fakeMove(Entity entity, Vector vector) {
+ long x = entityToPacket(vector.getX());
+ long y = entityToPacket(vector.getY());
+ long z = entityToPacket(vector.getZ());
+ ClientboundMoveEntityPacket packet = new ClientboundMoveEntityPacket.Pos(entity.getEntityId(), (short) x, (short) y, (short) z, entity.isOnGround());
+ for (Player player : getPlayersThatSee(entity)) {
+ PacketHelperImpl.send(player, packet);
+ }
+ }
+
+ @Override
+ public void fakeTeleport(Entity entity, Location location) {
+ FriendlyByteBuf packetData = new FriendlyByteBuf(Unpooled.buffer());
+ // Referenced from ClientboundTeleportEntityPacket source
+ packetData.writeVarInt(entity.getEntityId());
+ packetData.writeDouble(location.getX());
+ packetData.writeDouble(location.getY());
+ packetData.writeDouble(location.getZ());
+ packetData.writeByte((byte)((int)(location.getYaw() * 256.0F / 360.0F)));
+ packetData.writeByte((byte)((int)(location.getPitch() * 256.0F / 360.0F)));
+ packetData.writeBoolean(entity.isOnGround());
+ ClientboundTeleportEntityPacket packet = ClientboundTeleportEntityPacket.STREAM_CODEC.decode(packetData);
+ for (Player player : getPlayersThatSee(entity)) {
+ PacketHelperImpl.send(player, packet);
+ }
+ }
+
+ @Override
+ public void clientResetLoc(Entity entity) {
+ ClientboundTeleportEntityPacket packet = new ClientboundTeleportEntityPacket(entity.getEntityId(), PositionMoveRotation.of(((CraftEntity) entity).getHandle()), Set.of(), entity.isOnGround());
+ for (Player player : getPlayersThatSee(entity)) {
+ PacketHelperImpl.send(player, packet);
+ }
+ }
+
+ @Override
+ public void teleport(Entity entity, Location loc) {
+ net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle();
+ nmsEntity.setYRot(loc.getYaw());
+ nmsEntity.setXRot(loc.getPitch());
+ if (nmsEntity instanceof ServerPlayer) {
+ nmsEntity.teleportTo(loc.getX(), loc.getY(), loc.getZ());
+ }
+ nmsEntity.setPos(loc.getX(), loc.getY(), loc.getZ());
+ }
+
+ @Override
+ public void setBoundingBox(Entity entity, BoundingBox box) {
+ ((CraftEntity) entity).getHandle().setBoundingBox(new AABB(box.getMinX(), box.getMinY(), box.getMinZ(), box.getMaxX(), box.getMaxY(), box.getMaxZ()));
+ }
+
+ public static final Field EXPERIENCE_ORB_AGE = ReflectionHelper.getFields(net.minecraft.world.entity.ExperienceOrb.class).get(ReflectionMappingsInfo.ExperienceOrb_age, int.class);
+
+ @Override
+ public void setTicksLived(Entity entity, int ticks) {
+ // Bypass Spigot's must-be-at-least-1-tick requirement, as negative tick counts are useful
+ ((CraftEntity) entity).getHandle().tickCount = ticks;
+ if (entity instanceof CraftFallingBlock craftFallingBlock) {
+ craftFallingBlock.getHandle().time = ticks;
+ }
+ else if (entity instanceof CraftItem craftItem) {
+ ((ItemEntity) craftItem.getHandle()).age = ticks;
+ }
+ else if (entity instanceof CraftExperienceOrb craftExperienceOrb) {
+ try {
+ EXPERIENCE_ORB_AGE.setInt(craftExperienceOrb.getHandle(), ticks);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+ }
+
+ @Override
+ public void setHeadAngle(LivingEntity entity, float angle) {
+ ((CraftLivingEntity) entity).getHandle().setYHeadRot(angle);
+ }
+
+ @Override
+ public void setEndermanAngry(Enderman enderman, boolean angry) {
+ ((CraftEnderman) enderman).getHandle().getEntityData().set(ENDERMAN_DATA_ACCESSOR_SCREAMING, angry);
+ }
+
+ public static class FakeDamageSrc extends DamageSource { public DamageSource real; public FakeDamageSrc(DamageSource src) { super(null); real = src; } }
+
+ public static DamageSources backupDamageSources;
+
+ public static DamageSources getReusableDamageSources() {
+ if (backupDamageSources == null) {
+ backupDamageSources = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle().damageSources();
+ }
+ return backupDamageSources;
+ }
+
+ public static DamageSource getSourceFor(net.minecraft.world.entity.Entity nmsSource, EntityDamageEvent.DamageCause cause, net.minecraft.world.entity.Entity nmsSourceProvider) {
+ DamageSources sources = nmsSourceProvider == null ? getReusableDamageSources() : nmsSourceProvider.level().damageSources();
+ DamageSource src = sources.generic();
+ if (nmsSource != null) {
+ if (nmsSource instanceof net.minecraft.world.entity.player.Player nmsPlayer) {
+ src = nmsSource.level().damageSources().playerAttack(nmsPlayer);
+ }
+ else if (nmsSource instanceof net.minecraft.world.entity.LivingEntity nmsLivingEntity) {
+ src = nmsSource.level().damageSources().mobAttack(nmsLivingEntity);
+ }
+ }
+ if (cause == null) {
+ return src;
+ }
+ return switch (cause) {
+ case CONTACT -> sources.cactus();
+ case ENTITY_ATTACK -> sources.mobAttack(nmsSource instanceof net.minecraft.world.entity.LivingEntity nmsLivingEntity ? nmsLivingEntity : null);
+ case ENTITY_SWEEP_ATTACK -> src != sources.generic() ? src.sweep() : src;
+ case PROJECTILE -> sources.thrown(nmsSource, nmsSource != null && nmsSource.getBukkitEntity() instanceof Projectile projectile
+ && projectile.getShooter() instanceof CraftEntity shooter ? shooter.getHandle() : null);
+ case SUFFOCATION -> sources.inWall();
+ case FALL -> sources.fall();
+ case FIRE -> sources.inFire();
+ case FIRE_TICK -> sources.onFire();
+ case MELTING -> sources.melting();
+ case LAVA -> sources.lava();
+ case DROWNING -> sources.drown();
+ case BLOCK_EXPLOSION -> nmsSource instanceof PrimedTnt primedTnt ? sources.explosion(primedTnt, primedTnt.getOwner()) : sources.explosion(null);
+ case ENTITY_EXPLOSION -> sources.explosion(nmsSource, null);
+ case VOID -> sources.fellOutOfWorld();
+ case LIGHTNING -> sources.lightningBolt();
+ case STARVATION -> sources.starve();
+ case POISON -> sources.poison();
+ case MAGIC -> sources.magic();
+ case WITHER -> sources.wither();
+ case FALLING_BLOCK -> sources.fallingBlock(nmsSource);
+ case THORNS -> sources.thorns(nmsSource);
+ case DRAGON_BREATH -> sources.dragonBreath();
+ case CUSTOM -> sources.generic();
+ case FLY_INTO_WALL -> sources.flyIntoWall();
+ case HOT_FLOOR -> sources.hotFloor();
+ case CAMPFIRE -> sources.campfire();
+ case CRAMMING -> sources.cramming();
+ case DRYOUT -> sources.dryOut();
+ case FREEZE -> sources.freeze();
+ case SONIC_BOOM -> sources.sonicBoom(nmsSource);
+ case WORLD_BORDER -> sources.outOfBorder();
+ case KILL -> sources.genericKill();
+ case SUICIDE -> new FakeDamageSrc(src);
+ };
+ }
+
+ @Override
+ public void damage(LivingEntity target, float amount, EntityTag source, Location sourceLoc, EntityDamageEvent.DamageCause cause) {
+ if (target == null) {
+ return;
+ }
+ net.minecraft.world.entity.LivingEntity nmsTarget = ((CraftLivingEntity) target).getHandle();
+ net.minecraft.world.entity.Entity nmsSource = source == null ? null : ((CraftEntity) source.getBukkitEntity()).getHandle();
+ DamageSource src = getSourceFor(nmsSource, cause, nmsTarget);
+ if (src instanceof FakeDamageSrc fakeDamageSrc) {
+ src = fakeDamageSrc.real;
+ if (fireFakeDamageEvent(target, source, sourceLoc, cause, amount).isCancelled()) {
+ return;
+ }
+ }
+ nmsTarget.hurt(src, amount);
+ }
+
+ @Override
+ public void setLastHurtBy(LivingEntity mob, LivingEntity damager) {
+ ((CraftLivingEntity) mob).getHandle().setLastHurtByMob(((CraftLivingEntity) damager).getHandle());
+ }
+
+ public static final Field FALLINGBLOCK_BLOCK_STATE = ReflectionHelper.getFields(FallingBlockEntity.class).getFirstOfType(BlockState.class);
+
+ @Override
+ public void setFallingBlockType(FallingBlock fallingBlock, BlockData block) {
+ BlockState state = ((CraftBlockData) block).getState();
+ FallingBlockEntity nmsEntity = ((CraftFallingBlock) fallingBlock).getHandle();
+ try {
+ FALLINGBLOCK_BLOCK_STATE.set(nmsEntity, state);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ @Override
+ public EntityTag getMobSpawnerDisplayEntity(CreatureSpawner spawner) {
+ SpawnerBlockEntity nmsSpawner = BlockHelperImpl.getTE((CraftCreatureSpawner) spawner);
+ ServerLevel level = ((CraftWorld) spawner.getWorld()).getHandle();
+ net.minecraft.world.entity.Entity nmsEntity = nmsSpawner.getSpawner().getOrCreateDisplayEntity(level, nmsSpawner.getBlockPos());
+ return new EntityTag(nmsEntity.getBukkitEntity());
+ }
+
+ public static final Field ZOMBIE_INWATERTIME = ReflectionHelper.getFields(net.minecraft.world.entity.monster.zombie.Zombie.class).get(ReflectionMappingsInfo.Zombie_inWaterTime, int.class);
+
+ @Override
+ public int getInWaterTime(Zombie zombie) {
+ try {
+ return ZOMBIE_INWATERTIME.getInt(((CraftZombie) zombie).getHandle());
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ return 0;
+ }
+ }
+
+ @Override
+ public void setInWaterTime(Zombie zombie, int ticks) {
+ try {
+ ZOMBIE_INWATERTIME.setInt(((CraftZombie) zombie).getHandle(), ticks);
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ public static final MethodHandle TRACKING_RANGE_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ChunkMap.TrackedEntity.class, int.class);
+
+ @Override
+ public void setTrackingRange(Entity entity, int range) {
+ try {
+ ChunkMap map = ((CraftWorld) entity.getWorld()).getHandle().getChunkSource().chunkMap;
+ ChunkMap.TrackedEntity entry = map.entityMap.get(entity.getEntityId());
+ if (entry != null) {
+ TRACKING_RANGE_SETTER.invoke(entry, range);
+ }
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ @Override
+ public boolean isAggressive(org.bukkit.entity.Mob mob) {
+ return ((CraftMob) mob).getHandle().isAggressive();
+ }
+
+ @Override
+ public void setAggressive(org.bukkit.entity.Mob mob, boolean aggressive) {
+ ((CraftMob) mob).getHandle().setAggressive(aggressive);
+ }
+
+ // Use reflection because Paper changes the method return type
+ public static final MethodHandle PLAYERLIST_REMOVE = ReflectionHelper.getMethodHandle(PlayerList.class, "remove", ServerPlayer.class);
+
+ @Override
+ public void setUUID(Entity entity, UUID id) {
+ try {
+ net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle();
+ nmsEntity.stopRiding();
+ nmsEntity.getPassengers().forEach(net.minecraft.world.entity.Entity::stopRiding);
+ Level level = nmsEntity.level();
+ DedicatedPlayerList playerList = ((CraftServer) Bukkit.getServer()).getHandle();
+ if (nmsEntity instanceof ServerPlayer nmsPlayer) {
+ PLAYERLIST_REMOVE.invoke(playerList, nmsPlayer);
+ }
+ else {
+ nmsEntity.remove(net.minecraft.world.entity.Entity.RemovalReason.DISCARDED);
+ }
+ nmsEntity.unsetRemoved();
+ nmsEntity.setUUID(id);
+ if (nmsEntity instanceof ServerPlayer nmsPlayer) {
+ playerList.placeNewPlayer(DenizenNetworkManagerImpl.getConnection(nmsPlayer), nmsPlayer, new CommonListenerCookie(nmsPlayer.getGameProfile(), nmsPlayer.connection.latency(), nmsPlayer.clientInformation(), nmsPlayer.connection.isTransferred()));
+ }
+ else {
+ level.addFreshEntity(nmsEntity);
+ }
+ }
+ catch (Throwable ex) {
+ Debug.echoError(ex);
+ }
+ }
+
+ public static final Field SynchedEntityData_itemsById = ReflectionHelper.getFields(SynchedEntityData.class).get(ReflectionMappingsInfo.SynchedEntityData_itemsById);
+
+ public static Int2ObjectMap> getDataItems(Entity entity) {
+ try {
+ return (Int2ObjectMap>) SynchedEntityData_itemsById.get(((CraftEntity) entity).getHandle().getEntityData());
+ }
+ catch (IllegalAccessException e) {
+ throw new RuntimeException(e); // Stop the code here to avoid NPEs down the road
+ }
+ }
+
+ public static void convertToInternalData(Entity entity, MapTag internalData, BiConsumer, Object> processConverted) {
+ Int2ObjectMap> dataItemsById = getDataItems(entity);
+ for (Map.Entry entry : internalData.entrySet()) {
+ int id = EntityDataNameMapper.getIdForName(((CraftEntity) entity).getHandle().getClass(), entry.getKey().low);
+ if (id == -1) {
+ Debug.echoError("Invalid internal data key: " + entry.getKey());
+ return;
+ }
+ SynchedEntityData.DataItem