From 3fdc1dabe8008ba284287014b263564646bfa0d8 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 12 Jul 2025 23:55:39 +0100 Subject: [PATCH 001/169] Initial cleanups & optimizations --- .../nms/v1_21/ReflectionMappingsInfo.java | 4 + .../network/handlers/FakeBlockHelper.java | 142 ++++++++++-------- .../packet/FakeBlocksPacketHandlers.java | 2 +- 3 files changed, 87 insertions(+), 61 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 91b55ad7f6..0fbee1ebbe 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -98,6 +98,7 @@ public class ReflectionMappingsInfo { public static String ClientboundSetPassengersPacket_passengers = "c"; // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo + public static String ClientboundLevelChunkPacketDataBlockEntityInfo_create_method = "a"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "c"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_y = "d"; @@ -126,4 +127,7 @@ public class ReflectionMappingsInfo { // net.minecraft.stats.ServerRecipeBook public static String ServerRecipeBook_addHighlight_method = "e"; + + // net.minecraft.world.level.block.entity.BlockEntityType + public static String BlockEntityType_validBlocks = "Y"; } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index ff41dfa046..286b092508 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -8,10 +8,11 @@ import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.world.level.biome.Biome; @@ -22,38 +23,56 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.PalettedContainer; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockStates; +import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockType; import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; public class FakeBlockHelper { public static Field CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getFirstOfType(List.class); + public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); + public static final MethodHandle CHUNK_DATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); - public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 3).findFirst().get(); + public static Field BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).get(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); + + public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); + + static { + try { + for (BlockEntityType nmsBlockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.get(nmsBlockEntityType); + for (Block validBlock : validBlocks) { + MATERIAL_BLOCK_ENTITY_TYPES.put(CraftBlockType.minecraftToBukkit(validBlock), nmsBlockEntityType); + } + } + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } public static BlockState getNMSState(FakeBlock block) { return ((CraftBlockData) block.material.getModernData()).getState(); } - public static boolean anyBlocksInSection(List blocks, int y) { - int minY = y << 4; - int maxY = (y << 4) + 16; - for (FakeBlock block : blocks) { + public static boolean anyBlocksInSection(List blocksInChunk, int y) { + int minY = SectionPos.sectionToBlockCoord(y); + int maxY = minY + 16; + for (FakeBlock block : blocksInChunk) { int blockY = block.location.getBlockY(); if (blockY >= minY && blockY < maxY) { return true; @@ -65,7 +84,7 @@ public static boolean anyBlocksInSection(List blocks, int y) { public static Field PAPER_CHUNK_READY; public static boolean tryPaperPatch = true; - public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket newPacket, ClientboundLevelChunkWithLightPacket oldPacket) { + public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket newPacket) { if (!Denizen.supportsPaper || !tryPaperPatch) { return; } @@ -88,57 +107,54 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalPacket, int chunkX, int chunkZ, List blocks) { + public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) { try { - ClientboundLevelChunkWithLightPacket duplicateCorePacket = DenizenNetworkManagerImpl.copyPacket(originalPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); - copyPacketPaperPatch(duplicateCorePacket, originalPacket); - RegistryFriendlyByteBuf copier = new RegistryFriendlyByteBuf(Unpooled.buffer(), CraftRegistry.getMinecraftRegistry()); - originalPacket.getChunkData().write(copier); - ClientboundLevelChunkPacketData packet = new ClientboundLevelChunkPacketData(copier, chunkX, chunkZ); - FriendlyByteBuf serial = originalPacket.getChunkData().getReadBuffer(); - FriendlyByteBuf outputSerial = new FriendlyByteBuf(Unpooled.buffer(serial.readableBytes())); - List blockEntities = new ArrayList((List) CHUNKDATA_BLOCK_ENTITIES.get(originalPacket.getChunkData())); - CHUNKDATA_BLOCK_ENTITIES.set(packet, blockEntities); - for (int i = 0; i < blockEntities.size(); i++) { - Object blockEnt = blockEntities.get(i); + ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(copiedChunkPacket); + // A list of block entities sent with the chunk data + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + LocationTag location = new LocationTag(world, 0, 0, 0); + ListIterator blockEntitiesIterator = blockEntities.listIterator(); + while (blockEntitiesIterator.hasNext()) { + Object blockEnt = blockEntitiesIterator.next(); int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); - int x = (chunkX << 4) + ((xz >> 4) & 15); - int z = (chunkZ << 4) + (xz & 15); - for (FakeBlock block : blocks) { - LocationTag loc = block.location; - if (loc.getBlockX() == x && loc.getBlockY() == y && loc.getBlockZ() == z && block.material != null) { - BlockEntity newBlockEnt = CraftBlockStates.createNewTileEntity(block.material.getMaterial()); - Object newData = CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR.invoke(xz, y, newBlockEnt.getType(), newBlockEnt.getUpdateTag(CraftRegistry.getMinecraftRegistry())); - blockEntities.set(i, newData); - break; - } + int relativeX = SectionPos.sectionRelative(xz >> 4); + int relativeZ = SectionPos.sectionRelative(xz); + int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; + int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; + location.setX(x); + location.setY(y); + location.setZ(z); + if (fakeBlockMap.byLocation.containsKey(location)) { + blockEntitiesIterator.remove(); } } + // Get the original chunk data to read, and a buf of the same size to write + FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); int worldMinY = world.getMinHeight(); int worldMaxY = world.getMaxHeight(); - int minChunkY = worldMinY >> 4; - int maxChunkY = worldMaxY >> 4; - Registry biomeRegistry = ((CraftWorld) world).getHandle().registryAccess().lookupOrThrow(Registries.BIOME); + int minChunkY = SectionPos.blockToSectionCoord(worldMinY); + int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + // These are section coords, iterating through every chunk section for (int y = minChunkY; y < maxChunkY; y++) { - int blockCount = serial.readShort(); - // reflected constructors as workaround for spigot remapper bug - Mojang "IdMap" became Spigot "IRegistry" but should be "Registry" - PalettedContainer states = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - states.read(serial); - PalettedContainer biomes = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(biomeRegistry, biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); - biomes.read(serial); - if (anyBlocksInSection(blocks, y)) { - int minY = y << 4; - int maxY = (y << 4) + 16; - for (FakeBlock block : blocks) { + int blockCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + states.read(rawChunkData); + PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + biomes.read(rawChunkData); + if (anyBlocksInSection(blocksInChunk, y)) { + int minY = SectionPos.sectionToBlockCoord(y); + int maxY = minY + 16; + for (FakeBlock block : blocksInChunk) { int blockY = block.location.getBlockY(); if (blockY >= minY && blockY < maxY && block.material != null) { - int blockX = block.location.getBlockX(); - int blockZ = block.location.getBlockZ(); - blockX -= (blockX >> 4) * 16; - blockY -= (blockY >> 4) * 16; - blockZ -= (blockZ >> 4) * 16; - BlockState oldState = states.get(blockX, blockY, blockZ); + int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(blockY); + int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); BlockState newState = getNMSState(block); if (oldState.isAir() && !newState.isAir()) { blockCount++; @@ -146,18 +162,24 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo else if (newState.isAir() && !oldState.isAir()) { blockCount--; } - states.set(blockX, blockY, blockZ, newState); + states.set(relativeX, relativeY, relativeZ, newState); + BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (nmsBlockEntityType == null) { + continue; + } + BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); } } } - outputSerial.writeShort(blockCount); - states.write(outputSerial); - biomes.write(outputSerial); + newChunkData.writeShort(blockCount); + states.write(newChunkData); + biomes.write(newChunkData); } - byte[] outputBytes = outputSerial.array(); - CHUNKDATA_BUFFER_SETTER.invoke(packet, outputBytes); - CHUNKPACKET_CHUNKDATA_SETTER.invoke(duplicateCorePacket, packet); - return duplicateCorePacket; + CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + return copiedChunkPacket; } catch (Throwable ex) { Debug.echoError(ex); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 4938114cac..52ed0f191d 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -47,7 +47,7 @@ public static Packet processShowFakeForPacket(DenizenN if (blocks == null || blocks.isEmpty()) { return packet; } - ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks); + ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); return newPacket; } else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { From b4b800668b3a1f005b35a93b41dd38e81930846a Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 12 Jul 2025 23:57:54 +0100 Subject: [PATCH 002/169] Remove unnecessary `try` --- .../network/handlers/FakeBlockHelper.java | 138 +++++++++--------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 286b092508..a01beda1ce 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -107,83 +107,77 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) { - try { - ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); - copyPacketPaperPatch(copiedChunkPacket); - // A list of block entities sent with the chunk data - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); - LocationTag location = new LocationTag(world, 0, 0, 0); - ListIterator blockEntitiesIterator = blockEntities.listIterator(); - while (blockEntitiesIterator.hasNext()) { - Object blockEnt = blockEntitiesIterator.next(); - int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); - int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); - int relativeX = SectionPos.sectionRelative(xz >> 4); - int relativeZ = SectionPos.sectionRelative(xz); - int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; - int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; - location.setX(x); - location.setY(y); - location.setZ(z); - if (fakeBlockMap.byLocation.containsKey(location)) { - blockEntitiesIterator.remove(); - } + public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { + ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(copiedChunkPacket); + // A list of block entities sent with the chunk data + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + LocationTag location = new LocationTag(world, 0, 0, 0); + ListIterator blockEntitiesIterator = blockEntities.listIterator(); + while (blockEntitiesIterator.hasNext()) { + Object blockEnt = blockEntitiesIterator.next(); + int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); + int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int relativeX = SectionPos.sectionRelative(xz >> 4); + int relativeZ = SectionPos.sectionRelative(xz); + int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; + int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; + location.setX(x); + location.setY(y); + location.setZ(z); + if (fakeBlockMap.byLocation.containsKey(location)) { + blockEntitiesIterator.remove(); } - // Get the original chunk data to read, and a buf of the same size to write - FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); - FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); - int worldMinY = world.getMinHeight(); - int worldMaxY = world.getMaxHeight(); - int minChunkY = SectionPos.blockToSectionCoord(worldMinY); - int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); - Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); - // These are section coords, iterating through every chunk section - for (int y = minChunkY; y < maxChunkY; y++) { - int blockCount = rawChunkData.readShort(); - PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - states.read(rawChunkData); - PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); - biomes.read(rawChunkData); - if (anyBlocksInSection(blocksInChunk, y)) { - int minY = SectionPos.sectionToBlockCoord(y); - int maxY = minY + 16; - for (FakeBlock block : blocksInChunk) { - int blockY = block.location.getBlockY(); - if (blockY >= minY && blockY < maxY && block.material != null) { - int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); - int relativeY = SectionPos.sectionRelative(blockY); - int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); - BlockState oldState = states.get(relativeX, relativeY, relativeZ); - BlockState newState = getNMSState(block); - if (oldState.isAir() && !newState.isAir()) { - blockCount++; - } - else if (newState.isAir() && !oldState.isAir()) { - blockCount--; - } - states.set(relativeX, relativeY, relativeZ, newState); - BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); - if (nmsBlockEntityType == null) { - continue; - } - BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); - Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); - blockEntities.add(packetBlockEntityData); + } + // Get the original chunk data to read, and a buf of the same size to write + FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); + int worldMinY = world.getMinHeight(); + int worldMaxY = world.getMaxHeight(); + int minChunkY = SectionPos.blockToSectionCoord(worldMinY); + int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + // These are section coords, iterating through every chunk section + for (int y = minChunkY; y < maxChunkY; y++) { + int blockCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + states.read(rawChunkData); + PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + biomes.read(rawChunkData); + if (anyBlocksInSection(blocksInChunk, y)) { + int minY = SectionPos.sectionToBlockCoord(y); + int maxY = minY + 16; + for (FakeBlock block : blocksInChunk) { + int blockY = block.location.getBlockY(); + if (blockY >= minY && blockY < maxY && block.material != null) { + int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(blockY); + int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); + BlockState newState = getNMSState(block); + if (oldState.isAir() && !newState.isAir()) { + blockCount++; + } + else if (newState.isAir() && !oldState.isAir()) { + blockCount--; } + states.set(relativeX, relativeY, relativeZ, newState); + BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (nmsBlockEntityType == null) { + continue; + } + BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); } } - newChunkData.writeShort(blockCount); - states.write(newChunkData); - biomes.write(newChunkData); } - CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); - return copiedChunkPacket; - } - catch (Throwable ex) { - Debug.echoError(ex); + newChunkData.writeShort(blockCount); + states.write(newChunkData); + biomes.write(newChunkData); } - return null; + CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + return copiedChunkPacket; } } From 78306a0437f0713eca6710076d81ea0500b8e651 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 13 Jul 2025 00:27:59 +0100 Subject: [PATCH 003/169] Cleanup reflection --- .../nms/v1_21/ReflectionMappingsInfo.java | 10 +++---- .../network/handlers/FakeBlockHelper.java | 29 ++++++++----------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 0fbee1ebbe..18d5f6e051 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -97,6 +97,10 @@ public class ReflectionMappingsInfo { // net.minecraft.network.protocol.game.ClientboundSetPassengersPacket public static String ClientboundSetPassengersPacket_passengers = "c"; + // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData + public static String ClientboundLevelChunkPacketData_buffer = "d"; + public static String ClientboundLevelChunkPacketData_blockEntitiesData = "e"; + // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo public static String ClientboundLevelChunkPacketDataBlockEntityInfo_create_method = "a"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "c"; @@ -113,12 +117,6 @@ public class ReflectionMappingsInfo { // 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 = "R"; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index a01beda1ce..61a876b8af 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -11,7 +11,6 @@ import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; @@ -32,29 +31,25 @@ import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; import java.lang.invoke.MethodHandle; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.*; public class FakeBlockHelper { - public static Field CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getFirstOfType(List.class); - public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; - public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); - public static final MethodHandle CHUNK_DATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); - public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); - public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); - public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); - public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); - public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 3).findFirst().get(); - public static Field BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).get(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); + public static final MethodHandle CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_blockEntitiesData, List.class); + public static final MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getSetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_buffer, byte[].class); + public static final Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; + public static final MethodHandle CHUNKDATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); + public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); + public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); + public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); static { try { for (BlockEntityType nmsBlockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.get(nmsBlockEntityType); + Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.invokeExact(nmsBlockEntityType); for (Block validBlock : validBlocks) { MATERIAL_BLOCK_ENTITY_TYPES.put(CraftBlockType.minecraftToBukkit(validBlock), nmsBlockEntityType); } @@ -111,13 +106,13 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); // A list of block entities sent with the chunk data - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invoke(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); ListIterator blockEntitiesIterator = blockEntities.listIterator(); while (blockEntitiesIterator.hasNext()) { Object blockEnt = blockEntitiesIterator.next(); - int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); - int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int xz = (int) CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.invoke(blockEnt); + int y = (int) CHUNKDATA_BLOCKENTITYINFO_Y.invoke(blockEnt); int relativeX = SectionPos.sectionRelative(xz >> 4); int relativeZ = SectionPos.sectionRelative(xz); int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; @@ -168,7 +163,7 @@ else if (newState.isAir() && !oldState.isAir()) { } BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); - Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); } } From 06d6df9a0df790ed3b98519ec3c47d9aeddec324 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:01:41 +0100 Subject: [PATCH 004/169] Initial work on fake block light levels --- .../network/handlers/FakeBlockHelper.java | 144 ++++++++++++++++++ .../packet/FakeBlocksPacketHandlers.java | 3 +- 2 files changed, 145 insertions(+), 2 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 61a876b8af..9723a3ca96 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -1,12 +1,17 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.FakeBlock; +import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -14,6 +19,9 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.network.protocol.game.ClientboundLightUpdatePacketData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; @@ -21,7 +29,10 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; @@ -132,8 +143,20 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo int minChunkY = SectionPos.blockToSectionCoord(worldMinY); int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + int blocksLit = 0, skyLit = 0; // These are section coords, iterating through every chunk section + ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); + Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); for (int y = minChunkY; y < maxChunkY; y++) { + SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); + int sectionIndex = y + Math.abs(minChunkY) + 1; + boolean hasSky = false, hasBlock = false; + if (lightData.getBlockYMask().get(sectionIndex)) { + hasBlock = true; + } + if (lightData.getSkyYMask().get(sectionIndex)) { + hasSky = true; + } int blockCount = rawChunkData.readShort(); PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); states.read(rawChunkData); @@ -165,9 +188,29 @@ else if (newState.isAir() && !oldState.isAir()) { createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); + DataLayer blockLights; + if (!hasBlock) { + Debug.log(">>>>>>>>>>>>>>>>>>> No light data, adding"); + blockLights = new DataLayer(); + lightData.getBlockUpdates().add(blocksLit, blockLights.getData()); + lightData.getBlockYMask().set(sectionIndex); + lightData.getEmptyBlockYMask().clear(sectionIndex); + hasBlock = true; + } + else { + blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + } + DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); + blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, world, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } + if (hasBlock) { + blocksLit++; + } + if (hasSky) { + skyLit++; + } newChunkData.writeShort(blockCount); states.write(newChunkData); biomes.write(newChunkData); @@ -175,4 +218,105 @@ else if (newState.isAir() && !oldState.isAir()) { CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); return copiedChunkPacket; } + + public static final int[][] directions = { + {0, -1, 0}, + {0, 1, 0}, + {-1, 0, 0}, + {1, 0, 0}, + {0, 0, -1}, + {0, 0, 1} + }; + + public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + int maxLight = Math.max(blockLights.get(relativeX, relativeY, relativeZ), skyLights.get(relativeX, relativeY, relativeZ)); + if (maxLight == 15) { + return 15; + } + List blockLookups = null; + for (int[] direction : directions) { + int yOffest = direction[1]; + int neighborX = relativeX + direction[0]; + int neighborY = relativeY + yOffest; + int neighborZ = relativeZ + direction[2]; + if (coordOutOfSection(neighborX) || coordOutOfSection(neighborZ)) { + if (blockLookups == null) { + blockLookups = new ArrayList<>(2); + } + blockLookups.add(new BlockPos(sectionPos.minBlockX() + neighborX, sectionPos.minBlockY() + neighborY, sectionPos.minBlockZ() + neighborZ)); + continue; + } + int light; + if (coordOutOfSection(neighborY)) { + int adjacentSectionIndex = sectionIndex + yOffest; + boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); + boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); + if (!hasBlockLights && !hasSkyLights) { + Debug.log("No lights in adjacent section"); + continue; + } + int wrappedNeighborY = SectionPos.sectionRelative(neighborY); + light = Math.max( + hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0, + hasBlockLights ? new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0 + ); + Debug.log("Adjacent packet light: " + light); + } + else { + light = Math.max(blockLights.get(neighborX, neighborY, neighborZ), skyLights.get(neighborX, neighborY, neighborZ)); + Debug.log("Packet light: " + light); + } + if (light == 15) { + return 15; + } + if (light > maxLight) { + maxLight = light; + } + } + if (blockLookups == null) { + return maxLight; + } + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + for (BlockPos blockPos : blockLookups) { + SectionPos containingSection = SectionPos.of(blockPos); + SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { + Debug.log("Getting section to cache"); + LevelLightEngine lightEngine = nmsWorld.getLightEngine(); + DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); + DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); + return new SectionLightCache(sectionBlockLights, sectionSkyLights); + }); + int light = sectionLight.getLight(blockPos); + Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { + NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); + }, 1); + Debug.log("Block light: " + light); + if (light == 15) { + return 15; + } + if (light > maxLight) { + maxLight = light; + } + } + return maxLight; + } + + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { + + public int getLight(BlockPos blockPos) { + int relativeX = SectionPos.sectionRelative(blockPos.getX()); + int relativeY = SectionPos.sectionRelative(blockPos.getY()); + int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); + int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) : 0; + if (skyLight == 15) { + return skyLight; + } + int blockLight = blockLights != null ? blockLights.get(relativeX, relativeY, relativeZ) : 0; + return Math.max(skyLight, blockLight); + } + } + + public static boolean coordOutOfSection(int relativeCoord) { + return relativeCoord < 0 || relativeCoord > 15; + } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 52ed0f191d..f8b31d4052 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -47,8 +47,7 @@ public static Packet processShowFakeForPacket(DenizenN if (blocks == null || blocks.isEmpty()) { return packet; } - ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); - return newPacket; + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); } else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); From d23b77218c5a769b697863f2c9dbfed0888101e3 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:33:58 +0100 Subject: [PATCH 005/169] Minor optimization to `max` handling --- .../network/handlers/FakeBlockHelper.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 9723a3ca96..2f0180bce4 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -229,7 +229,7 @@ else if (newState.isAir() && !oldState.isAir()) { }; public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int maxLight = Math.max(blockLights.get(relativeX, relativeY, relativeZ), skyLights.get(relativeX, relativeY, relativeZ)); + int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); if (maxLight == 15) { return 15; } @@ -256,14 +256,16 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - light = Math.max( - hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0, - hasBlockLights ? new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0 - ); + int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0; + if (skyLight == 15 || !hasBlockLights) { + return skyLight; + } + int blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + light = Math.max(skyLight, blockLight); Debug.log("Adjacent packet light: " + light); } else { - light = Math.max(blockLights.get(neighborX, neighborY, neighborZ), skyLights.get(neighborX, neighborY, neighborZ)); + light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights); Debug.log("Packet light: " + light); } if (light == 15) { @@ -301,6 +303,15 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat return maxLight; } + public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData) { + int skyLight = skyLightData.get(relativeX, relativeY, relativeZ); + if (skyLight == 15) { + return 15; + } + int blockLight = blockLightData.get(relativeX, relativeY, relativeZ); + return Math.max(skyLight, blockLight); + } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { public int getLight(BlockPos blockPos) { From 0a660dfa3ccbea82c3f17bac4ad4aa0cd68e8c9e Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:35:19 +0100 Subject: [PATCH 006/169] Pass in NMS world --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 2f0180bce4..e5362bf056 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -185,7 +185,8 @@ else if (newState.isAir() && !oldState.isAir()) { continue; } BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + createdBlockEntity.setLevel(nmsWorld); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); DataLayer blockLights; @@ -201,7 +202,7 @@ else if (newState.isAir() && !oldState.isAir()) { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); } DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); - blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, world, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); + blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } @@ -228,7 +229,7 @@ else if (newState.isAir() && !oldState.isAir()) { {0, 0, 1} }; - public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); if (maxLight == 15) { return 15; @@ -278,7 +279,6 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat if (blockLookups == null) { return maxLight; } - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { From a56183031978df4df30d61f152a9c8cd00052e06 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:25:47 +0100 Subject: [PATCH 007/169] Account for sky darkness --- .../network/handlers/FakeBlockHelper.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index e5362bf056..fa5bffabbb 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -230,7 +230,8 @@ else if (newState.isAir() && !oldState.isAir()) { }; public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); + int ambientDarkness = nmsWorld.getSkyDarken(); + int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights, ambientDarkness); if (maxLight == 15) { return 15; } @@ -257,7 +258,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0; + int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness : 0; if (skyLight == 15 || !hasBlockLights) { return skyLight; } @@ -266,7 +267,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat Debug.log("Adjacent packet light: " + light); } else { - light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights); + light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights, ambientDarkness); Debug.log("Packet light: " + light); } if (light == 15) { @@ -288,7 +289,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int light = sectionLight.getLight(blockPos); + int light = sectionLight.getLight(blockPos, ambientDarkness); Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); }, 1); @@ -303,8 +304,8 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat return maxLight; } - public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData) { - int skyLight = skyLightData.get(relativeX, relativeY, relativeZ); + public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData, int ambientDarkness) { + int skyLight = skyLightData.get(relativeX, relativeY, relativeZ) - ambientDarkness; if (skyLight == 15) { return 15; } @@ -314,15 +315,15 @@ public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLaye public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - public int getLight(BlockPos blockPos) { + public int getLight(BlockPos blockPos, int ambientDarkness) { int relativeX = SectionPos.sectionRelative(blockPos.getX()); int relativeY = SectionPos.sectionRelative(blockPos.getY()); int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); - int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) : 0; - if (skyLight == 15) { + int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) - ambientDarkness : 0; + if (skyLight == 15 || blockLights == null) { return skyLight; } - int blockLight = blockLights != null ? blockLights.get(relativeX, relativeY, relativeZ) : 0; + int blockLight = blockLights.get(relativeX, relativeY, relativeZ); return Math.max(skyLight, blockLight); } } From 9bf7492d8591b52b695b968fa062aa136e528e32 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 22:13:50 +0100 Subject: [PATCH 008/169] Set both block and sky light for smoother visuals --- .../network/handlers/FakeBlockHelper.java | 136 ++++++++++-------- 1 file changed, 78 insertions(+), 58 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index fa5bffabbb..7681e6892e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -189,20 +189,32 @@ else if (newState.isAir() && !oldState.isAir()) { createdBlockEntity.setLevel(nmsWorld); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); - DataLayer blockLights; - if (!hasBlock) { - Debug.log(">>>>>>>>>>>>>>>>>>> No light data, adding"); - blockLights = new DataLayer(); - lightData.getBlockUpdates().add(blocksLit, blockLights.getData()); - lightData.getBlockYMask().set(sectionIndex); - lightData.getEmptyBlockYMask().clear(sectionIndex); - hasBlock = true; + BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, + getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), + lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); + Debug.log("Final data: " + estimatedLights); + if (estimatedLights.block() > 0) { + DataLayer blockLights; + if (!hasBlock) { + blockLights = addLayer(lightData.getBlockUpdates(), blocksLit, lightData.getBlockYMask(), lightData.getEmptyBlockYMask(), sectionIndex); + hasBlock = true; + } + else { + blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + } + blockLights.set(relativeX, relativeY, relativeZ, estimatedLights.block()); } - else { - blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + if (estimatedLights.sky() > 0) { + DataLayer skyLights; + if (!hasSky) { + skyLights = addLayer(lightData.getSkyUpdates(), skyLit, lightData.getSkyYMask(), lightData.getEmptySkyYMask(), sectionIndex); + hasSky = true; + } + else { + skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); + } + skyLights.set(relativeX, relativeY, relativeZ, estimatedLights.sky()); } - DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); - blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } @@ -220,6 +232,20 @@ else if (newState.isAir() && !oldState.isAir()) { return copiedChunkPacket; } + public static DataLayer addLayer(List layers, int index, BitSet litSections, BitSet unlitSections, int sectionIndex) { + DataLayer newLayer = new DataLayer(); + layers.add(index, newLayer.getData()); + litSections.set(sectionIndex); + unlitSections.clear(sectionIndex); + return newLayer; + } + + public static DataLayer getLayer(boolean has, List layers, int index) { + return has ? new DataLayer(layers.get(index)) : null; + } + + public record BlockLightData(int sky, int block) {} + public static final int[][] directions = { {0, -1, 0}, {0, 1, 0}, @@ -229,12 +255,10 @@ else if (newState.isAir() && !oldState.isAir()) { {0, 0, 1} }; - public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int ambientDarkness = nmsWorld.getSkyDarken(); - int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights, ambientDarkness); - if (maxLight == 15) { - return 15; - } + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + int ambientDarkness = 0; + int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); + int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); List blockLookups = null; for (int[] direction : directions) { int yOffest = direction[1]; @@ -248,7 +272,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat blockLookups.add(new BlockPos(sectionPos.minBlockX() + neighborX, sectionPos.minBlockY() + neighborY, sectionPos.minBlockZ() + neighborZ)); continue; } - int light; + int blockLight = -1, skyLight = -1; if (coordOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); @@ -258,27 +282,28 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness : 0; - if (skyLight == 15 || !hasBlockLights) { - return skyLight; + if (hasSkyLights) { + skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness; + } + if (hasBlockLights) { + blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - int blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); - light = Math.max(skyLight, blockLight); - Debug.log("Adjacent packet light: " + light); + Debug.log("Adjacent packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } else { - light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights, ambientDarkness); - Debug.log("Packet light: " + light); + skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); + blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); + Debug.log("Packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } - if (light == 15) { - return 15; + if (skyLight > maxSky) { + maxSky = skyLight; } - if (light > maxLight) { - maxLight = light; + if (blockLight > maxBlock) { + maxBlock = blockLight; } } if (blockLookups == null) { - return maxLight; + return new BlockLightData(maxSky, maxBlock); } for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); @@ -289,42 +314,37 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int light = sectionLight.getLight(blockPos, ambientDarkness); + int skyLight = sectionLight.getSkyLight(blockPos, ambientDarkness); + int blockLight = sectionLight.getBlockLight(blockPos); + if (skyLight > maxSky) { + maxSky = skyLight; + } + if (blockLight > maxBlock) { + maxBlock = blockLight; + } Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); }, 1); - Debug.log("Block light: " + light); - if (light == 15) { - return 15; - } - if (light > maxLight) { - maxLight = light; - } } - return maxLight; + return new BlockLightData(maxSky, maxBlock); } - public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData, int ambientDarkness) { - int skyLight = skyLightData.get(relativeX, relativeY, relativeZ) - ambientDarkness; - if (skyLight == 15) { - return 15; - } - int blockLight = blockLightData.get(relativeX, relativeY, relativeZ); - return Math.max(skyLight, blockLight); + public static int getLight(DataLayer lightData, BlockPos blockPos) { + return lightData != null ? lightData.get(SectionPos.sectionRelative(blockPos.getX()), SectionPos.sectionRelative(blockPos.getY()), SectionPos.sectionRelative(blockPos.getZ())) : -1; + } + + public static int getLight(DataLayer lightData, int relativeX, int relativeY, int relativeZ) { + return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - public int getLight(BlockPos blockPos, int ambientDarkness) { - int relativeX = SectionPos.sectionRelative(blockPos.getX()); - int relativeY = SectionPos.sectionRelative(blockPos.getY()); - int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); - int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) - ambientDarkness : 0; - if (skyLight == 15 || blockLights == null) { - return skyLight; - } - int blockLight = blockLights.get(relativeX, relativeY, relativeZ); - return Math.max(skyLight, blockLight); + public int getSkyLight(BlockPos blockPos, int ambientDarkness) { + return getLight(skyLights, blockPos) - ambientDarkness; + } + + public int getBlockLight(BlockPos blockPos) { + return getLight(blockLights, blockPos); } } From 515940fa15edb583803d76df247b43fbeec13e22 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 22:16:09 +0100 Subject: [PATCH 009/169] No need for ambient darkness --- .../impl/network/handlers/FakeBlockHelper.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 7681e6892e..bd122da8dd 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -256,7 +256,6 @@ public record BlockLightData(int sky, int block) {} }; public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int ambientDarkness = 0; int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); List blockLookups = null; @@ -283,7 +282,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); if (hasSkyLights) { - skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness; + skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } if (hasBlockLights) { blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); @@ -314,8 +313,8 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int skyLight = sectionLight.getSkyLight(blockPos, ambientDarkness); - int blockLight = sectionLight.getBlockLight(blockPos); + int skyLight = getLight(sectionLight.skyLights(), blockPos); + int blockLight = getLight(sectionLight.blockLights(), blockPos); if (skyLight > maxSky) { maxSky = skyLight; } @@ -337,16 +336,7 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } - public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - - public int getSkyLight(BlockPos blockPos, int ambientDarkness) { - return getLight(skyLights, blockPos) - ambientDarkness; - } - - public int getBlockLight(BlockPos blockPos) { - return getLight(blockLights, blockPos); - } - } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} public static boolean coordOutOfSection(int relativeCoord) { return relativeCoord < 0 || relativeCoord > 15; From f2110006d8ee4563a013d997d29046cc501f91ec Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 18 Jul 2025 20:22:14 +0100 Subject: [PATCH 010/169] Bring back some short-circuiting --- .../network/handlers/FakeBlockHelper.java | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index bd122da8dd..858cbef6cf 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -244,7 +244,10 @@ public static DataLayer getLayer(boolean has, List layers, int index) { return has ? new DataLayer(layers.get(index)) : null; } - public record BlockLightData(int sky, int block) {} + public record BlockLightData(int sky, int block) { + public static final BlockLightData MAX_BLOCK_LIGHT = new BlockLightData(0, 15); + public static final BlockLightData MAX_SKY_LIGHT = new BlockLightData(15, 0); + } public static final int[][] directions = { {0, -1, 0}, @@ -256,8 +259,15 @@ public record BlockLightData(int sky, int block) {} }; public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + boolean isSkyBright = nmsWorld.getSkyDarken() == 0; int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); + if (isSkyBright && maxSky == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (maxBlock == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } List blockLookups = null; for (int[] direction : directions) { int yOffest = direction[1]; @@ -277,7 +287,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); if (!hasBlockLights && !hasSkyLights) { - Debug.log("No lights in adjacent section"); continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); @@ -287,12 +296,16 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (hasBlockLights) { blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - Debug.log("Adjacent packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } else { skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); - Debug.log("Packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); + } + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; } if (skyLight > maxSky) { maxSky = skyLight; @@ -307,7 +320,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { - Debug.log("Getting section to cache"); + Debug.log(">>>>>>>> Getting section to cache"); LevelLightEngine lightEngine = nmsWorld.getLightEngine(); DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); @@ -315,6 +328,12 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY }); int skyLight = getLight(sectionLight.skyLights(), blockPos); int blockLight = getLight(sectionLight.blockLights(), blockPos); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } if (skyLight > maxSky) { maxSky = skyLight; } From 15d8371a4d3835c57f09c07a844b3e83576f54f1 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 24 Jul 2025 20:15:23 +0100 Subject: [PATCH 011/169] Handle all semi-transparent blocks' lighting --- .../network/handlers/FakeBlockHelper.java | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 858cbef6cf..b36f7d88a6 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -1,11 +1,9 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; import com.denizenscript.denizen.Denizen; -import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.FakeBlock; -import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; @@ -32,7 +30,6 @@ import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; @@ -180,19 +177,19 @@ else if (newState.isAir() && !oldState.isAir()) { blockCount--; } states.set(relativeX, relativeY, relativeZ, newState); - BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); - if (nmsBlockEntityType == null) { + BlockEntityType blockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (blockEntityType != null) { + BlockEntity createdBlockEntity = blockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); + } + if (blockEntityType == null && newState.isSolidRender()) { continue; } - BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); - createdBlockEntity.setLevel(nmsWorld); - Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); - blockEntities.add(packetBlockEntityData); BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), - lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); - Debug.log("Final data: " + estimatedLights); + lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); if (estimatedLights.block() > 0) { DataLayer blockLights; if (!hasBlock) { @@ -274,7 +271,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int neighborX = relativeX + direction[0]; int neighborY = relativeY + yOffest; int neighborZ = relativeZ + direction[2]; - if (coordOutOfSection(neighborX) || coordOutOfSection(neighborZ)) { + if (posOutOfSection(neighborX) || posOutOfSection(neighborZ)) { if (blockLookups == null) { blockLookups = new ArrayList<>(2); } @@ -282,7 +279,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY continue; } int blockLight = -1, skyLight = -1; - if (coordOutOfSection(neighborY)) { + if (posOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); @@ -320,7 +317,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { - Debug.log(">>>>>>>> Getting section to cache"); LevelLightEngine lightEngine = nmsWorld.getLightEngine(); DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); @@ -340,9 +336,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight > maxBlock) { maxBlock = blockLight; } - Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { - NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); - }, 1); } return new BlockLightData(maxSky, maxBlock); } @@ -357,7 +350,7 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} - public static boolean coordOutOfSection(int relativeCoord) { - return relativeCoord < 0 || relativeCoord > 15; + public static boolean posOutOfSection(int relativePos) { + return relativePos < 0 || relativePos > 15; } } From 47c2988cc25b9f410dc7940b4a97612f97455d7a Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 27 Jul 2025 13:00:52 +0100 Subject: [PATCH 012/169] Naming, comments --- .../network/handlers/FakeBlockHelper.java | 81 +++++++++---------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index b36f7d88a6..b18b4da774 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -113,7 +113,7 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); - // A list of block entities sent with the chunk data + // A list of ClientboundLevelChunkPacketData$BlockEntityInfo List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invoke(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); ListIterator blockEntitiesIterator = blockEntities.listIterator(); @@ -132,27 +132,26 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo blockEntitiesIterator.remove(); } } - // Get the original chunk data to read, and a buf of the same size to write + // Get the original chunk data to read, and a new buf of the same size to write FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); - int worldMinY = world.getMinHeight(); - int worldMaxY = world.getMaxHeight(); - int minChunkY = SectionPos.blockToSectionCoord(worldMinY); - int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + final int minChunkY = SectionPos.blockToSectionCoord(world.getMinHeight()); + final int maxChunkY = SectionPos.blockToSectionCoord(world.getMaxHeight()); Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); int blocksLit = 0, skyLit = 0; - // These are section coords, iterating through every chunk section ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); + // These are section coords, iterating through every chunk section for (int y = minChunkY; y < maxChunkY; y++) { SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); + // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) int sectionIndex = y + Math.abs(minChunkY) + 1; - boolean hasSky = false, hasBlock = false; + boolean hasSkyLight = false, hasBlockLight = false; if (lightData.getBlockYMask().get(sectionIndex)) { - hasBlock = true; + hasBlockLight = true; } if (lightData.getSkyYMask().get(sectionIndex)) { - hasSky = true; + hasSkyLight = true; } int blockCount = rawChunkData.readShort(); PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); @@ -188,13 +187,13 @@ else if (newState.isAir() && !oldState.isAir()) { continue; } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, - getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), + getLayer(hasBlockLight, lightData.getBlockUpdates(), blocksLit), getLayer(hasSkyLight, lightData.getSkyUpdates(), skyLit), lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); if (estimatedLights.block() > 0) { DataLayer blockLights; - if (!hasBlock) { + if (!hasBlockLight) { blockLights = addLayer(lightData.getBlockUpdates(), blocksLit, lightData.getBlockYMask(), lightData.getEmptyBlockYMask(), sectionIndex); - hasBlock = true; + hasBlockLight = true; } else { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); @@ -203,9 +202,9 @@ else if (newState.isAir() && !oldState.isAir()) { } if (estimatedLights.sky() > 0) { DataLayer skyLights; - if (!hasSky) { + if (!hasSkyLight) { skyLights = addLayer(lightData.getSkyUpdates(), skyLit, lightData.getSkyYMask(), lightData.getEmptySkyYMask(), sectionIndex); - hasSky = true; + hasSkyLight = true; } else { skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); @@ -215,10 +214,10 @@ else if (newState.isAir() && !oldState.isAir()) { } } } - if (hasBlock) { + if (hasBlockLight) { blocksLit++; } - if (hasSky) { + if (hasSkyLight) { skyLit++; } newChunkData.writeShort(blockCount); @@ -246,6 +245,8 @@ public record BlockLightData(int sky, int block) { public static final BlockLightData MAX_SKY_LIGHT = new BlockLightData(15, 0); } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} + public static final int[][] directions = { {0, -1, 0}, {0, 1, 0}, @@ -255,14 +256,14 @@ public record BlockLightData(int sky, int block) { {0, 0, 1} }; - public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { boolean isSkyBright = nmsWorld.getSkyDarken() == 0; - int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); - int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); - if (isSkyBright && maxSky == 15) { + int maxSkyLight = getLight(skyLights, relativeX, relativeY, relativeZ); + int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); + if (isSkyBright && maxSkyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } - if (maxBlock == 15) { + if (maxBlockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } List blockLookups = null; @@ -281,17 +282,17 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int blockLight = -1, skyLight = -1; if (posOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; - boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); - boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); - if (!hasBlockLights && !hasSkyLights) { + boolean hasSkyLight = lightData.getSkyYMask().get(adjacentSectionIndex); + boolean hasBlockLight = lightData.getBlockYMask().get(adjacentSectionIndex); + if (!hasBlockLight && !hasSkyLight) { continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - if (hasSkyLights) { - skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (hasSkyLight) { + skyLight = new DataLayer(lightData.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - if (hasBlockLights) { - blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (hasBlockLight) { + blockLight = new DataLayer(lightData.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } } else { @@ -304,15 +305,15 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } - if (skyLight > maxSky) { - maxSky = skyLight; + if (skyLight > maxSkyLight) { + maxSkyLight = skyLight; } - if (blockLight > maxBlock) { - maxBlock = blockLight; + if (blockLight > maxBlockLight) { + maxBlockLight = blockLight; } } if (blockLookups == null) { - return new BlockLightData(maxSky, maxBlock); + return new BlockLightData(maxSkyLight, maxBlockLight); } for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); @@ -330,14 +331,14 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } - if (skyLight > maxSky) { - maxSky = skyLight; + if (skyLight > maxSkyLight) { + maxSkyLight = skyLight; } - if (blockLight > maxBlock) { - maxBlock = blockLight; + if (blockLight > maxBlockLight) { + maxBlockLight = blockLight; } } - return new BlockLightData(maxSky, maxBlock); + return new BlockLightData(maxSkyLight, maxBlockLight); } public static int getLight(DataLayer lightData, BlockPos blockPos) { @@ -348,8 +349,6 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } - public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} - public static boolean posOutOfSection(int relativePos) { return relativePos < 0 || relativePos > 15; } From 54b908c55b6a27162ca8409bc4addc7a5e46bcef Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 27 Jul 2025 18:11:20 +0100 Subject: [PATCH 013/169] Skip lighting if the existing state isn't solid --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index b18b4da774..deba5a6b61 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -183,7 +183,7 @@ else if (newState.isAir() && !oldState.isAir()) { Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); } - if (blockEntityType == null && newState.isSolidRender()) { + if (!oldState.isSolidRender() || (blockEntityType == null && newState.isSolidRender())) { continue; } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, From 97e44bcd3924e7a2edffd408ed1154161eb61475 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:39:33 +0100 Subject: [PATCH 014/169] Split up fake block packet handlers --- .../handlers/DenizenNetworkManagerImpl.java | 4 +- .../packet/FakeBlocksPacketHandlers.java | 155 +++++++++--------- 2 files changed, 82 insertions(+), 77 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java index bcde3c8c85..7841537489 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -66,7 +66,7 @@ public static > T copyPacket(T original, StreamCodec> { - Packet handlePacket(DenizenNetworkManagerImpl networkManager, T packet) throws Exception; + Packet handlePacket(DenizenNetworkManagerImpl networkManager, T packet) throws Throwable; } public static final Map>, List>> packetHandlers = new HashMap<>(); @@ -376,7 +376,7 @@ public Packet processPacketHandlersFor(Packet processShowFakeForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { - return packet; + return chunkPacket; } - try { - if (packet instanceof ClientboundLevelChunkWithLightPacket) { - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return packet; - } - int chunkX = ((ClientboundLevelChunkWithLightPacket) packet).getX(); - int chunkZ = ((ClientboundLevelChunkWithLightPacket) packet).getZ(); - ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); - List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); - if (blocks == null || blocks.isEmpty()) { - return packet; - } - return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); - } - else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return sectionBlocksUpdatePacket; - } - SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionBlocksUpdatePacket); - ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); - if (!map.byChunk.containsKey(coordinateDenizen)) { - return sectionBlocksUpdatePacket; - } - ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionBlocksUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); - LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); - BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); - short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); - BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); - OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); - BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); - for (int i = 0; i < offsetArray.length; i++) { - short offset = offsetArray[i]; - BlockPos pos = coord.relativeToBlockPos(offset); - location.setX(pos.getX()); - location.setY(pos.getY()); - location.setZ(pos.getZ()); - FakeBlock block = map.byLocation.get(location); - if (block != null) { - dataArray[i] = FakeBlockHelper.getNMSState(block); - } - } - return newPacket; - } - else if (packet instanceof ClientboundBlockUpdatePacket) { - BlockPos pos = ((ClientboundBlockUpdatePacket) packet).getPos(); - LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); - if (block != null) { - ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(((ClientboundBlockUpdatePacket) packet).getPos(), FakeBlockHelper.getNMSState(block)); - return newPacket; - } - } - else if (packet instanceof ClientboundBlockChangedAckPacket) { - // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. - /* - ClientboundBlockChangedAckPacket origPack = (ClientboundBlockChangedAckPacket) packet; - BlockPos pos = origPack.pos(); - LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); - if (block != null) { - ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(origPack.pos(), FakeBlockHelper.getNMSState(block), origPack.action(), false); - oldManager.send(newPacket, genericfuturelistener); - return true; - }*/ + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return chunkPacket; + } + int chunkX = chunkPacket.getX(); + int chunkZ = chunkPacket.getZ(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); + List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); + if (blocks == null || blocks.isEmpty()) { + return chunkPacket; + } + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocks, map); + } + + public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws IllegalAccessException { + if (FakeBlock.blocks.isEmpty()) { + return sectionUpdatePacket; + } + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return sectionUpdatePacket; + } + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); + if (!map.byChunk.containsKey(coordinateDenizen)) { + return sectionUpdatePacket; + } + ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); + BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); + short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); + BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); + OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); + BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); + for (int i = 0; i < offsetArray.length; i++) { + short offset = offsetArray[i]; + BlockPos pos = coord.relativeToBlockPos(offset); + location.setX(pos.getX()); + location.setY(pos.getY()); + location.setZ(pos.getZ()); + FakeBlock block = map.byLocation.get(location); + if (block != null) { + dataArray[i] = FakeBlockHelper.getNMSState(block); } } - catch (Throwable ex) { - Debug.echoError(ex); + return newPacket; + } + + public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { + if (FakeBlock.blocks.isEmpty()) { + return blockUpdatePacket; + } + BlockPos pos = blockUpdatePacket.getPos(); + LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); + if (block != null) { + ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); + return newPacket; + } + return blockUpdatePacket; + } + + // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. + /* + public static ClientboundBlockChangedAckPacket processBlockChangedAckPacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockChangedAckPacket blockChangedAckPacket) { + if (FakeBlock.blocks.isEmpty()) { + return blockChangedAckPacket; + } + BlockPos pos = blockChangedAckPacket.pos(); + LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); + if (block != null) { + ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(blockChangedAckPacket.pos(), FakeBlockHelper.getNMSState(block), blockChangedAckPacket.action(), false); + oldManager.send(newPacket, genericfuturelistener); + return true; } - return packet; } + */ } From 2024dbf25782304bc8b6055f05cc4f38acebe2c7 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:11:45 +0100 Subject: [PATCH 015/169] Cleanup fake block handlers --- .../packet/FakeBlocksPacketHandlers.java | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index e7e76b3723..c74d60d2c7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -7,11 +7,12 @@ import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; +import it.unimi.dsi.fastutil.shorts.ShortArraySet; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; import java.lang.reflect.Field; @@ -61,26 +62,21 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac if (!map.byChunk.containsKey(coordinateDenizen)) { return sectionUpdatePacket; } - ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); - BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); - short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); - BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); - OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); - BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); - for (int i = 0; i < offsetArray.length; i++) { - short offset = offsetArray[i]; - BlockPos pos = coord.relativeToBlockPos(offset); - location.setX(pos.getX()); - location.setY(pos.getY()); - location.setZ(pos.getZ()); + for (int i = 0; i < originalOffsetArray.length; i++) { + short offset = originalOffsetArray[i]; + location.setX(coord.relativeToBlockX(offset)); + location.setY(coord.relativeToBlockY(offset)); + location.setZ(coord.relativeToBlockZ(offset)); FakeBlock block = map.byLocation.get(location); if (block != null) { - dataArray[i] = FakeBlockHelper.getNMSState(block); + statesArray[i] = FakeBlockHelper.getNMSState(block); } } - return newPacket; + return new ClientboundSectionBlocksUpdatePacket(coord, new ShortArraySet(originalOffsetArray), statesArray); } public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { @@ -91,8 +87,7 @@ public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetwo LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); if (block != null) { - ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); - return newPacket; + return new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); } return blockUpdatePacket; } From 365d4b6eded8ea2ea1cae9b315199945bc5569bd Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:53:51 +0100 Subject: [PATCH 016/169] Don't make new section blocks packet unless needed --- .../network/handlers/packet/FakeBlocksPacketHandlers.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index c74d60d2c7..e5e10d49b2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -66,6 +66,7 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + boolean hasAny = false; for (int i = 0; i < originalOffsetArray.length; i++) { short offset = originalOffsetArray[i]; location.setX(coord.relativeToBlockX(offset)); @@ -74,8 +75,12 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac FakeBlock block = map.byLocation.get(location); if (block != null) { statesArray[i] = FakeBlockHelper.getNMSState(block); + hasAny = true; } } + if (!hasAny) { + return sectionUpdatePacket; + } return new ClientboundSectionBlocksUpdatePacket(coord, new ShortArraySet(originalOffsetArray), statesArray); } From 19c450b23c003fd4ce49de2077433fa1a10f842a Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 17:20:42 +0100 Subject: [PATCH 017/169] Section block packets: use `MethodHandle`s --- .../packet/FakeBlocksPacketHandlers.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index e5e10d49b2..7f513acd96 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -15,7 +15,7 @@ import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; -import java.lang.reflect.Field; +import java.lang.invoke.MethodHandle; import java.util.Arrays; import java.util.List; @@ -27,9 +27,9 @@ public static void registerHandlers() { DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processBlockUpdatePacket); } - public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); - public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); - public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); + public static final MethodHandle SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); + public static final MethodHandle OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); + public static final MethodHandle BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { @@ -49,7 +49,7 @@ public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPac return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocks, map); } - public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws IllegalAccessException { + public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { return sectionUpdatePacket; } @@ -57,13 +57,13 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac if (map == null) { return sectionUpdatePacket; } - SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); if (!map.byChunk.containsKey(coordinateDenizen)) { return sectionUpdatePacket; } - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); - BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + short[] originalOffsetArray = (short[]) OFFSETARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); + BlockState[] originalStatesArray = (BlockState[]) BLOCKARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); boolean hasAny = false; From 4d00a6e97509aff1c32f2ed41b96edebc2eeba36 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:38:59 +0100 Subject: [PATCH 018/169] Minor change --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index deba5a6b61..23bb735dd7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -143,7 +143,6 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); // These are section coords, iterating through every chunk section for (int y = minChunkY; y < maxChunkY; y++) { - SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) int sectionIndex = y + Math.abs(minChunkY) + 1; boolean hasSkyLight = false, hasBlockLight = false; @@ -159,6 +158,7 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); biomes.read(rawChunkData); if (anyBlocksInSection(blocksInChunk, y)) { + SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); int minY = SectionPos.sectionToBlockCoord(y); int maxY = minY + 16; for (FakeBlock block : blocksInChunk) { From 29b3a87e59d0f6c54301a542a71c0d4c5b19b6a3 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:46:31 +0100 Subject: [PATCH 019/169] Reflection fixup --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 23bb735dd7..74b1ec1912 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -224,7 +224,7 @@ else if (newState.isAir() && !oldState.isAir()) { states.write(newChunkData); biomes.write(newChunkData); } - CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); return copiedChunkPacket; } From 6acdb14a95589bf4baf773aca375e69cb52e884c Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 27 Sep 2025 11:16:10 +0100 Subject: [PATCH 020/169] Persist light through fake blocks between sections --- .../denizen/utilities/blocks/FakeBlock.java | 2 + .../network/handlers/FakeBlockHelper.java | 41 ++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java index 5efa823896..87cf588e40 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java @@ -75,6 +75,8 @@ public static List getFakeBlocksFor(UUID id, ChunkCoordinate chunkCoo public final ChunkCoordinate chunkCoord; public MaterialTag material; public BukkitTask currentTask = null; + public int lastBlockLight = -1; + public int lastSkyLight = -1; private FakeBlock(PlayerTag player, LocationTag location) { this.player = player; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 74b1ec1912..433632bac2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -188,7 +188,7 @@ else if (newState.isAir() && !oldState.isAir()) { } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, getLayer(hasBlockLight, lightData.getBlockUpdates(), blocksLit), getLayer(hasSkyLight, lightData.getSkyUpdates(), skyLit), - lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); + lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit, fakeBlockMap); if (estimatedLights.block() > 0) { DataLayer blockLights; if (!hasBlockLight) { @@ -199,6 +199,7 @@ else if (newState.isAir() && !oldState.isAir()) { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); } blockLights.set(relativeX, relativeY, relativeZ, estimatedLights.block()); + block.lastBlockLight = estimatedLights.block(); } if (estimatedLights.sky() > 0) { DataLayer skyLights; @@ -210,6 +211,7 @@ else if (newState.isAir() && !oldState.isAir()) { skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); } skyLights.set(relativeX, relativeY, relativeZ, estimatedLights.sky()); + block.lastSkyLight = estimatedLights.sky(); } } } @@ -256,13 +258,13 @@ public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} {0, 0, 1} }; - public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit, FakeBlock.FakeBlockMap fakeBlockMap) { boolean isSkyBright = nmsWorld.getSkyDarken() == 0; int maxSkyLight = getLight(skyLights, relativeX, relativeY, relativeZ); - int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); if (isSkyBright && maxSkyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } + int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); if (maxBlockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } @@ -290,20 +292,26 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int wrappedNeighborY = SectionPos.sectionRelative(neighborY); if (hasSkyLight) { skyLight = new DataLayer(lightData.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } } if (hasBlockLight) { blockLight = new DataLayer(lightData.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } } } else { skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); - } - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } } if (skyLight > maxSkyLight) { maxSkyLight = skyLight; @@ -324,13 +332,26 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); int skyLight = getLight(sectionLight.skyLights(), blockPos); - int blockLight = getLight(sectionLight.blockLights(), blockPos); if (isSkyBright && skyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } + int blockLight = getLight(sectionLight.blockLights(), blockPos); if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } + FakeBlock fakeBlock = fakeBlockMap.byLocation.get(new LocationTag(nmsWorld.getWorld(), blockPos.getX(), blockPos.getY(), blockPos.getZ())); + if (fakeBlock.lastSkyLight > skyLight) { + skyLight = fakeBlock.lastSkyLight; + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + } + if (fakeBlock.lastBlockLight > blockLight) { + blockLight = fakeBlock.lastBlockLight; + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } + } if (skyLight > maxSkyLight) { maxSkyLight = skyLight; } From 46fedf5584afa5e4e7070c39377eb4afef6d46ec Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 27 Sep 2025 11:23:09 +0100 Subject: [PATCH 021/169] No `EnumMap` --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 433632bac2..1b0f11f0d0 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -52,7 +52,7 @@ public class FakeBlockHelper { public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); - public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); + public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); static { try { From 8577540b8b8a86d8346e09ed545202d78ee43e38 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 30 Sep 2025 22:01:44 +0100 Subject: [PATCH 022/169] 1.21.9 part 1: bump versions --- README.md | 2 +- paper/pom.xml | 2 +- plugin/pom.xml | 2 +- v1_21/pom.xml | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index cd876a87ca..3427ae9203 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, and 1.21.8! +**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, and 1.21.9! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html diff --git a/paper/pom.xml b/paper/pom.xml index d426267ecc..ce394197b1 100644 --- a/paper/pom.xml +++ b/paper/pom.xml @@ -25,7 +25,7 @@ io.papermc.paper paper-api - 1.21.8-R0.1-SNAPSHOT + 1.21.9-R0.1-SNAPSHOT provided diff --git a/plugin/pom.xml b/plugin/pom.xml index 50400c64ce..80f0daa09f 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -30,7 +30,7 @@ org.spigotmc spigot-api - 1.21.8-R0.1-SNAPSHOT + 1.21.9-R0.1-SNAPSHOT jar provided diff --git a/v1_21/pom.xml b/v1_21/pom.xml index 70c9f2ca0d..03366284f3 100644 --- a/v1_21/pom.xml +++ b/v1_21/pom.xml @@ -19,13 +19,13 @@ org.spigotmc spigot-api - 1.21.8-R0.1-SNAPSHOT + 1.21.9-R0.1-SNAPSHOT provided org.spigotmc spigot - 1.21.8-R0.1-SNAPSHOT + 1.21.9-R0.1-SNAPSHOT remapped-mojang provided @@ -45,9 +45,9 @@ remap-obf - org.spigotmc:minecraft-server:1.21.8-R0.1-SNAPSHOT:txt:maps-mojang + org.spigotmc:minecraft-server:1.21.9-R0.1-SNAPSHOT:txt:maps-mojang true - org.spigotmc:spigot:1.21.8-R0.1-SNAPSHOT:jar:remapped-mojang + org.spigotmc:spigot:1.21.9-R0.1-SNAPSHOT:jar:remapped-mojang true remapped-obf @@ -60,8 +60,8 @@ remap-spigot ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.21.8-R0.1-SNAPSHOT:csrg:maps-spigot - org.spigotmc:spigot:1.21.8-R0.1-SNAPSHOT:jar:remapped-obf + org.spigotmc:minecraft-server:1.21.9-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.21.9-R0.1-SNAPSHOT:jar:remapped-obf From fa3fa0c8d09701726be4ca84aeb24a7ba466f588 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 30 Sep 2025 22:05:06 +0100 Subject: [PATCH 023/169] 1.21.9 part 2: bump import revisions --- .../denizen/nms/v1_21/Handler.java | 26 +++++++++---------- .../v1_21/helpers/AdvancementHelperImpl.java | 8 +++--- .../v1_21/helpers/AnimationHelperImpl.java | 6 ++--- .../nms/v1_21/helpers/BlockHelperImpl.java | 22 ++++++++-------- .../nms/v1_21/helpers/ChunkHelperImpl.java | 4 +-- .../v1_21/helpers/CustomEntityHelperImpl.java | 4 +-- .../nms/v1_21/helpers/EntityHelperImpl.java | 16 ++++++------ .../nms/v1_21/helpers/FishingHelperImpl.java | 8 +++--- .../nms/v1_21/helpers/ItemHelperImpl.java | 18 ++++++------- .../nms/v1_21/helpers/PacketHelperImpl.java | 16 ++++++------ .../nms/v1_21/helpers/PlayerHelperImpl.java | 18 ++++++------- .../nms/v1_21/helpers/WorldHelperImpl.java | 2 +- .../denizen/nms/v1_21/impl/BiomeNMSImpl.java | 8 +++--- .../v1_21/impl/ImprovedOfflinePlayerImpl.java | 8 +++--- .../nms/v1_21/impl/ProfileEditorImpl.java | 4 +-- .../nms/v1_21/impl/blocks/BlockLightImpl.java | 4 +-- .../impl/entities/CraftFakeArrowImpl.java | 4 +-- .../impl/entities/CraftFakePlayerImpl.java | 4 +-- .../entities/CraftItemProjectileImpl.java | 6 ++--- .../impl/entities/EntityFakeArrowImpl.java | 4 +-- .../impl/entities/EntityFakePlayerImpl.java | 2 +- .../handlers/AbstractListenerPlayInImpl.java | 2 +- .../handlers/DenizenNetworkManagerImpl.java | 6 ++--- .../handlers/DenizenPacketListenerImpl.java | 2 +- .../network/handlers/FakeBlockHelper.java | 8 +++--- .../packet/ActionBarEventPacketHandlers.java | 2 +- .../handlers/packet/AttachPacketHandlers.java | 4 +-- .../packet/DisguisePacketHandlers.java | 2 +- .../packet/FakeEquipmentPacketHandlers.java | 2 +- .../packet/HideParticlesPacketHandlers.java | 2 +- .../network/packets/PacketOutChatImpl.java | 2 +- 31 files changed, 112 insertions(+), 112 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java index 1cd431f486..9092b7a8ce 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java @@ -68,19 +68,19 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.boss.BossBar; -import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R5.boss.CraftBossBar; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftInventory; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftInventoryCustom; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftInventoryView; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R5.legacy.FieldRename; -import org.bukkit.craftbukkit.v1_21_R5.persistence.CraftPersistentDataContainer; -import org.bukkit.craftbukkit.v1_21_R5.util.*; +import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R6.boss.CraftBossBar; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventoryCustom; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.legacy.FieldRename; +import org.bukkit.craftbukkit.v1_21_R6.persistence.CraftPersistentDataContainer; +import org.bukkit.craftbukkit.v1_21_R6.util.*; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java index 0b2ca9366e..0c6b66fb56 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java @@ -14,10 +14,10 @@ import net.minecraft.server.ServerAdvancementManager; import net.minecraft.server.level.ServerPlayer; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; import org.bukkit.entity.Player; import java.util.*; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AnimationHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AnimationHelperImpl.java index a59f65bee6..58f94499b8 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AnimationHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AnimationHelperImpl.java @@ -2,9 +2,9 @@ import com.denizenscript.denizen.nms.abstracts.AnimationHelper; import net.minecraft.world.entity.Entity; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftHorse; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPolarBear; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftHorse; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPolarBear; import org.bukkit.entity.EntityType; import org.bukkit.entity.Horse; import org.bukkit.entity.IronGolem; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java index 99ae170c91..067c3f4d79 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java @@ -34,17 +34,17 @@ import org.bukkit.block.Block; import org.bukkit.block.CreatureSpawner; import org.bukkit.block.Skull; -import org.bukkit.craftbukkit.v1_21_R5.CraftChunk; -import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlock; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockEntityState; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftSkull; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_21_R6.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlock; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftSkull; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftMagicNumbers; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ChunkHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ChunkHelperImpl.java index 79e765a6e6..974ab21f15 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ChunkHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ChunkHelperImpl.java @@ -20,8 +20,8 @@ import net.minecraft.world.level.levelgen.Heightmap; import org.bukkit.Chunk; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R5.CraftChunk; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/CustomEntityHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/CustomEntityHelperImpl.java index 9b0aa2a05a..f5cb6d5eec 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/CustomEntityHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/CustomEntityHelperImpl.java @@ -20,8 +20,8 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.scoreboard.Scoreboard; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java index 09c17b076c..38e84804bc 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java @@ -67,14 +67,14 @@ import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.CreatureSpawner; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlock; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R5.entity.*; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlock; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R6.entity.*; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; import org.bukkit.entity.*; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.EquipmentSlot; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/FishingHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/FishingHelperImpl.java index b5d75d105a..531f56e824 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/FishingHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/FishingHelperImpl.java @@ -18,10 +18,10 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftFishHook; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftFishHook; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; import org.bukkit.entity.FishHook; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java index 14298cc907..b9785d4a07 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java @@ -69,15 +69,15 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R5.inventory.*; -import org.bukkit.craftbukkit.v1_21_R5.map.CraftMapView; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftMagicNumbers; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.inventory.*; +import org.bukkit.craftbukkit.v1_21_R6.map.CraftMapView; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.*; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java index 0156bee78a..8384e8753e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java @@ -50,14 +50,14 @@ import org.bukkit.block.Sign; import org.bukkit.block.sign.Side; import org.bukkit.block.sign.SignSide; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R5.map.CraftMapCanvas; -import org.bukkit.craftbukkit.v1_21_R5.map.CraftMapView; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.map.CraftMapCanvas; +import org.bukkit.craftbukkit.v1_21_R6.map.CraftMapView; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java index c3ee8fcced..4dbc62c864 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java @@ -60,15 +60,15 @@ import net.minecraft.world.phys.AABB; import org.bukkit.*; import org.bukkit.boss.BossBar; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.boss.CraftBossBar; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftMagicNumbers; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.boss.CraftBossBar; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java index 0cb2efa1a7..04dbcce690 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java @@ -16,7 +16,7 @@ import net.minecraft.world.level.storage.PrimaryLevelData; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; public class WorldHelperImpl implements WorldHelper { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java index 423fdff0f5..24f6662195 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java @@ -22,10 +22,10 @@ import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.block.Block; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftEntityType; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntityType; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; import org.bukkit.entity.EntityType; import java.lang.invoke.MethodHandle; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java index 14b59f20d9..af893053c8 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java @@ -24,10 +24,10 @@ import net.minecraft.world.level.storage.ValueOutput; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftInventory; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftInventoryPlayer; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventoryPlayer; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java index 2f25a8878d..88e170a755 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java @@ -20,8 +20,8 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerRespawnEvent; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/blocks/BlockLightImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/blocks/BlockLightImpl.java index 0565fa5845..cb8ecd0997 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/blocks/BlockLightImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/blocks/BlockLightImpl.java @@ -21,8 +21,8 @@ import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R5.CraftChunk; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlock; +import org.bukkit.craftbukkit.v1_21_R6.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlock; import org.bukkit.util.Vector; import java.lang.invoke.MethodHandle; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java index cc8338ff35..41e5f37402 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java @@ -2,8 +2,8 @@ import com.denizenscript.denizen.nms.interfaces.FakeArrow; import net.minecraft.world.entity.projectile.AbstractArrow; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftAbstractArrow; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftAbstractArrow; public class CraftFakeArrowImpl extends CraftAbstractArrow implements FakeArrow { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakePlayerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakePlayerImpl.java index 376e62d8e1..3d1687b869 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakePlayerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakePlayerImpl.java @@ -4,8 +4,8 @@ import com.denizenscript.denizen.nms.NMSHandler; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftItemProjectileImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftItemProjectileImpl.java index d1d84be876..3504f71463 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftItemProjectileImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftItemProjectileImpl.java @@ -3,9 +3,9 @@ import com.denizenscript.denizen.nms.interfaces.ItemProjectile; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java index 10aba52738..f701bb0f71 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java @@ -7,8 +7,8 @@ import net.minecraft.world.item.Items; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; import org.bukkit.event.entity.CreatureSpawnEvent; public class EntityFakeArrowImpl extends SpectralArrow { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakePlayerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakePlayerImpl.java index 9cdf134882..b0f61cf1ef 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakePlayerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakePlayerImpl.java @@ -14,7 +14,7 @@ import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.world.entity.player.Player; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R5.CraftServer; +import org.bukkit.craftbukkit.v1_21_R6.CraftServer; import org.bukkit.event.entity.CreatureSpawnEvent; public class EntityFakePlayerImpl extends ServerPlayer { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java index 69c4d3f6e3..8bd06d5c14 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java @@ -31,7 +31,7 @@ import net.minecraft.world.entity.Relative; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; import org.bukkit.event.player.PlayerTeleportEvent; import java.lang.invoke.MethodHandle; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java index bcde3c8c85..e6dae30090 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -32,9 +32,9 @@ import net.minecraft.util.debugchart.LocalSampleLogger; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; import org.bukkit.entity.Player; import javax.annotation.Nullable; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenPacketListenerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenPacketListenerImpl.java index 25e29ecc56..7984075272 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenPacketListenerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenPacketListenerImpl.java @@ -17,7 +17,7 @@ import net.minecraft.network.protocol.game.*; import net.minecraft.server.level.ServerPlayer; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlock; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlock; import org.bukkit.event.block.SignChangeEvent; public class DenizenPacketListenerImpl extends AbstractListenerPlayInImpl { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index ff41dfa046..7c538b3ae2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -23,10 +23,10 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.PalettedContainer; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockStates; -import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlockStates; +import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java index 0f3ef55965..2726aed312 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java @@ -8,7 +8,7 @@ import com.denizenscript.denizencore.objects.core.ElementTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftChatMessage; public class ActionBarEventPacketHandlers { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/AttachPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/AttachPacketHandlers.java index dcea0cfffe..9090cd17fa 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/AttachPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/AttachPacketHandlers.java @@ -13,8 +13,8 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PositionMoveRotation; import net.minecraft.world.phys.Vec3; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftVector; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftVector; import org.bukkit.util.Vector; import java.lang.reflect.Field; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DisguisePacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DisguisePacketHandlers.java index a281b4c20d..5c3cd767b4 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DisguisePacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DisguisePacketHandlers.java @@ -14,7 +14,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PositionMoveRotation; import net.minecraft.world.level.Level; -import org.bukkit.craftbukkit.v1_21_R5.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java index 9e886625a7..8ec2e35795 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java @@ -12,7 +12,7 @@ import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; -import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; import java.util.ArrayList; import java.util.List; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/HideParticlesPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/HideParticlesPacketHandlers.java index ba98b2ef6a..4e2109ee9d 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/HideParticlesPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/HideParticlesPacketHandlers.java @@ -4,7 +4,7 @@ import com.denizenscript.denizen.utilities.packets.HideParticles; import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; import org.bukkit.Particle; -import org.bukkit.craftbukkit.v1_21_R5.CraftParticle; +import org.bukkit.craftbukkit.v1_21_R6.CraftParticle; import java.util.Set; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java index 56ec98bb64..e3f8e6444a 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java @@ -5,7 +5,7 @@ import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftChatMessage; public class PacketOutChatImpl extends PacketOutChat { From 54288eaccccac613a62d0d7d9d409bf5eb70f176 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 30 Sep 2025 22:09:25 +0100 Subject: [PATCH 024/169] 1.21.9 part 3: update reflection mappings --- .../nms/v1_21/ReflectionMappingsInfo.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 811303325a..1729caf8aa 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -11,34 +11,34 @@ public class ReflectionMappingsInfo { public static String MappedRegistry_registrationInfos = "h"; // net.minecraft.world.entity.Entity - public static String Entity_onGround = "bb"; - public static String Entity_DATA_SHARED_FLAGS_ID = "az"; - public static String Entity_DATA_CUSTOM_NAME = "bl"; - public static String Entity_DATA_CUSTOM_NAME_VISIBLE = "bm"; + 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 = "bo"; - public static String LivingEntity_autoSpinAttackTicks = "bL"; + public static String LivingEntity_attackStrengthTicker = "by"; + public static String LivingEntity_autoSpinAttackTicks = "bV"; public static String LivingEntity_setLivingEntityFlag_method = "c"; // net.minecraft.world.entity.player.Player - public static String Player_DATA_PLAYER_ABSORPTION_ID = "d"; - public static String Player_DATA_PLAYER_MODE_CUSTOMISATION = "cg"; + public static String Player_DATA_PLAYER_ABSORPTION_ID = "b"; + public static String Player_DATA_PLAYER_MODE_CUSTOMISATION = ERROR_UNKNOWN_TARGET; // net.minecraft.server.level.ServerPlayer - public static String ServerPlayer_respawnConfig = "dA"; + public static String ServerPlayer_respawnConfig = "dq"; // net.minecraft.world.entity.monster.EnderMan - public static String EnderMan_DATA_CREEPY = "cl"; + public static String EnderMan_DATA_CREEPY = "cu"; // net.minecraft.world.entity.monster.Zombie - public static String Zombie_inWaterTime = "cA"; + public static String Zombie_inWaterTime = "cJ"; // net.minecraft.world.item.Item public static String Item_components = "c"; // net.minecraft.world.level.Level - public static String Level_isClientSide = "C"; + public static String Level_isClientSide = "E"; // net.minecraft.server.level.ThreadedLevelLightEngine public static String ThreadedLevelLightEngine_addTask_method = "a"; @@ -118,7 +118,7 @@ public class ReflectionMappingsInfo { public static String HolderReference_bindTags_method = "a"; // net.minecraft.server.level.ServerLevel - public static String ServerLevel_sleepStatus = "R"; + public static String ServerLevel_sleepStatus = "O"; // net.minecraft.world.item.AdventureModePredicate public static String AdventureModePredicate_predicates = "g"; From eb89e66bfa323b371f7e4ddc7fc5aa28e675c482 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 30 Sep 2025 22:11:35 +0100 Subject: [PATCH 025/169] 1.21.9 part 4: update mappings check --- .../main/java/com/denizenscript/denizen/nms/v1_21/Handler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java index 9092b7a8ce..1145c19659 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java @@ -151,7 +151,7 @@ public void undisableAsyncCatcher() { @Override public boolean isExactServerVersionMatch() { - return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("1.21.8") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("98b42190c84edaa346fd96106ee35d6f"); + return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("1.21.9") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("614efe5192cd0510bc2ddc5feefa155d"); } @Override From 5cdacb83e4233b3f162b328b3ee817643d861bab Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 1 Oct 2025 23:43:22 +0100 Subject: [PATCH 026/169] 1.21.9 part 5: initial code updates --- .../denizen/nms/v1_21/Handler.java | 22 +++---- .../nms/v1_21/ReflectionMappingsInfo.java | 7 ++- .../v1_21/helpers/AdvancementHelperImpl.java | 2 +- .../nms/v1_21/helpers/BlockHelperImpl.java | 6 +- .../nms/v1_21/helpers/ItemHelperImpl.java | 28 +++++---- .../nms/v1_21/helpers/PacketHelperImpl.java | 9 +-- .../nms/v1_21/helpers/PlayerHelperImpl.java | 62 +++++++++++++------ .../nms/v1_21/helpers/WorldHelperImpl.java | 4 +- .../nms/v1_21/impl/ProfileEditorImpl.java | 60 +++++++++++++----- .../handlers/AbstractListenerPlayInImpl.java | 4 +- .../handlers/DenizenNetworkManagerImpl.java | 6 +- .../network/handlers/FakeBlockHelper.java | 7 ++- .../TablistUpdateEventPacketHandlers.java | 13 ++-- 13 files changed, 141 insertions(+), 89 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java index 1145c19659..69fffef268 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java @@ -31,7 +31,6 @@ import com.google.common.collect.Iterables; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import com.mojang.authlib.yggdrasil.ProfileResult; import com.mojang.serialization.DynamicOps; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.md_5.bungee.api.ChatColor; @@ -184,24 +183,23 @@ public PlayerProfile fillPlayerProfile(PlayerProfile playerProfile) { GameProfile profile = null; MinecraftServer minecraftServer = ((CraftServer) Bukkit.getServer()).getServer(); if (playerProfile.getUniqueId() != null) { - profile = minecraftServer.getProfileCache().get(playerProfile.getUniqueId()).orElse(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.getProfileCache().get(playerProfile.getName()).orElse(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.getProperties().containsKey("textures") ? Iterables.getFirst(profile.getProperties().get("textures"), null) : null; - if (textures == null || !textures.hasSignature() || profile.getName() == null || profile.getId() == null) { - ProfileResult actualProfile = minecraftServer.getSessionService().fetchProfile(profile.getId(), true); - if (actualProfile == null) { + 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; } - profile = actualProfile.profile(); - textures = profile.getProperties().containsKey("textures") ? Iterables.getFirst(profile.getProperties().get("textures"), null) : null; + textures = profile.properties().containsKey("textures") ? Iterables.getFirst(profile.properties().get("textures"), null) : null; } - return new PlayerProfile(profile.getName(), profile.getId(), textures == null ? null : textures.value(), textures == null ? null : textures.signature()); + return new PlayerProfile(profile.name(), profile.id(), textures == null ? null : textures.value(), textures == null ? null : textures.signature()); } catch (Exception e) { if (CoreConfiguration.debugVerbose) { @@ -281,8 +279,8 @@ public void setInventoryTitle(InventoryView view, String title) { @Override public PlayerProfile getPlayerProfile(Player player) { GameProfile gameProfile = ((CraftPlayer) player).getProfile(); - Property property = Iterables.getFirst(gameProfile.getProperties().get("textures"), null); - return new PlayerProfile(gameProfile.getName(), gameProfile.getId(), + 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); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 1729caf8aa..f4839e4a5b 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -23,7 +23,6 @@ public class ReflectionMappingsInfo { // net.minecraft.world.entity.player.Player public static String Player_DATA_PLAYER_ABSORPTION_ID = "b"; - public static String Player_DATA_PLAYER_MODE_CUSTOMISATION = ERROR_UNKNOWN_TARGET; // net.minecraft.server.level.ServerPlayer public static String ServerPlayer_respawnConfig = "dq"; @@ -37,6 +36,12 @@ public class ReflectionMappingsInfo { // 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 = "E"; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java index 0c6b66fb56..f67b11f035 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java @@ -176,7 +176,7 @@ private static AdvancementHolder asNMSCopy(com.denizenscript.denizen.nms.util.Ad : 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::new), AdvancementType.valueOf(advancement.frame.name()), + 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; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java index 067c3f4d79..880b123dfd 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java @@ -85,15 +85,15 @@ public PlayerProfile getPlayerProfile(Skull skull) { if (profile == null) { return null; } - com.mojang.authlib.properties.Property property = Iterables.getFirst(profile.properties().get("textures"), null); - return new PlayerProfile(profile.name().orElse(null), profile.id().orElse(null), property != null ? property.value() : 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, new ResolvableProfile(gameProfile)); + craftSkull_profile.set(skull, ResolvableProfile.createResolved(gameProfile)); } catch (Throwable ex) { Debug.echoError(ex); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java index b9785d4a07..7b7e675059 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java @@ -49,6 +49,7 @@ import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ItemLore; import net.minecraft.world.item.component.ResolvableProfile; +import net.minecraft.world.item.component.TypedEntityData; import net.minecraft.world.item.crafting.*; import net.minecraft.world.item.crafting.BlastingRecipe; import net.minecraft.world.item.crafting.Recipe; @@ -73,6 +74,7 @@ import org.bukkit.craftbukkit.v1_21_R6.CraftServer; import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntityType; import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_21_R6.inventory.*; import org.bukkit.craftbukkit.v1_21_R6.map.CraftMapView; @@ -342,8 +344,8 @@ public PlayerProfile getSkullSkin(ItemStack is) { net.minecraft.world.item.ItemStack itemStack = CraftItemStack.asNMSCopy(is); ResolvableProfile profile = itemStack.get(DataComponents.PROFILE); if (profile != null) { - Property property = Iterables.getFirst(profile.properties().get("textures"), null); - return new PlayerProfile(profile.name().orElse(null), profile.id().orElse(null), + 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, property != null ? property.signature() : null); } @@ -354,7 +356,7 @@ public PlayerProfile getSkullSkin(ItemStack is) { public ItemStack setSkullSkin(ItemStack itemStack, PlayerProfile playerProfile) { GameProfile gameProfile = ProfileEditorImpl.getGameProfile(playerProfile); net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); - nmsItemStack.set(DataComponents.PROFILE, new ResolvableProfile(gameProfile)); + nmsItemStack.set(DataComponents.PROFILE, ResolvableProfile.createResolved(gameProfile)); return CraftItemStack.asBukkitCopy(nmsItemStack); } @@ -385,7 +387,7 @@ public ItemStack setNbtData(ItemStack itemStack, CompoundBinaryTag compoundTag) @Override public CompoundBinaryTag getCustomData(ItemStack item) { CustomData customData = CraftItemStack.asNMSCopy(item).get(DataComponents.CUSTOM_DATA); - return customData != null ? NBTAdapter.toAPI(customData.getUnsafe()) : null; + return customData != null ? NBTAdapter.toAPI(customData.copyTag()) : null; } @Override @@ -417,21 +419,21 @@ public ItemStack setPartialOldNbt(ItemStack item, CompoundBinaryTag oldTag) { @Override public CompoundBinaryTag getEntityData(ItemStack item) { - CustomData entityData = CraftItemStack.asNMSCopy(item).get(DataComponents.ENTITY_DATA); + TypedEntityData> entityData = CraftItemStack.asNMSCopy(item).get(DataComponents.ENTITY_DATA); return entityData != null ? NBTAdapter.toAPI(entityData.getUnsafe()) : null; } - public static final CompoundTag EMPTY_TAG = new CompoundTag(); - @Override public ItemStack setEntityData(ItemStack item, CompoundBinaryTag entityNbt, EntityType entityType) { - CompoundTag nmsEntityNbt = EMPTY_TAG; - if (entityNbt != null && !entityNbt.isEmpty() && (!entityNbt.keySet().contains("id") || entityNbt.size() > 1)) { - nmsEntityNbt = NBTAdapter.toNMS(entityNbt); - nmsEntityNbt.putString("id", entityType.getKey().toString()); - } net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); - CustomData.set(DataComponents.ENTITY_DATA, nmsItemStack, nmsEntityNbt); + if (entityNbt == null || entityNbt.isEmpty() || (entityNbt.size() == 1 && entityNbt.keySet().contains("id"))) { + nmsItemStack.remove(DataComponents.ENTITY_DATA); + } + else { + CompoundTag nmsEntityNbt = NBTAdapter.toNMS(entityNbt); + nmsEntityNbt.remove("id"); + nmsItemStack.set(DataComponents.ENTITY_DATA, TypedEntityData.of(CraftEntityType.bukkitToMinecraft(entityType), nmsEntityNbt)); + } return CraftItemStack.asBukkitCopy(nmsItemStack); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java index 8384e8753e..55c69bc5c7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java @@ -21,8 +21,6 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; import net.minecraft.network.protocol.common.custom.BrandPayload; -import net.minecraft.network.protocol.common.custom.GameTestAddMarkerDebugPayload; -import net.minecraft.network.protocol.common.custom.GameTestClearMarkersDebugPayload; import net.minecraft.network.protocol.game.*; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.SynchedEntityData; @@ -354,15 +352,12 @@ public void enableNetworkManager() { @Override public void showDebugTestMarker(Player player, Location location, ColorTag color, String name, int time) { - int colorInt = color.blue | (color.green << 8) | (color.red << 16) | (color.alpha << 24); - GameTestAddMarkerDebugPayload payload = new GameTestAddMarkerDebugPayload(CraftLocation.toBlockPosition(location), colorInt, name, time); - send(player, new ClientboundCustomPayloadPacket(payload)); + BlockPos nmsPos = CraftLocation.toBlockPosition(location); + send(player, new ClientboundGameTestHighlightPosPacket(nmsPos, nmsPos)); } @Override public void clearDebugTestMarker(Player player) { - GameTestClearMarkersDebugPayload payload = new GameTestClearMarkersDebugPayload(); - send(player, new ClientboundCustomPayloadPacket(payload)); } @Override diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java index 4dbc62c864..93f8d17add 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java @@ -24,15 +24,13 @@ import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import it.unimi.dsi.fastutil.ints.IntList; import net.md_5.bungee.api.ChatColor; -import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; import net.minecraft.network.protocol.game.*; -import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; @@ -41,6 +39,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.server.players.NameAndId; import net.minecraft.server.players.PlayerList; import net.minecraft.server.players.ServerOpList; import net.minecraft.server.players.ServerOpListEntry; @@ -48,6 +47,7 @@ import net.minecraft.tags.BlockTags; import net.minecraft.tags.TagNetworkSerialization; import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Avatar; import net.minecraft.world.entity.Leashable; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.PositionMoveRotation; @@ -57,6 +57,7 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.phys.AABB; import org.bukkit.*; import org.bukkit.boss.BossBar; @@ -77,6 +78,7 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; import java.util.*; +import java.util.function.Predicate; public class PlayerHelperImpl extends PlayerHelper { @@ -88,8 +90,6 @@ public class PlayerHelperImpl extends PlayerHelper { public static final MethodHandle PLAYER_RESPAWNCONFIG_SETTER = ReflectionHelper.getFinalSetter(ServerPlayer.class, ReflectionMappingsInfo.ServerPlayer_respawnConfig, ServerPlayer.RespawnConfig.class); public static final MethodHandle SERVER_RECIPE_BOOK_ADD_HIGHLIGHT = ReflectionHelper.getMethodHandle(ServerRecipeBook.class, ReflectionMappingsInfo.ServerRecipeBook_addHighlight_method, ResourceKey.class); - public static final EntityDataAccessor PLAYER_DATA_ACCESSOR_SKINLAYERS = ReflectionHelper.getFieldValue(net.minecraft.world.entity.player.Player.class, ReflectionMappingsInfo.Player_DATA_PLAYER_MODE_CUSTOMISATION, null); - @Override public void stopSound(Player player, NamespacedKey sound, SoundCategory category) { ((CraftPlayer) player).getHandle().connection.send(new ClientboundStopSoundPacket(sound == null ? null : CraftNamespacedKey.toMinecraft(sound), null)); @@ -127,6 +127,31 @@ public void addFakePassenger(List players, Entity vehicle, FakeEntity } } + public record FakeEntitySynchronizer(ServerGamePacketListenerImpl target) implements ServerEntity.Synchronizer { + + @Override + public void sendToTrackingPlayers(Packet packet) { + target.send(packet); + } + + @Override + public void sendToTrackingPlayersAndSelf(Packet packet) { + sendToTrackingPlayers(packet); + } + + @Override + public void sendToTrackingPlayersFiltered(Packet packet, Predicate predicate) { + if (predicate.test(target.getPlayer())) { + sendToTrackingPlayers(packet); + } + } + + @Override + public void sendToTrackingPlayersFilteredAndSelf(Packet packet, Predicate predicate) { + sendToTrackingPlayersFiltered(packet, predicate); + } + } + @Override public FakeEntity sendEntitySpawn(List players, DenizenEntityType entityType, LocationTag location, ArrayList mechanisms, int customId, UUID customUUID, boolean autoTrack) { CraftWorld world = ((CraftWorld) location.getWorld()); @@ -191,8 +216,7 @@ else if (mechanism.matches("skin_blob")) { fake.triggerSpawnPacket = (player) -> { ServerPlayer nmsPlayer = ((CraftPlayer) player.getPlayerEntity()).getHandle(); ServerGamePacketListenerImpl conn = nmsPlayer.connection; - // TODO: 1.21.5: what's the correct input for `BiConsumer, List> biconsumer`? - final ServerEntity tracker = new ServerEntity(world.getHandle(), nmsEntity, 1, true, conn::send, (p, u) -> conn.send(p), Collections.singleton(nmsPlayer.connection)); + final ServerEntity tracker = new ServerEntity(world.getHandle(), nmsEntity, 1, true, new FakeEntitySynchronizer(conn), Set.of(conn)); tracker.addPairing(nmsPlayer); final TrackerData data = new TrackerData(player, tracker); trackers.add(data); @@ -313,13 +337,13 @@ public boolean hasChunkLoaded(Player player, Chunk chunk) { @Override public void setTemporaryOp(Player player, boolean op) { MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - GameProfile profile = ((CraftPlayer) player).getProfile(); + NameAndId nameAndId = new NameAndId(((CraftPlayer) player).getProfile()); ServerOpList opList = server.getPlayerList().getOps(); if (op) { - opList.add(new ServerOpListEntry(profile, server.getOperatorUserPermissionLevel(), opList.canBypassPlayerLimit(profile))); + opList.add(new ServerOpListEntry(nameAndId, server.operatorUserPermissionLevel(), opList.canBypassPlayerLimit(nameAndId))); } else { - opList.remove(profile); + opList.remove(nameAndId); } player.recalculatePermissions(); } @@ -367,12 +391,12 @@ public void quietlyAddRecipe(Player player, NamespacedKey key) { @Override public byte getSkinLayers(Player player) { - return ((CraftPlayer) player).getHandle().getEntityData().get(PLAYER_DATA_ACCESSOR_SKINLAYERS); + return ((CraftPlayer) player).getHandle().getEntityData().get(Avatar.DATA_PLAYER_MODE_CUSTOMISATION); } @Override public void setSkinLayers(Player player, byte flags) { - ((CraftPlayer) player).getHandle().getEntityData().set(PLAYER_DATA_ACCESSOR_SKINLAYERS, flags); + ((CraftPlayer) player).getHandle().getEntityData().set(Avatar.DATA_PLAYER_MODE_CUSTOMISATION, flags); } @Override @@ -391,7 +415,7 @@ public void setSpawnForced(Player player, boolean forced) { ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); try { ServerPlayer.RespawnConfig config = nmsPlayer.getRespawnConfig(); - config = new ServerPlayer.RespawnConfig(config.dimension(), config.pos(), config.angle(), forced); + config = new ServerPlayer.RespawnConfig(config.respawnData(), forced); PLAYER_RESPAWNCONFIG_SETTER.invoke(nmsPlayer, config); } catch (Throwable ex) { @@ -406,11 +430,12 @@ public Location getBedSpawnLocation(Player player) { if (nmsRespawnConfig == null) { return null; } - Level nmsWorld = MinecraftServer.getServer().getLevel(nmsRespawnConfig.dimension() != null ? nmsRespawnConfig.dimension() : Level.OVERWORLD); + LevelData.RespawnData nmsRespawnData = nmsRespawnConfig.respawnData(); + Level nmsWorld = MinecraftServer.getServer().getLevel(nmsRespawnData.dimension()); if (nmsWorld == null) { return null; } - return CraftLocation.toBukkit(nmsRespawnConfig.pos(), nmsWorld.getWorld(), nmsRespawnConfig.angle(), 0); + return CraftLocation.toBukkit(nmsRespawnData.pos(), nmsWorld.getWorld(), nmsRespawnData.yaw(), nmsRespawnData.pitch()); } @Override @@ -430,10 +455,7 @@ public void sendPlayerInfoAddPacket(Player player, EnumSet edit case UPDATE_LISTED -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED; }); } - GameProfile profile = new GameProfile(id, name != null ? name : ProfileEditorImpl.EMPTY_NAME); - if (texture != null) { - profile.getProperties().put("textures", new Property("textures", texture, signature)); - } + GameProfile profile = ProfileEditorImpl.createGameProfile(id, name, texture, signature); // TODO: 1.21.3: Player list order and hat visibility support ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(display, ChatColor.WHITE)), true, player.getPlayerListOrder(), null); PacketHelperImpl.send(player, ProfileEditorImpl.createInfoPacket(actions, List.of(entry))); @@ -483,7 +505,7 @@ public void refreshPlayer(Player player) { nmsPlayer.connection.send(new ClientboundUpdateMobEffectPacket(nmsPlayer.getId(), nmsEffect, false)); } nmsPlayer.onUpdateAbilities(); - PlayerList nmsPlayerList = nmsPlayer.getServer().getPlayerList(); + PlayerList nmsPlayerList = nmsPlayer.server.getPlayerList(); nmsPlayerList.sendPlayerPermissionLevel(nmsPlayer); nmsPlayerList.sendLevelInfo(nmsPlayer, nmsWorld); nmsPlayerList.sendAllPlayerInfo(nmsPlayer); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java index 04dbcce690..89c53a537c 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java @@ -22,7 +22,7 @@ public class WorldHelperImpl implements WorldHelper { @Override public boolean isStatic(World world) { - return ((CraftWorld) world).getHandle().isClientSide; + return ((CraftWorld) world).getHandle().isClientSide(); } @Override @@ -98,7 +98,7 @@ public void wakeUpAllPlayers(World world) { // net.minecraft.server.level.ServerLevel#resetWeatherCycle() @Override public void clearWeather(World world) { - PrimaryLevelData data = ((CraftWorld) world).getHandle().L; + PrimaryLevelData data = ((CraftWorld) world).getHandle().J; data.setRaining(false); if (!data.isRaining()) { data.setRainTime(0); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java index 88e170a755..8507338e11 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java @@ -5,31 +5,34 @@ import com.denizenscript.denizen.nms.abstracts.ProfileEditor; 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.helpers.PacketHelperImpl; import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.collect.ImmutableMultimap; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.datafixers.util.Either; import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_21_R6.CraftServer; import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerRespawnEvent; +import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; +import java.util.*; public class ProfileEditorImpl extends ProfileEditor { @@ -88,14 +91,15 @@ public static ClientboundPlayerInfoUpdatePacket processPlayerInfoUpdatePacket(De } String rename = RenameCommand.getCustomNameFor(entry.profileId(), networkManager.player.getBukkitEntity(), false); GameProfile baseProfile = fakeProfiles.containsKey(entry.profileId()) ? getGameProfile(fakeProfiles.get(entry.profileId())) : entry.profile(); - GameProfile modifiedProfile = new GameProfile(baseProfile.getId(), rename != null ? (rename.length() > 16 ? rename.substring(0, 16) : rename) : baseProfile.getName()); + PropertyMap modifiedProperties; if (ProfileEditor.mirrorUUIDs.contains(entry.profileId())) { - modifiedProfile.getProperties().putAll(ownProfile.getProperties()); + modifiedProperties = ownProfile.properties(); } else { // On Paper 1.19+, we use Paper's PlayerProfile API instead of this system - modifiedProfile.getProperties().putAll(Denizen.supportsPaper ? entry.profile().getProperties() : baseProfile.getProperties()); + modifiedProperties = Denizen.supportsPaper ? entry.profile().properties() : baseProfile.properties(); } + GameProfile modifiedProfile = new GameProfile(baseProfile.id(), rename != null ? (rename.length() > 16 ? rename.substring(0, 16) : rename) : baseProfile.name(), modifiedProperties); String listRename = RenameCommand.getCustomNameFor(entry.profileId(), networkManager.player.getBukkitEntity(), true); Component displayName = listRename != null ? Handler.componentToNMS(FormattedTextHelper.parse(listRename, ChatColor.WHITE)) : entry.displayName(); ClientboundPlayerInfoUpdatePacket.Entry modifiedEntry = new ClientboundPlayerInfoUpdatePacket.Entry(entry.profileId(), modifiedProfile, entry.listed(), entry.latency(), entry.gameMode(), displayName, entry.showHat(), entry.listOrder(), entry.chatSession()); @@ -121,17 +125,45 @@ public static ClientboundPlayerInfoUpdatePacket createInfoPacket(EnumSet unpacked = (Either) RESOLVABLEPROFILE_UNPACK.invokeExact(resolvableProfile); + return unpacked.map(GameProfile::id, + partial -> { + try { + Optional uuid = (Optional) RESOLVABLEPROFILE_PARTIAL_ID.invoke(partial); + return uuid.orElse(null); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + } + ); + } + catch (Throwable e) { + Debug.echoError(e); + return null; } - return gameProfile; } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java index 8bd06d5c14..e6d56fbac7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java @@ -608,9 +608,9 @@ public void handleContainerSlotStateChanged(ServerboundContainerSlotStateChanged } @Override - public void handleDebugSampleSubscription(ServerboundDebugSampleSubscriptionPacket packet) { + public void handleDebugSubscriptionRequest(ServerboundDebugSubscriptionRequestPacket packet) { if (handlePacketIn(packet)) { return; } - oldListener.handleDebugSampleSubscription(packet); + oldListener.handleDebugSubscriptionRequest(packet); } @Override diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java index e6dae30090..f1d556d7ae 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -272,7 +272,7 @@ public void debugOutputPacket(Packet packet) { } else if (packet instanceof ClientboundSetEntityMotionPacket) { ClientboundSetEntityMotionPacket velPacket = (ClientboundSetEntityMotionPacket) packet; - doPacketOutput("Packet: ClientboundSetEntityMotionPacket sent to " + player.getScoreboardName() + " for entity ID: " + velPacket.getId() + ": " + velPacket.getXa() + "," + velPacket.getYa() + "," + velPacket.getZa()); + doPacketOutput("Packet: ClientboundSetEntityMotionPacket sent to " + player.getScoreboardName() + " for entity ID: " + velPacket.getId() + ": " + velPacket.getMovement()); } else if (packet instanceof ClientboundAddEntityPacket) { ClientboundAddEntityPacket addEntityPacket = (ClientboundAddEntityPacket) packet; @@ -290,8 +290,8 @@ else if (packet instanceof ClientboundRemoveEntitiesPacket) { else if (packet instanceof ClientboundPlayerInfoUpdatePacket) { ClientboundPlayerInfoUpdatePacket playerInfoPacket = (ClientboundPlayerInfoUpdatePacket) packet; doPacketOutput("Packet: ClientboundPlayerInfoPacket sent to " + player.getScoreboardName() + " of types " + playerInfoPacket.actions() + " for player profiles: " + - playerInfoPacket.entries().stream().map(p -> "mode=" + p.gameMode() + "/latency=" + p.latency() + "/display=" + p.displayName() + "/name=" + p.profile().getName() + "/id=" + p.profile().getId() + "/" - + p.profile().getProperties().asMap().entrySet().stream().map(e -> e.getKey() + "=" + e.getValue().stream().map(v -> v.value() + ";" + v.signature()).collect(Collectors.joining(";;;"))).collect(Collectors.joining("/"))).collect(Collectors.joining(", "))); + playerInfoPacket.entries().stream().map(p -> "mode=" + p.gameMode() + "/latency=" + p.latency() + "/display=" + p.displayName() + "/name=" + p.profile().name() + "/id=" + p.profile().id() + "/" + + p.profile().properties().asMap().entrySet().stream().map(e -> e.getKey() + "=" + e.getValue().stream().map(v -> v.value() + ";" + v.signature()).collect(Collectors.joining(";;;"))).collect(Collectors.joining("/"))).collect(Collectors.joining(", "))); } else { doPacketOutput("Packet: " + packet.getClass().getCanonicalName() + " sent to " + player.getScoreboardName()); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 7c538b3ae2..dfe309b3db 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -22,6 +22,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.Strategy; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; @@ -44,7 +45,7 @@ public class FakeBlockHelper { public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); - public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 3).findFirst().get(); + public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 2).findFirst().get(); public static BlockState getNMSState(FakeBlock block) { return ((CraftBlockData) block.material.getModernData()).getState(); @@ -123,9 +124,9 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo for (int y = minChunkY; y < maxChunkY; y++) { int blockCount = serial.readShort(); // reflected constructors as workaround for spigot remapper bug - Mojang "IdMap" became Spigot "IRegistry" but should be "Registry" - PalettedContainer states = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + PalettedContainer states = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); states.read(serial); - PalettedContainer biomes = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(biomeRegistry, biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer biomes = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry)); biomes.read(serial); if (anyBlocksInSection(blocks, y)) { int minY = y << 4; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java index a23de7900f..21e5d5ba0c 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java @@ -73,13 +73,13 @@ public static Packet processTablistPacket(DenizenNetwo for (ClientboundPlayerInfoUpdatePacket.Entry update : infoPacket.entries()) { GameProfile profile = update.profile(); String texture = null, signature = null; - if (profile.getProperties().containsKey("textures")) { - Property property = profile.getProperties().get("textures").stream().findFirst().get(); + if (profile.properties().containsKey("textures")) { + Property property = profile.properties().get("textures").stream().findFirst().get(); texture = property.value(); signature = property.signature(); } String modeText = update.gameMode() == null ? null : update.gameMode().name(); - PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData(mode, profile.getId(), update.listed(), profile.getName(), + PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData(mode, profile.id(), update.listed(), profile.name(), update.displayName() == null ? null : FormattedTextHelper.stringify(Handler.componentToSpigot(update.displayName())), modeText, texture, signature, update.latency()); PlayerReceivesTablistUpdateScriptEvent.fire(networkManager.player.getBukkitEntity(), data); if (data.modified) { @@ -93,11 +93,8 @@ public static Packet processTablistPacket(DenizenNetwo } } if (!data.cancelled) { - GameProfile newProfile = new GameProfile(data.id, data.name); - if (data.texture != null) { - newProfile.getProperties().put("textures", new Property("textures", data.texture, data.signature)); - } - ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(newProfile.getId(), newProfile, data.isListed, data.latency, data.gamemode == null ? null : GameType.byName(CoreUtilities.toLowerCase(data.gamemode)), + GameProfile newProfile = ProfileEditorImpl.createGameProfile(data.id, data.name, data.texture, data.signature); + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(newProfile.id(), newProfile, data.isListed, data.latency, data.gamemode == null ? null : GameType.byName(CoreUtilities.toLowerCase(data.gamemode)), data.display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(data.display, ChatColor.WHITE)), update.showHat(), update.listOrder(), update.chatSession()); networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(entry))); } From 27b34f6bfb91e4feb8a4777b17ebb2df87beb719 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 2 Oct 2025 00:58:35 +0100 Subject: [PATCH 027/169] `debugblock`: minimal compatibility, meta note --- .../scripts/commands/player/DebugBlockCommand.java | 10 ++++++++-- .../denizen/nms/v1_21/helpers/PacketHelperImpl.java | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/DebugBlockCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/DebugBlockCommand.java index 5d8312f97e..defcfd3b8f 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/DebugBlockCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/DebugBlockCommand.java @@ -5,15 +5,15 @@ import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizen.utilities.Utilities; -import com.denizenscript.denizencore.objects.core.ColorTag; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; import com.denizenscript.denizencore.objects.Argument; +import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.objects.core.DurationTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.commands.AbstractCommand; +import com.denizenscript.denizencore.utilities.debugging.Debug; import java.util.Collections; import java.util.List; @@ -43,6 +43,12 @@ public DebugBlockCommand() { // // If arguments are unspecified, the default color is white, the default player is the linked player, the default name is none, and the default duration is 10 seconds. // + // Note that on MC 1.21+ this has limitations (within Minecraft itself), namely: + // - the color is always green. + // - the duration is always 10 seconds. + // - the name can only be a LocationTag and defaults to the debug block's location if unspecified. + // - debug blocks can't be cleared. + // // @Tags // None // diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java index 55c69bc5c7..0c6ddcd2b1 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java @@ -13,6 +13,7 @@ import com.denizenscript.denizen.utilities.maps.MapImage; import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; import com.denizenscript.denizencore.objects.core.ColorTag; +import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.md_5.bungee.api.ChatColor; @@ -353,7 +354,8 @@ public void enableNetworkManager() { @Override public void showDebugTestMarker(Player player, Location location, ColorTag color, String name, int time) { BlockPos nmsPos = CraftLocation.toBlockPosition(location); - send(player, new ClientboundGameTestHighlightPosPacket(nmsPos, nmsPos)); + LocationTag displayPos = !name.isEmpty() ? LocationTag.valueOf(name, CoreUtilities.noDebugContext) : null; + send(player, new ClientboundGameTestHighlightPosPacket(nmsPos, displayPos != null ? CraftLocation.toBlockPosition(displayPos) : nmsPos)); } @Override From af2d566399e2fb5d68df6767fd621af9918dba6e Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 8 Oct 2025 00:23:15 +0100 Subject: [PATCH 028/169] `1.21.10` update --- README.md | 2 +- paper/pom.xml | 2 +- plugin/pom.xml | 2 +- v1_21/pom.xml | 12 ++++++------ .../com/denizenscript/denizen/nms/v1_21/Handler.java | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3427ae9203..79173dc00b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, and 1.21.9! +**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, and 1.21.10! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html diff --git a/paper/pom.xml b/paper/pom.xml index ce394197b1..550955154c 100644 --- a/paper/pom.xml +++ b/paper/pom.xml @@ -25,7 +25,7 @@ io.papermc.paper paper-api - 1.21.9-R0.1-SNAPSHOT + 1.21.10-R0.1-SNAPSHOT provided diff --git a/plugin/pom.xml b/plugin/pom.xml index 80f0daa09f..fce192d44c 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -30,7 +30,7 @@ org.spigotmc spigot-api - 1.21.9-R0.1-SNAPSHOT + 1.21.10-R0.1-SNAPSHOT jar provided diff --git a/v1_21/pom.xml b/v1_21/pom.xml index 03366284f3..0036775b50 100644 --- a/v1_21/pom.xml +++ b/v1_21/pom.xml @@ -19,13 +19,13 @@ org.spigotmc spigot-api - 1.21.9-R0.1-SNAPSHOT + 1.21.10-R0.1-SNAPSHOT provided org.spigotmc spigot - 1.21.9-R0.1-SNAPSHOT + 1.21.10-R0.1-SNAPSHOT remapped-mojang provided @@ -45,9 +45,9 @@ remap-obf - org.spigotmc:minecraft-server:1.21.9-R0.1-SNAPSHOT:txt:maps-mojang + org.spigotmc:minecraft-server:1.21.10-R0.1-SNAPSHOT:txt:maps-mojang true - org.spigotmc:spigot:1.21.9-R0.1-SNAPSHOT:jar:remapped-mojang + org.spigotmc:spigot:1.21.10-R0.1-SNAPSHOT:jar:remapped-mojang true remapped-obf @@ -60,8 +60,8 @@ remap-spigot ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.21.9-R0.1-SNAPSHOT:csrg:maps-spigot - org.spigotmc:spigot:1.21.9-R0.1-SNAPSHOT:jar:remapped-obf + org.spigotmc:minecraft-server:1.21.10-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.21.10-R0.1-SNAPSHOT:jar:remapped-obf diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java index 69fffef268..5266fc39f4 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java @@ -150,7 +150,7 @@ public void undisableAsyncCatcher() { @Override public boolean isExactServerVersionMatch() { - return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("1.21.9") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("614efe5192cd0510bc2ddc5feefa155d"); + return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("1.21.10") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("614efe5192cd0510bc2ddc5feefa155d"); } @Override From 2232f28c799087a9332f12f0b639905d76cc9b7c Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:14:06 +0200 Subject: [PATCH 029/169] `server.recent_tps`: paper compatibility fix (#2782) --- .../denizen/paper/utilities/PaperAPIToolsImpl.java | 5 +++++ .../com/denizenscript/denizen/tags/core/ServerTagBase.java | 2 +- .../com/denizenscript/denizen/utilities/PaperAPITools.java | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java index c468235626..48ed7612df 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java @@ -409,4 +409,9 @@ public void setMaterialTags(Material type, Set tags) { } BlockTagsSetter.INSTANCE.setTags(type, tags); } + + @Override + public double[] getRecentTps() { + return Bukkit.getTPS(); + } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java index f8bda93241..a5ba0146c2 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java +++ b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java @@ -1660,7 +1660,7 @@ else if (nameLow.startsWith(matchInput) && (newMatch.isOnline() == matchPlayer.i // --> tagProcessor.registerTag(ListTag.class, "recent_tps", (attribute, object) -> { ListTag recentTPS = new ListTag(3); - for (double tps : NMSHandler.instance.getRecentTps()) { + for (double tps : PaperAPITools.instance.getRecentTps()) { recentTPS.addObject(new ElementTag(tps)); } return recentTPS; diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java index 2625cc5ced..48bcd0c09b 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java @@ -233,4 +233,8 @@ public boolean hasCustomName(PotionMeta meta) { public void setMaterialTags(Material type, Set tags) { NMSHandler.blockHelper.setVanillaTags(type, tags); } + + public double[] getRecentTps() { + return NMSHandler.instance.getRecentTps(); + } } From 1eabd92ffff4b99906ae8c232addcf502bf587b6 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Sat, 1 Nov 2025 13:24:49 -0700 Subject: [PATCH 030/169] `entity exit vehicle, form/go in block, glide`: update (#2788) --- .../entity/EntityExitsVehicleScriptEvent.java | 12 +++++------- .../entity/EntityFormsBlockScriptEvent.java | 15 ++++++--------- .../events/entity/EntityGlideScriptEvent.java | 12 +++++------- .../entity/EntityGoesIntoBlockScriptEvent.java | 12 ++++++------ 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExitsVehicleScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExitsVehicleScriptEvent.java index 01902181df..5af1f56a4a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExitsVehicleScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExitsVehicleScriptEvent.java @@ -63,13 +63,11 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("vehicle")) { - return vehicle.getDenizenObject(); - } - else if (name.equals("entity")) { - return entity.getDenizenObject(); - } - return super.getContext(name); + return switch (name) { + case "vehicle" -> vehicle.getDenizenObject(); + case "entity" -> entity.getDenizenObject(); + default -> super.getContext(name); + }; } @Override diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityFormsBlockScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityFormsBlockScriptEvent.java index b55d57fdc7..95d02da061 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityFormsBlockScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityFormsBlockScriptEvent.java @@ -63,15 +63,12 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": - return location; - case "material": - return material; - case "entity": - return entity; - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "material" -> material; + case "entity" -> entity; + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityGlideScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityGlideScriptEvent.java index b88c3103d2..c139c128cc 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityGlideScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityGlideScriptEvent.java @@ -66,13 +66,11 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("state")) { - return new ElementTag(state); - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "state" -> new ElementTag(state); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityGoesIntoBlockScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityGoesIntoBlockScriptEvent.java index 957a336fd3..6acd83ccbf 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityGoesIntoBlockScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityGoesIntoBlockScriptEvent.java @@ -63,12 +63,12 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - switch (name) { - case "entity": return entity.getDenizenObject(); - case "location": return location; - case "material": return material; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "location" -> location; + case "material" -> material; + default -> super.getContext(name); + }; } @EventHandler From cae57ceca05a177f48bcae26c156f92466f91269 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Wed, 12 Nov 2025 17:03:24 -0800 Subject: [PATCH 031/169] `entity pose, combust, create portal, despawn`: update (#2786) * EntityChangesPoseScriptEvent, EntityCombustsScriptEvent, EntityCreatePortalScriptEvent, and EntityDespawnScriptEvent * getDenizenObject --- .../entity/EntityChangesPoseScriptEvent.java | 15 ++++---- .../entity/EntityCombustsScriptEvent.java | 36 ++++++++----------- .../entity/EntityCreatePortalScriptEvent.java | 20 ++++------- .../entity/EntityDespawnScriptEvent.java | 12 +++---- 4 files changed, 31 insertions(+), 52 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesPoseScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesPoseScriptEvent.java index a543c74c62..ed6906b1e3 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesPoseScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesPoseScriptEvent.java @@ -68,15 +68,12 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - switch (name) { - case "entity": - return entity; - case "old_pose": - return new ElementTag(oldPose); - case "new_pose": - return new ElementTag(event.getPose()); - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "old_pose" -> new ElementTag(oldPose); + case "new_pose" -> new ElementTag(event.getPose()); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCombustsScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCombustsScriptEvent.java index 74f951aabf..3f7ec80d03 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCombustsScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCombustsScriptEvent.java @@ -80,32 +80,24 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - switch (name) { - case "entity": - return entity.getDenizenObject(); - case "duration": - return new DurationTag(event.getDuration()); - case "source": - if (event instanceof EntityCombustByEntityEvent) { - return new EntityTag(((EntityCombustByEntityEvent) event).getCombuster()).getDenizenObject(); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "duration" -> new DurationTag(event.getDuration()); + case "source" -> { + if (event instanceof EntityCombustByEntityEvent byEntity) { + yield new EntityTag(byEntity.getCombuster()).getDenizenObject(); } - else if (event instanceof EntityCombustByBlockEvent) { - Block combuster = ((EntityCombustByBlockEvent) event).getCombuster(); + else if (event instanceof EntityCombustByBlockEvent byBlock) { + Block combuster = byBlock.getCombuster(); if (combuster != null) { - return new LocationTag(combuster.getLocation()); + yield new LocationTag(combuster.getLocation()); } } - break; - case "source_type": - if (event instanceof EntityCombustByEntityEvent) { - return new ElementTag("ENTITY"); - } - else if (event instanceof EntityCombustByBlockEvent) { - return new ElementTag("LOCATION"); - } - return new ElementTag("NONE"); - } - return super.getContext(name); + yield null; + } + case "source_type" -> new ElementTag(event instanceof EntityCombustByEntityEvent ? "ENTITY" : (event instanceof EntityCombustByBlockEvent ? "LOCATION" : "NONE")); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCreatePortalScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCreatePortalScriptEvent.java index b07b613933..f7b8026318 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCreatePortalScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCreatePortalScriptEvent.java @@ -8,7 +8,6 @@ import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; -import org.bukkit.block.BlockState; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityCreatePortalEvent; @@ -61,19 +60,12 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - switch (name) { - case "entity": - return entity; - case "portal_type": - return new ElementTag(event.getPortalType().toString()); - case "blocks": - ListTag blocks = new ListTag(); - for (BlockState block : event.getBlocks()) { - blocks.add(new LocationTag(block.getBlock().getLocation()).identifySimple()); - } - return blocks; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "portal_type" -> new ElementTag(event.getPortalType().toString()); + case "blocks" -> new ListTag(event.getBlocks(), block -> new LocationTag(block.getLocation())); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityDespawnScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityDespawnScriptEvent.java index e39a215822..ab32db8e67 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityDespawnScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityDespawnScriptEvent.java @@ -63,12 +63,10 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("cause")) { - return cause; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity; + case "cause" -> cause; + default -> super.getContext(name); + }; } } From 1494314d16917b93f63ac8dd819cfc1599ed8c8b Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Thu, 13 Nov 2025 05:18:37 -0800 Subject: [PATCH 032/169] `EntityTag.variant`: copper golems support (#2780) * Copper Golem Variant * changed enum method * bracket fix * requireEnum fix * slight changes * removed getKeyOrThrow --- .../paper/utilities/PaperAPIToolsImpl.java | 19 +++- .../properties/entity/EntityVariant.java | 91 +++++++++++-------- .../denizen/utilities/PaperAPITools.java | 17 +++- 3 files changed, 79 insertions(+), 48 deletions(-) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java index 48ed7612df..b78920a954 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java @@ -11,6 +11,7 @@ import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.DenizenCore; +import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.utilities.CoreUtilities; @@ -20,6 +21,7 @@ import com.destroystokyo.paper.profile.ProfileProperty; import io.papermc.paper.entity.TeleportFlag; import io.papermc.paper.potion.PotionMix; +import io.papermc.paper.world.WeatheringCopperState; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.md_5.bungee.api.ChatColor; @@ -27,10 +29,7 @@ import org.bukkit.*; import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.entity.TextDisplay; +import org.bukkit.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.inventory.InventoryType; @@ -414,4 +413,16 @@ public void setMaterialTags(Material type, Set tags) { public double[] getRecentTps() { return Bukkit.getTPS(); } + + @Override + public String getCopperGolemState(CopperGolem copperGolem) { + return copperGolem.getWeatheringState().name(); + } + + @Override + public void setCopperGolemState(ElementTag variant, CopperGolem copperGolem, Mechanism mechanism) { + if (mechanism.requireEnum(WeatheringCopperState.class)) { + copperGolem.setWeatheringState(variant.asEnum(WeatheringCopperState.class)); + } + } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityVariant.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityVariant.java index 4ded567281..f97f758b57 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityVariant.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityVariant.java @@ -3,15 +3,13 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.EntityTag; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import org.bukkit.entity.Chicken; -import org.bukkit.entity.Cow; -import org.bukkit.entity.Pig; -import org.bukkit.entity.Wolf; +import org.bukkit.entity.*; import java.lang.invoke.MethodHandle; @@ -37,18 +35,21 @@ public class EntityVariant extends EntityProperty { // @name variant // @input ElementTag // @description - // Controls which variant a chicken, cow, pig, or wolf is. + // Controls which variant a chicken, copper golem, cow, pig, or wolf is. // A list of valid chicken variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Chicken.Variant.html>. + // A list of valid copper golem variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/CopperGolem.CopperWeatherState.html>. // A list of valid cow variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Cow.Variant.html>. // A list of valid pig variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Pig.Variant.html>. // A list of valid wolf variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Wolf.Variant.html>. // --> - public static boolean describes(EntityTag entity) { - return entity.getBukkitEntity() instanceof Wolf - || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && entity.getBukkitEntity() instanceof Chicken) - || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && entity.getBukkitEntity() instanceof Cow) - || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && entity.getBukkitEntity() instanceof Pig); + public static boolean describes(EntityTag entityTag) { + Entity entity = entityTag.getBukkitEntity(); + return entity instanceof Wolf + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && (entity instanceof Chicken + || entity instanceof CopperGolem + || entity instanceof Cow + || entity instanceof Pig)); } @Override @@ -56,20 +57,25 @@ public ElementTag getPropertyValue() { if (getEntity() instanceof Wolf wolf) { return new ElementTag(Utilities.namespacedKeyToString(wolf.getVariant().getKey()), true); } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getEntity() instanceof Chicken chicken) { - return new ElementTag(Utilities.namespacedKeyToString(chicken.getVariant().getKey()), true); - } - else if (COW_GET_VARIANT != null && getEntity() instanceof Cow cow) { - try { - return new ElementTag(Utilities.namespacedKeyToString(((Cow.Variant) COW_GET_VARIANT.invoke(cow)).getKey()), true); + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + if (getEntity() instanceof Chicken chicken) { + return new ElementTag(Utilities.namespacedKeyToString(chicken.getVariant().getKey()), true); } - catch (Throwable e) { - Debug.echoError(e); - return null; + else if (getEntity() instanceof CopperGolem copperGolem) { + return new ElementTag(PaperAPITools.instance.getCopperGolemState(copperGolem), true); + } + else if (COW_GET_VARIANT != null && getEntity() instanceof Cow cow) { + try { + return new ElementTag(Utilities.namespacedKeyToString(((Cow.Variant) COW_GET_VARIANT.invoke(cow)).getKey()), true); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + } + else if (getEntity() instanceof Pig pig) { + return new ElementTag(Utilities.namespacedKeyToString(pig.getVariant().getKey()), true); } - } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getEntity() instanceof Pig pig) { - return new ElementTag(Utilities.namespacedKeyToString(pig.getVariant().getKey()), true); } return null; } @@ -82,27 +88,32 @@ public void setPropertyValue(ElementTag variant, Mechanism mechanism) { wolf.setVariant(wolfVariant); } } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getEntity() instanceof Chicken chicken) { - Chicken.Variant chickenVariant = Utilities.elementToRequiredEnumLike(variant, Chicken.Variant.class, mechanism); - if (chickenVariant != null) { - chicken.setVariant(chickenVariant); - } - } - else if (COW_SET_VARIANT != null && getEntity() instanceof Cow cow) { - Cow.Variant cowVariant = Utilities.elementToRequiredEnumLike(variant, Cow.Variant.class, mechanism); - if (cowVariant != null) { - try { - COW_SET_VARIANT.invoke(cow, cowVariant); + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + if (getEntity() instanceof Chicken chicken) { + Chicken.Variant chickenVariant = Utilities.elementToRequiredEnumLike(variant, Chicken.Variant.class, mechanism); + if (chickenVariant != null) { + chicken.setVariant(chickenVariant); } - catch (Throwable e) { - Debug.echoError(e); + } + else if (getEntity() instanceof CopperGolem copperGolem) { + PaperAPITools.instance.setCopperGolemState(variant, copperGolem, mechanism); + } + else if (COW_SET_VARIANT != null && getEntity() instanceof Cow cow) { + Cow.Variant cowVariant = Utilities.elementToRequiredEnumLike(variant, Cow.Variant.class, mechanism); + if (cowVariant != null) { + try { + COW_SET_VARIANT.invoke(cow, cowVariant); + } + catch (Throwable e) { + Debug.echoError(e); + } } } - } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getEntity() instanceof Pig pig) { - Pig.Variant pigVariant = Utilities.elementToRequiredEnumLike(variant, Pig.Variant.class, mechanism); - if (pigVariant != null) { - pig.setVariant(pigVariant); + else if (getEntity() instanceof Pig pig) { + Pig.Variant pigVariant = Utilities.elementToRequiredEnumLike(variant, Pig.Variant.class, mechanism); + if (pigVariant != null) { + pig.setVariant(pigVariant); + } } } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java index 48bcd0c09b..5ee627cd11 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java @@ -5,16 +5,15 @@ import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; import com.denizenscript.denizen.scripts.containers.core.ItemScriptContainer; import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.*; import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.entity.TextDisplay; +import org.bukkit.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.inventory.InventoryType; @@ -237,4 +236,14 @@ public void setMaterialTags(Material type, Set tags) { public double[] getRecentTps() { return NMSHandler.instance.getRecentTps(); } + + public String getCopperGolemState(CopperGolem copperGolem) { + return copperGolem.getWeatherState().name(); + } + + public void setCopperGolemState(ElementTag variant, CopperGolem copperGolem, Mechanism mechanism) { + if (mechanism.requireEnum(CopperGolem.CopperWeatherState.class)) { + copperGolem.setWeatherState(variant.asEnum(CopperGolem.CopperWeatherState.class)); + } + } } From 8f57b87921509cf49f10df0b6590b9a49ef550c0 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Thu, 13 Nov 2025 05:29:16 -0800 Subject: [PATCH 033/169] `entity drops item, enters/exists portal, enters vehicle`: modernize (#2787) * EntityDropsItemScriptEvent, EntityEntersPortalScriptEvent, EntityEntersVehicleScriptEvent, and EntityExitsPortalScriptEvent * getDenizenObject * minor fix --- .../entity/EntityDropsItemScriptEvent.java | 18 +++++++----------- .../entity/EntityEntersPortalScriptEvent.java | 12 +++++------- .../entity/EntityEntersVehicleScriptEvent.java | 12 +++++------- .../entity/EntityExitsPortalScriptEvent.java | 12 +++++------- 4 files changed, 22 insertions(+), 32 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityDropsItemScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityDropsItemScriptEvent.java index 21942ffb38..55184b440a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityDropsItemScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityDropsItemScriptEvent.java @@ -68,17 +68,13 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - switch (name) { - case "item": - return item; - case "entity": - return itemEntity; - case "dropped_by": - return dropper.getDenizenObject(); - case "location": - return location; - } - return super.getContext(name); + return switch (name) { + case "item" -> item; + case "entity" -> itemEntity; + case "dropped_by" -> dropper.getDenizenObject(); + case "location" -> location; + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityEntersPortalScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityEntersPortalScriptEvent.java index 40799e70a8..e08bb23c75 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityEntersPortalScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityEntersPortalScriptEvent.java @@ -59,13 +59,11 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("location")) { - return location; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "location" -> location; + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityEntersVehicleScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityEntersVehicleScriptEvent.java index 6fefc81e8f..dae5c17519 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityEntersVehicleScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityEntersVehicleScriptEvent.java @@ -79,13 +79,11 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("vehicle")) { - return vehicle.getDenizenObject(); - } - else if (name.equals("entity")) { - return entity.getDenizenObject(); - } - return super.getContext(name); + return switch (name) { + case "vehicle" -> vehicle.getDenizenObject(); + case "entity" -> entity.getDenizenObject(); + default -> super.getContext(name); + }; } @Override diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExitsPortalScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExitsPortalScriptEvent.java index 211b259437..6bcaf28b5e 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExitsPortalScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExitsPortalScriptEvent.java @@ -59,13 +59,11 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("location")) { - return location; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "location" -> location; + default -> super.getContext(name); + }; } @EventHandler From 8e018cd268057e44d44949973c11c1eaff9e351e Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Sun, 16 Nov 2025 17:48:32 +0100 Subject: [PATCH 034/169] `EntityTag.detonate` mech: fix wind charge support (#2793) --- .../denizen/objects/EntityTag.java | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java index 81a797a550..ac5ffe4a29 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java @@ -3223,6 +3223,29 @@ else if (object.getBukkitEntity() instanceof Hanging hanging) { fox.setSleeping(input.asBoolean()); }); + // <--[mechanism] + // @object EntityTag + // @name detonate + // @input None + // @description + // If the entity is a firework, creeper, or wind charge, detonates it. + // --> + tagProcessor.registerMechanism("detonate", false, (object, mechanism) -> { + Entity entity = object.getBukkitEntity(); + if (entity instanceof Firework firework) { + firework.detonate(); + } + else if (entity instanceof Creeper creeper) { + creeper.explode(); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && entity instanceof AbstractWindCharge windCharge) { + windCharge.explode(); + } + else { + mechanism.echoError("Cannot detonate entity of type '" + object.getBukkitEntityType().name() + "'."); + } + }); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { // <--[mechanism] @@ -4130,28 +4153,6 @@ public void adjust(Mechanism mechanism) { getLivingEntity().setSwimming(mechanism.getValue().asBoolean()); } - // <--[mechanism] - // @object EntityTag - // @name detonate - // @input None - // @description - // If the entity is a firework, creeper, or wind charge, detonates it. - // --> - if (mechanism.matches("detonate")) { - if (getBukkitEntity() instanceof Firework firework) { - firework.detonate(); - } - else if (getBukkitEntity() instanceof Creeper creeper) { - creeper.explode(); - } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBukkitEntity() instanceof WindCharge windCharge) { - windCharge.explode(); - } - else { - Debug.echoError("Cannot detonate entity of type '" + getBukkitEntityType().name() + "'."); - } - } - // <--[mechanism] // @object EntityTag // @name ignite From 955934f2163f2b066219264ca2050c9ee177d111 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Sat, 22 Nov 2025 16:47:46 -0800 Subject: [PATCH 035/169] `area enter/exit, creeper powered, entity breaks hanging/changes block`: update (#2785) * AreaEnterExitScriptEvent, CreeperPoweredScriptEvent, EntityBreaksHangingScriptEvent, and EntityChangesBlockScriptEvent * getDenizenObject * shortened context --- .../entity/AreaEnterExitScriptEvent.java | 91 +++++++++---------- .../entity/CreeperPoweredScriptEvent.java | 16 ++-- .../EntityBreaksHangingScriptEvent.java | 18 ++-- .../entity/EntityChangesBlockScriptEvent.java | 18 ++-- 4 files changed, 62 insertions(+), 81 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/AreaEnterExitScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/AreaEnterExitScriptEvent.java index f9fb2c4ba0..15438d8915 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/AreaEnterExitScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/AreaEnterExitScriptEvent.java @@ -53,7 +53,6 @@ public AreaEnterExitScriptEvent() { registerCouldMatcher(" enters|exits "); } - public EntityTag currentEntity; public AreaContainmentObject area; public boolean isEntering; @@ -87,52 +86,46 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("area")) { - return area; - } - else if (name.equals("cause")) { - String cause; - if (currentEvent instanceof PlayerJoinEvent) { - cause = "JOIN"; - } - else if (currentEvent instanceof PlayerQuitEvent) { - cause = "QUIT"; - } - else if (currentEvent instanceof PlayerChangedWorldEvent) { - cause = "WORLD_CHANGE"; - } - else if (currentEvent instanceof PlayerTeleportEvent) { - cause = "TELEPORT"; - } - else if (currentEvent instanceof VehicleMoveEvent) { - cause = "VEHICLE"; - } - else if (currentEvent instanceof PlayerMoveEvent) { - cause = "WALK"; - } - else { - cause = "UNKNOWN"; - } - return new ElementTag(cause); - } - else if (name.equals("to") && to != null) { - return new LocationTag(to); - } - else if (name.equals("from")) { - if (currentEvent instanceof PlayerMoveEvent) { - return new LocationTag(((PlayerMoveEvent) currentEvent).getFrom()); - } - else if (currentEvent instanceof VehicleMoveEvent) { - return new LocationTag(((VehicleMoveEvent) currentEvent).getFrom()); + return switch (name) { + case "area" -> area; + case "cause" -> { + if (currentEvent instanceof PlayerJoinEvent) { + yield new ElementTag("JOIN"); + } + else if (currentEvent instanceof PlayerQuitEvent) { + yield new ElementTag("QUIT"); + } + else if (currentEvent instanceof PlayerChangedWorldEvent) { + yield new ElementTag("WORLD_CHANGE"); + } + else if (currentEvent instanceof PlayerTeleportEvent) { + yield new ElementTag("TELEPORT"); + } + else if (currentEvent instanceof VehicleMoveEvent) { + yield new ElementTag("VEHICLE"); + } + else if (currentEvent instanceof PlayerMoveEvent) { + yield new ElementTag("WALK"); + } + else { + yield new ElementTag("UNKNOWN"); + } } - else { - return new LocationTag(currentEntity.getLocation()); + case "to" -> to != null ? new LocationTag(to) : null; + case "from" -> { + if (currentEvent instanceof PlayerMoveEvent playerMove) { + yield new LocationTag(playerMove.getFrom()); + } + else if (currentEvent instanceof VehicleMoveEvent vehicleMove) { + yield new LocationTag(vehicleMove.getFrom()); + } + else { + yield new LocationTag(currentEntity.getLocation()); + } } - } - else if (name.equals("entity")) { - return currentEntity.getDenizenObject(); - } - return super.getContext(name); + case "entity" -> currentEntity.getDenizenObject(); + default -> super.getContext(name); + }; } public void registerCorrectClass() { @@ -178,7 +171,7 @@ else if (!needsMatchers && (matcher instanceof ExactMatchHelper)) { } exactTracked = needsMatchers ? null : exacts.toArray(new String[0]); matchers = needsMatchers ? matchList.toArray(new MatchHelper[0]) : null; - flagTracked = flags.size() > 0 ? flags.toArray(new String[0]) : null; + flagTracked = !flags.isEmpty() ? flags.toArray(new String[0]) : null; registerCorrectClass(); } @@ -258,7 +251,7 @@ public void processNewPosition(EntityTag entity, Location pos, Event eventCause) if (doTrackAll || matchers != null || flagTracked != null) { if (pos != null) { NotedAreaTracker.forEachAreaThatContains(new LocationTag(pos), (a) -> { - if (a instanceof FlaggableObject && anyMatch(a.getNoteName(), (FlaggableObject) a)) { + if (a instanceof FlaggableObject flaggable && anyMatch(a.getNoteName(), flaggable)) { processSingle(a, entity, inAreas, pos, eventCause); } }); @@ -279,11 +272,11 @@ public void processNewPosition(EntityTag entity, Location pos, Event eventCause) else { for (String name : exactTracked) { Notable obj = NoteManager.getSavedObject(name); - if (!(obj instanceof AreaContainmentObject)) { + if (!(obj instanceof AreaContainmentObject areaObject)) { Debug.echoError("Invalid area enter/exit event area '" + name + "'"); continue; } - processSingle((AreaContainmentObject) obj, entity, inAreas, pos, eventCause); + processSingle(areaObject, entity, inAreas, pos, eventCause); } } if (inAreas != null && inAreas.isEmpty()) { diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/CreeperPoweredScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/CreeperPoweredScriptEvent.java index 3eaee2ea7a..5c81f08581 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/CreeperPoweredScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/CreeperPoweredScriptEvent.java @@ -53,16 +53,12 @@ public boolean matches(ScriptPath path) { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("lightning") && lightning != null) { - return lightning; - } - else if (name.equals("cause")) { - return cause; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity; + case "lightning" -> lightning; + case "cause" -> cause; + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityBreaksHangingScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityBreaksHangingScriptEvent.java index aa4a142ce0..3a9b087522 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityBreaksHangingScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityBreaksHangingScriptEvent.java @@ -88,17 +88,13 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - switch (name) { - case "cause": - return cause; - case "breaker": - return breaker; - case "hanging": - return hanging; - case "location": - return location; - } - return super.getContext(name); + return switch (name) { + case "cause" -> cause; + case "breaker" -> breaker.getDenizenObject(); + case "hanging" -> hanging; + case "location" -> location; + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesBlockScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesBlockScriptEvent.java index 873ccd4de9..d5c3d82ca1 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesBlockScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesBlockScriptEvent.java @@ -78,17 +78,13 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - switch (name) { - case "entity": - return entity; - case "location": - return location; - case "new_material": - return new_material; - case "old_material": - return old_material; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "location" -> location; + case "new_material" -> new_material; + case "old_material" -> old_material; + default -> super.getContext(name); + }; } @EventHandler From 543e1357277149069a728c039f32120e092ca1fb Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Sat, 22 Nov 2025 16:53:59 -0800 Subject: [PATCH 036/169] `entity interacts/spawns/swims/tamed`: update (#2789) * EntityInteractScriptEvent, EntitySpawnScriptEvent, EntitySwimScriptEvent, and EntityTamesScriptEvent * getDenizenObject * minor change --- .../entity/EntityInteractScriptEvent.java | 12 ++++---- .../events/entity/EntitySpawnScriptEvent.java | 24 ++++++--------- .../events/entity/EntitySwimScriptEvent.java | 12 ++++---- .../events/entity/EntityTamesScriptEvent.java | 29 +++++-------------- 4 files changed, 27 insertions(+), 50 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityInteractScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityInteractScriptEvent.java index 404cf77b40..8c433ab55c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityInteractScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityInteractScriptEvent.java @@ -61,13 +61,11 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("location")) { - return location; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "location" -> location; + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySpawnScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySpawnScriptEvent.java index 0ac74a8b35..31602998bf 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySpawnScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySpawnScriptEvent.java @@ -79,19 +79,13 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("location")) { - return location; - } - else if (name.equals("reason")) { - return reason; - } - else if (name.equals("spawner_location") && event instanceof SpawnerSpawnEvent) { - return new LocationTag(((SpawnerSpawnEvent) event).getSpawner().getLocation()); - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity; + case "location" -> location; + case "reason" -> reason; + case "spawner_location" -> event instanceof SpawnerSpawnEvent spawner ? new LocationTag(spawner.getSpawner().getLocation()) : null; + default -> super.getContext(name); + }; } @EventHandler @@ -99,8 +93,8 @@ public void onEntitySpawn(EntitySpawnEvent event) { Entity entity = event.getEntity(); this.entity = new EntityTag(entity); location = new LocationTag(event.getLocation()); - if (event instanceof CreatureSpawnEvent) { - CreatureSpawnEvent.SpawnReason creatureReason = ((CreatureSpawnEvent) event).getSpawnReason(); + if (event instanceof CreatureSpawnEvent creatureSpawn) { + CreatureSpawnEvent.SpawnReason creatureReason = creatureSpawn.getSpawnReason(); if (creatureReason == CreatureSpawnEvent.SpawnReason.SPAWNER) { return; // Let the SpawnerSpawnEvent happen and handle it instead } diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySwimScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySwimScriptEvent.java index f189083ad9..9f9199d0af 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySwimScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySwimScriptEvent.java @@ -66,13 +66,11 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("state")) { - return new ElementTag(state); - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "state" -> new ElementTag(state); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityTamesScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityTamesScriptEvent.java index 10881babc4..8c287f3983 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityTamesScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityTamesScriptEvent.java @@ -19,8 +19,6 @@ public class EntityTamesScriptEvent extends BukkitScriptEvent implements Listene // player tames entity // player tames // - // @Regex ^on [^\s]+ (tames [^\s]+|tamed)$ - // // @Group Entity // // @Location true @@ -33,28 +31,19 @@ public class EntityTamesScriptEvent extends BukkitScriptEvent implements Listene // returns a EntityTag of the tamed entity. // returns a EntityTag of the owner. // - // @Player when a player tames an entity and using the 'players tames entity' event. + // @Player when a player is what tamed the entity. // // --> public EntityTamesScriptEvent() { + registerCouldMatcher(" tamed"); + registerCouldMatcher("player tames "); } public EntityTag entity; public EntityTag owner; public EntityTameEvent event; - @Override - public boolean couldMatch(ScriptPath path) { - if (!path.eventArgLowerAt(1).equals("tames") && !path.eventArgLowerAt(1).equals("tamed")) { - return false; - } - if (!couldMatchEntity(path.eventArgLowerAt(0))) { - return false; - } - return true; - } - @Override public boolean matches(ScriptPath path) { String cmd = path.eventArgLowerAt(1); @@ -76,13 +65,11 @@ public ScriptEntryData getScriptEntryData() { @Override public ObjectTag getContext(String name) { - if (name.equals("entity")) { - return entity; - } - else if (name.equals("owner")) { - return owner; - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity; + case "owner" -> owner.getDenizenObject(); + default -> super.getContext(name); + }; } @EventHandler From c4760af5b3426e40bc3f5c6fb58afabc12530adc Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:27:05 +0100 Subject: [PATCH 037/169] Server links support (#2754) * add util method * add link send event * add player and server mechs * move event to paper * fixes * fix * some fixes * meta change * fixes * ups * rename --- .../denizen/paper/PaperModule.java | 3 + .../events/PlayerLinksSendScriptEvent.java | 69 +++++++++++++++++++ .../paper/utilities/PaperAPIToolsImpl.java | 6 ++ .../denizen/objects/PlayerTag.java | 27 ++++++++ .../denizen/tags/core/ServerTagBase.java | 26 +++++++ .../denizen/utilities/PaperAPITools.java | 5 ++ .../denizen/utilities/Utilities.java | 53 ++++++++++++++ 7 files changed, 189 insertions(+) create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerLinksSendScriptEvent.java diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index 58ff60ed66..f83c2594e6 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -66,6 +66,9 @@ public static void init() { ScriptEvent.registerScriptEvent(PlayerItemTakesDamageScriptEventPaperImpl.class); ScriptEvent.registerScriptEvent(PlayerJumpsScriptEventPaperImpl.class); ScriptEvent.registerScriptEvent(PlayerLecternPageChangeScriptEvent.class); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + ScriptEvent.registerScriptEvent(PlayerLinksSendScriptEvent.class); + } ScriptEvent.registerScriptEvent(PlayerLoomPatternSelectScriptEvent.class); ScriptEvent.registerScriptEvent(PlayerNameEntityScriptEvent.class); if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerLinksSendScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerLinksSendScriptEvent.java new file mode 100644 index 0000000000..d05c079346 --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerLinksSendScriptEvent.java @@ -0,0 +1,69 @@ +package com.denizenscript.denizen.paper.events; + +import com.denizenscript.denizen.events.BukkitScriptEvent; +import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; +import com.denizenscript.denizencore.objects.core.ListTag; +import com.denizenscript.denizencore.scripts.ScriptEntryData; +import io.papermc.paper.connection.PlayerConfigurationConnection; +import io.papermc.paper.connection.PlayerGameConnection; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerLinksSendEvent; + +public class PlayerLinksSendScriptEvent extends BukkitScriptEvent implements Listener { + + // <--[event] + // @Events + // player receives links + // + // @Group Paper + // + // @Plugin Paper + // + // @Triggers when a player receives a list of links + // + // @Determine + // "LINKS:" to set the links sent to the player. Each item in the list must be a MapTag in <@link language Server Links Format>. + // "ADD_LINKS:" to add to the links sent to the player. Each item in the list must be a MapTag in <@link language Server Links Format>. + // + // @Player Always. + // + // @Warning this may fire early in the player login process, during which the linked player is essentially an offline player + // + // --> + + public PlayerLinksSendEvent event; + public PlayerTag player; + + public PlayerLinksSendScriptEvent() { + registerCouldMatcher("player receives links"); + this.registerDetermination("links", ListTag.class, (evt, context, value) -> { + Utilities.replaceServerLinks(evt.event.getLinks(), value, context); + }); + this.registerDetermination("add_links", ListTag.class, (evt, context, value) -> { + Utilities.fillServerLinks(evt.event.getLinks(), value, context); + }); + } + + @Override + public ScriptEntryData getScriptEntryData() { + return new BukkitScriptEntryData(player, null); + } + + @EventHandler + public void onPlayerLinksSend(PlayerLinksSendEvent event) { + if (event.getConnection() instanceof PlayerGameConnection connection) { + player = new PlayerTag(connection.getPlayer()); + } + else if (event.getConnection() instanceof PlayerConfigurationConnection connection) { + player = new PlayerTag(connection.getProfile().getId()); + } + else { + player = null; + } + this.event = event; + fire(event); + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java index b78920a954..0b6d741ced 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java @@ -40,6 +40,7 @@ import org.bukkit.scoreboard.Team; import org.bukkit.util.Consumer; +import java.net.URI; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -409,6 +410,11 @@ public void setMaterialTags(Material type, Set tags) { BlockTagsSetter.INSTANCE.setTags(type, tags); } + @Override + public void addLink(ServerLinks links, String display, URI uri) { + links.addLink(PaperModule.parseFormattedText(display, ChatColor.WHITE), uri); + } + @Override public double[] getRecentTps() { return Bukkit.getTPS(); diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java index eae5750277..39803af57d 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java @@ -2679,6 +2679,33 @@ else if (mechanism.requireObject(LocationTag.class)) { object.getNBTEditor().setSpawnForced(input.asBoolean()); } }); + + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + + // <--[mechanism] + // @object PlayerTag + // @name links + // @input ListTag(MapTag) + // @description + // Sends the specified list of server links to the player. This will override existing links player has. + // Each item in the list must be a MapTag in <@link language Server Links Format>. + // Generally prefer <@link mechanism PlayerTag.add_links> + // --> + registerOnlineOnlyMechanism("links", ListTag.class, (player, mechanism, input) -> { + player.getPlayerEntity().sendLinks(Utilities.replaceServerLinks(Bukkit.getServerLinks().copy(), input, mechanism.context)); + }); + + // <--[mechanism] + // @object PlayerTag + // @name add_links + // @input ListTag(MapTag) + // @description + // Adds the specified list of server links to the player. Each item in the list must be a MapTag in <@link language Server Links Format>. + // --> + registerOnlineOnlyMechanism("add_links", ListTag.class, (player, mechanism, input) -> { + player.getPlayerEntity().sendLinks(Utilities.fillServerLinks(Bukkit.getServerLinks().copy(), input, mechanism.context)); + }); + } } public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); diff --git a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java index a5ba0146c2..8055583ee4 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java +++ b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java @@ -2025,6 +2025,32 @@ else if (nameLow.startsWith(matchInput) && (newMatch.isOnline() == matchPlayer.i } }); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + + // <--[mechanism] + // @object server + // @name links + // @input ListTag(MapTag) + // @description + // Sets the default server links. Each item in the list must be a MapTag in <@link language Server Links Format>. + // Generally prefer <@link mechanism server.add_links> + // --> + tagProcessor.registerMechanism("links", false, ListTag.class, (object, mechanism, input) -> { + Utilities.replaceServerLinks(Bukkit.getServerLinks(), input, mechanism.context); + }); + + // <--[mechanism] + // @object server + // @name add_links + // @input ListTag(MapTag) + // @description + // Adds links to the default server links. Each item in the list must be a MapTag in <@link language Server Links Format>. + // --> + tagProcessor.registerMechanism("add_links", false, ListTag.class, (object, mechanism, input) -> { + Utilities.fillServerLinks(Bukkit.getServerLinks(), input, mechanism.context); + }); + } + // <--[mechanism] // @object server // @name default_colors diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java index 5ee627cd11..6f6877e768 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java @@ -24,6 +24,7 @@ import org.bukkit.util.Consumer; import java.lang.invoke.MethodHandle; +import java.net.URI; import java.util.List; import java.util.Set; import java.util.function.Predicate; @@ -233,6 +234,10 @@ public void setMaterialTags(Material type, Set tags) { NMSHandler.blockHelper.setVanillaTags(type, tags); } + public void addLink(ServerLinks links, String display, URI uri) { + links.addLink(display, uri); + } + public double[] getRecentTps() { return NMSHandler.instance.getRecentTps(); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java index 1487700384..45606f2846 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java @@ -13,8 +13,10 @@ import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; +import com.denizenscript.denizencore.objects.core.MapTag; import com.denizenscript.denizencore.objects.core.ScriptTag; import com.denizenscript.denizencore.scripts.ScriptEntry; +import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.AsciiMatcher; import com.denizenscript.denizencore.utilities.CoreConfiguration; @@ -38,6 +40,8 @@ import java.io.File; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.*; /** @@ -645,4 +649,53 @@ public static boolean requireEnumlike(Mechanism mechanism, Class type) { } return true; } + + // <--[language] + // @name Server Links Format + // @group Minecraft Logic + // @description + // Server links are represented in Denizen as <@link ObjectType MapTag>s with the following keys: + // - link: The address of the link. + // - type: The type of the link. Valid types are listed at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/ServerLinks.Type.html> + // - display: The display name of the link. + // When constructing this map, the "link" key is required. You can then optionally specify either the "type" or "display" key. + // --> + + public static ServerLinks replaceServerLinks(ServerLinks serverLinks, ListTag list, TagContext context) { + serverLinks.getLinks().forEach(serverLinks::removeLink); + return fillServerLinks(serverLinks, list, context); + } + + public static ServerLinks fillServerLinks(ServerLinks serverLinks, ListTag list, TagContext context) { + for (MapTag map : list.filter(MapTag.class, context)) { + if (!map.containsKey("link")) { + Debug.echoError("Invalid server links map '" + map + "': missing 'link' key!"); + continue; + } + URI uri; + String strUri = map.getElement("link").asString(); + try { + uri = new URI(strUri); + } + catch (URISyntaxException e) { + Debug.echoError("Invalid server links map '" + map + "': invalid 'link' key: " + strUri); + continue; + } + if (map.containsKey("display")) { + PaperAPITools.instance.addLink(serverLinks, map.getElement("display").asString(), uri); + } + else if (map.containsKey("type")) { + ServerLinks.Type type = map.getElement("type").asEnum(ServerLinks.Type.class); + if (type == null) { + Debug.echoError("Invalid server links map '" + map + "': invalid 'type' key: " + map.getElement("type")); + continue; + } + serverLinks.addLink(type, uri); + } + else { + Debug.echoError("Invalid server links map '" + map + "': must have either a 'display' or 'type' key!"); + } + } + return serverLinks; + } } From f2a556f0318f61dc938b659a84b116ca3b0e88af Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 24 Nov 2025 11:47:08 +0000 Subject: [PATCH 038/169] Minor cleanups to recent PRs --- .../entity/AreaEnterExitScriptEvent.java | 22 +++++++++++-------- .../entity/EntityChangesBlockScriptEvent.java | 16 +++++++------- .../entity/EntityCombustsScriptEvent.java | 8 +++---- .../entity/EntityCreatePortalScriptEvent.java | 8 +++---- .../events/entity/EntitySpawnScriptEvent.java | 10 ++++----- .../denizen/objects/EntityTag.java | 2 +- 6 files changed, 35 insertions(+), 31 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/AreaEnterExitScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/AreaEnterExitScriptEvent.java index 15438d8915..99aead67d9 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/AreaEnterExitScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/AreaEnterExitScriptEvent.java @@ -1,9 +1,10 @@ package com.denizenscript.denizen.events.entity; import com.denizenscript.denizen.events.BukkitScriptEvent; -import com.denizenscript.denizen.objects.*; +import com.denizenscript.denizen.objects.AreaContainmentObject; +import com.denizenscript.denizen.objects.EntityTag; +import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.NotedAreaTracker; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizencore.flags.AbstractFlagTracker; import com.denizenscript.denizencore.flags.FlaggableObject; @@ -13,6 +14,7 @@ import com.denizenscript.denizencore.objects.notable.NoteManager; import com.denizenscript.denizencore.scripts.ScriptEntryData; import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.debugging.Debug; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.event.Event; @@ -89,27 +91,29 @@ public ObjectTag getContext(String name) { return switch (name) { case "area" -> area; case "cause" -> { + String cause; if (currentEvent instanceof PlayerJoinEvent) { - yield new ElementTag("JOIN"); + cause = "JOIN"; } else if (currentEvent instanceof PlayerQuitEvent) { - yield new ElementTag("QUIT"); + cause = "QUIT"; } else if (currentEvent instanceof PlayerChangedWorldEvent) { - yield new ElementTag("WORLD_CHANGE"); + cause = "WORLD_CHANGE"; } else if (currentEvent instanceof PlayerTeleportEvent) { - yield new ElementTag("TELEPORT"); + cause = "TELEPORT"; } else if (currentEvent instanceof VehicleMoveEvent) { - yield new ElementTag("VEHICLE"); + cause = "VEHICLE"; } else if (currentEvent instanceof PlayerMoveEvent) { - yield new ElementTag("WALK"); + cause = "WALK"; } else { - yield new ElementTag("UNKNOWN"); + cause = "UNKNOWN"; } + yield new ElementTag(cause, true); } case "to" -> to != null ? new LocationTag(to) : null; case "from" -> { diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesBlockScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesBlockScriptEvent.java index d5c3d82ca1..93b1641206 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesBlockScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityChangesBlockScriptEvent.java @@ -42,8 +42,8 @@ public EntityChangesBlockScriptEvent() { public EntityTag entity; public LocationTag location; - public MaterialTag old_material; - public MaterialTag new_material; + public MaterialTag oldMaterial; + public MaterialTag newMaterial; public EntityChangeBlockEvent event; @Override @@ -52,7 +52,7 @@ public boolean matches(ScriptPath path) { if (!entity.tryAdvancedMatcher(entName, path.context)) { return false; } - if (!path.tryArgObject(2, old_material)) { + if (!path.tryArgObject(2, oldMaterial)) { return false; } if (path.eventArgLowerAt(3).equals("into")) { @@ -61,7 +61,7 @@ public boolean matches(ScriptPath path) { Debug.echoError("Invalid event material [" + getName() + "]: '" + path.event + "' for " + path.container.getName()); return false; } - else if (!new_material.tryAdvancedMatcher(mat2, path.context)) { + else if (!newMaterial.tryAdvancedMatcher(mat2, path.context)) { return false; } } @@ -81,8 +81,8 @@ public ObjectTag getContext(String name) { return switch (name) { case "entity" -> entity.getDenizenObject(); case "location" -> location; - case "new_material" -> new_material; - case "old_material" -> old_material; + case "new_material" -> newMaterial; + case "old_material" -> oldMaterial; default -> super.getContext(name); }; } @@ -91,8 +91,8 @@ public ObjectTag getContext(String name) { public void onEntityChangesBlock(EntityChangeBlockEvent event) { entity = new EntityTag(event.getEntity()); location = new LocationTag(event.getBlock().getLocation()); - old_material = new MaterialTag(location.getBlock()); - new_material = new MaterialTag(event.getTo()); + oldMaterial = new MaterialTag(location.getBlock()); + newMaterial = new MaterialTag(event.getTo()); this.event = event; fire(event); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCombustsScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCombustsScriptEvent.java index 3f7ec80d03..4813091b89 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCombustsScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCombustsScriptEvent.java @@ -84,11 +84,11 @@ public ObjectTag getContext(String name) { case "entity" -> entity.getDenizenObject(); case "duration" -> new DurationTag(event.getDuration()); case "source" -> { - if (event instanceof EntityCombustByEntityEvent byEntity) { - yield new EntityTag(byEntity.getCombuster()).getDenizenObject(); + if (event instanceof EntityCombustByEntityEvent byEntityEvent) { + yield new EntityTag(byEntityEvent.getCombuster()).getDenizenObject(); } - else if (event instanceof EntityCombustByBlockEvent byBlock) { - Block combuster = byBlock.getCombuster(); + else if (event instanceof EntityCombustByBlockEvent byBlockEvent) { + Block combuster = byBlockEvent.getCombuster(); if (combuster != null) { yield new LocationTag(combuster.getLocation()); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCreatePortalScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCreatePortalScriptEvent.java index f7b8026318..2a18c24c7c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCreatePortalScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityCreatePortalScriptEvent.java @@ -1,11 +1,11 @@ package com.denizenscript.denizen.events.entity; -import com.denizenscript.denizen.objects.EntityTag; -import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizen.events.BukkitScriptEvent; +import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.LocationTag; -import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; import org.bukkit.event.EventHandler; @@ -62,7 +62,7 @@ public ScriptEntryData getScriptEntryData() { public ObjectTag getContext(String name) { return switch (name) { case "entity" -> entity.getDenizenObject(); - case "portal_type" -> new ElementTag(event.getPortalType().toString()); + case "portal_type" -> new ElementTag(event.getPortalType()); case "blocks" -> new ListTag(event.getBlocks(), block -> new LocationTag(block.getLocation())); default -> super.getContext(name); }; diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySpawnScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySpawnScriptEvent.java index 31602998bf..6ca957840a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySpawnScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntitySpawnScriptEvent.java @@ -1,11 +1,11 @@ package com.denizenscript.denizen.events.entity; +import com.denizenscript.denizen.events.BukkitScriptEvent; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; -import com.denizenscript.denizen.events.BukkitScriptEvent; -import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; @@ -83,7 +83,7 @@ public ObjectTag getContext(String name) { case "entity" -> entity; case "location" -> location; case "reason" -> reason; - case "spawner_location" -> event instanceof SpawnerSpawnEvent spawner ? new LocationTag(spawner.getSpawner().getLocation()) : null; + case "spawner_location" -> event instanceof SpawnerSpawnEvent spawnerEvent ? new LocationTag(spawnerEvent.getSpawner().getLocation()) : null; default -> super.getContext(name); }; } @@ -93,8 +93,8 @@ public void onEntitySpawn(EntitySpawnEvent event) { Entity entity = event.getEntity(); this.entity = new EntityTag(entity); location = new LocationTag(event.getLocation()); - if (event instanceof CreatureSpawnEvent creatureSpawn) { - CreatureSpawnEvent.SpawnReason creatureReason = creatureSpawn.getSpawnReason(); + if (event instanceof CreatureSpawnEvent creatureSpawnEvent) { + CreatureSpawnEvent.SpawnReason creatureReason = creatureSpawnEvent.getSpawnReason(); if (creatureReason == CreatureSpawnEvent.SpawnReason.SPAWNER) { return; // Let the SpawnerSpawnEvent happen and handle it instead } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java index ac5ffe4a29..4ce44f74ab 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java @@ -3242,7 +3242,7 @@ else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && entity instanceo windCharge.explode(); } else { - mechanism.echoError("Cannot detonate entity of type '" + object.getBukkitEntityType().name() + "'."); + mechanism.echoError("Cannot detonate entity of type '" + object.getEntityType() + "'."); } }); From 64816783ff8370bd50b458e7b15770dc29f36222 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 24 Nov 2025 13:30:46 +0000 Subject: [PATCH 039/169] Minor cleanups to server links handling --- .../denizen/paper/PaperModule.java | 6 ++--- ...va => PlayerReceivesLinksScriptEvent.java} | 24 +++++++++---------- .../denizen/objects/PlayerTag.java | 2 +- .../denizen/tags/core/ServerTagBase.java | 2 +- .../denizen/utilities/Utilities.java | 10 ++++---- 5 files changed, 22 insertions(+), 22 deletions(-) rename paper/src/main/java/com/denizenscript/denizen/paper/events/{PlayerLinksSendScriptEvent.java => PlayerReceivesLinksScriptEvent.java} (67%) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index f83c2594e6..016e6b9694 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -66,9 +66,6 @@ public static void init() { ScriptEvent.registerScriptEvent(PlayerItemTakesDamageScriptEventPaperImpl.class); ScriptEvent.registerScriptEvent(PlayerJumpsScriptEventPaperImpl.class); ScriptEvent.registerScriptEvent(PlayerLecternPageChangeScriptEvent.class); - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { - ScriptEvent.registerScriptEvent(PlayerLinksSendScriptEvent.class); - } ScriptEvent.registerScriptEvent(PlayerLoomPatternSelectScriptEvent.class); ScriptEvent.registerScriptEvent(PlayerNameEntityScriptEvent.class); if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { @@ -79,6 +76,9 @@ public static void init() { if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_18)) { ScriptEvent.registerScriptEvent(PlayerRaiseLowerItemScriptEventPaperImpl.class); } + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + ScriptEvent.registerScriptEvent(PlayerReceivesLinksScriptEvent.class); + } ScriptEvent.registerScriptEvent(PlayerSelectsStonecutterRecipeScriptEvent.class); ScriptEvent.registerScriptEvent(PlayerSetSpawnScriptEvent.class); if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerLinksSendScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerReceivesLinksScriptEvent.java similarity index 67% rename from paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerLinksSendScriptEvent.java rename to paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerReceivesLinksScriptEvent.java index d05c079346..90bd7d51e8 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerLinksSendScriptEvent.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerReceivesLinksScriptEvent.java @@ -12,7 +12,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerLinksSendEvent; -public class PlayerLinksSendScriptEvent extends BukkitScriptEvent implements Listener { +public class PlayerReceivesLinksScriptEvent extends BukkitScriptEvent implements Listener { // <--[event] // @Events @@ -22,27 +22,27 @@ public class PlayerLinksSendScriptEvent extends BukkitScriptEvent implements Lis // // @Plugin Paper // - // @Triggers when a player receives a list of links + // @Triggers when a player receives a list of server links. // // @Determine // "LINKS:" to set the links sent to the player. Each item in the list must be a MapTag in <@link language Server Links Format>. - // "ADD_LINKS:" to add to the links sent to the player. Each item in the list must be a MapTag in <@link language Server Links Format>. + // "ADD_LINKS:" to send additional links to the player. Each item in the list must be a MapTag in <@link language Server Links Format>. // // @Player Always. // - // @Warning this may fire early in the player login process, during which the linked player is essentially an offline player + // @Warning this may fire early in the player login process, during which the linked player is essentially an offline player. // // --> public PlayerLinksSendEvent event; public PlayerTag player; - public PlayerLinksSendScriptEvent() { + public PlayerReceivesLinksScriptEvent() { registerCouldMatcher("player receives links"); - this.registerDetermination("links", ListTag.class, (evt, context, value) -> { + this.registerDetermination("links", ListTag.class, (evt, context, value) -> { Utilities.replaceServerLinks(evt.event.getLinks(), value, context); }); - this.registerDetermination("add_links", ListTag.class, (evt, context, value) -> { + this.registerDetermination("add_links", ListTag.class, (evt, context, value) -> { Utilities.fillServerLinks(evt.event.getLinks(), value, context); }); } @@ -54,14 +54,14 @@ public ScriptEntryData getScriptEntryData() { @EventHandler public void onPlayerLinksSend(PlayerLinksSendEvent event) { - if (event.getConnection() instanceof PlayerGameConnection connection) { - player = new PlayerTag(connection.getPlayer()); + if (event.getConnection() instanceof PlayerGameConnection gameConnection) { + player = new PlayerTag(gameConnection.getPlayer()); } - else if (event.getConnection() instanceof PlayerConfigurationConnection connection) { - player = new PlayerTag(connection.getProfile().getId()); + else if (event.getConnection() instanceof PlayerConfigurationConnection configConnection) { + player = new PlayerTag(configConnection.getProfile().getId()); } else { - player = null; + throw new IllegalStateException("Links send event fired with unknown connection type! " + event.getConnection() + " / " + event.getConnection().getClass().getName()); } this.event = event; fire(event); diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java index 39803af57d..0649efa9ed 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java @@ -2689,7 +2689,7 @@ else if (mechanism.requireObject(LocationTag.class)) { // @description // Sends the specified list of server links to the player. This will override existing links player has. // Each item in the list must be a MapTag in <@link language Server Links Format>. - // Generally prefer <@link mechanism PlayerTag.add_links> + // Generally prefer <@link mechanism PlayerTag.add_links>. // --> registerOnlineOnlyMechanism("links", ListTag.class, (player, mechanism, input) -> { player.getPlayerEntity().sendLinks(Utilities.replaceServerLinks(Bukkit.getServerLinks().copy(), input, mechanism.context)); diff --git a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java index 8055583ee4..cec4d36181 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java +++ b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java @@ -2033,7 +2033,7 @@ else if (nameLow.startsWith(matchInput) && (newMatch.isOnline() == matchPlayer.i // @input ListTag(MapTag) // @description // Sets the default server links. Each item in the list must be a MapTag in <@link language Server Links Format>. - // Generally prefer <@link mechanism server.add_links> + // Generally prefer <@link mechanism server.add_links>. // --> tagProcessor.registerMechanism("links", false, ListTag.class, (object, mechanism, input) -> { Utilities.replaceServerLinks(Bukkit.getServerLinks(), input, mechanism.context); diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java index 45606f2846..cfac76d3aa 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java @@ -655,10 +655,10 @@ public static boolean requireEnumlike(Mechanism mechanism, Class type) { // @group Minecraft Logic // @description // Server links are represented in Denizen as <@link ObjectType MapTag>s with the following keys: - // - link: The address of the link. - // - type: The type of the link. Valid types are listed at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/ServerLinks.Type.html> + // - link: The address of the link, required. + // And one of: + // - type: The type of the link, valid types are listed at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/ServerLinks.Type.html>. // - display: The display name of the link. - // When constructing this map, the "link" key is required. You can then optionally specify either the "type" or "display" key. // --> public static ServerLinks replaceServerLinks(ServerLinks serverLinks, ListTag list, TagContext context) { @@ -678,7 +678,7 @@ public static ServerLinks fillServerLinks(ServerLinks serverLinks, ListTag list, uri = new URI(strUri); } catch (URISyntaxException e) { - Debug.echoError("Invalid server links map '" + map + "': invalid 'link' key: " + strUri); + Debug.echoError("Invalid server links map '" + map + "': invalid 'link' value '" + strUri + "'."); continue; } if (map.containsKey("display")) { @@ -687,7 +687,7 @@ public static ServerLinks fillServerLinks(ServerLinks serverLinks, ListTag list, else if (map.containsKey("type")) { ServerLinks.Type type = map.getElement("type").asEnum(ServerLinks.Type.class); if (type == null) { - Debug.echoError("Invalid server links map '" + map + "': invalid 'type' key: " + map.getElement("type")); + Debug.echoError("Invalid server links map '" + map + "': invalid 'type' value '" + map.getElement("type") + "'."); continue; } serverLinks.addLink(type, uri); From 7b64f0d66be9eafbd2d0120a2a31422746d3780a Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Mon, 24 Nov 2025 06:18:00 -0800 Subject: [PATCH 040/169] `PlayerTag.bed_spawn`: 1.21 paper fix (#2794) --- .../denizen/nms/v1_21/helpers/PlayerHelperImpl.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java index 93f8d17add..c424ec7cbe 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java @@ -67,7 +67,6 @@ import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; import org.bukkit.craftbukkit.v1_21_R6.util.CraftMagicNumbers; import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; import org.bukkit.entity.Entity; @@ -432,10 +431,7 @@ public Location getBedSpawnLocation(Player player) { } LevelData.RespawnData nmsRespawnData = nmsRespawnConfig.respawnData(); Level nmsWorld = MinecraftServer.getServer().getLevel(nmsRespawnData.dimension()); - if (nmsWorld == null) { - return null; - } - return CraftLocation.toBukkit(nmsRespawnData.pos(), nmsWorld.getWorld(), nmsRespawnData.yaw(), nmsRespawnData.pitch()); + return nmsWorld != null ? new Location(nmsWorld.getWorld(), nmsRespawnData.pos().getX(), nmsRespawnData.pos().getY(), nmsRespawnData.pos().getZ(), nmsRespawnData.yaw(), nmsRespawnData.pitch()) : null; } @Override From df922b26b4dbf91eb1aad7375712778a90acf7f8 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:54:51 +0000 Subject: [PATCH 041/169] Fix offline player ender chest loading Reported at https://discord.com/channels/315163488085475337/1444338850825506998 --- .../denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java index af893053c8..9c1bff6525 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java @@ -105,9 +105,9 @@ public void setInventory(org.bukkit.inventory.PlayerInventory inventory) { @Override public Inventory getEnderChest() { if (enderchest == null) { - PlayerEnderChestContainer endchest = new PlayerEnderChestContainer(null); - Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> endchest.fromSlots(valueInput.listOrEmpty("EnderItems", ItemStackWithSlot.CODEC))); - enderchest = new CraftInventory(endchest); + PlayerEnderChestContainer nmsEnderChest = new PlayerEnderChestContainer(getFakeNmsPlayer()); + Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> nmsEnderChest.fromSlots(valueInput.listOrEmpty("EnderItems", ItemStackWithSlot.CODEC))); + enderchest = new CraftInventory(nmsEnderChest); } return enderchest; } From 9ac08f224f0eb3f3e211531a81691cc342ed88bd Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:08:50 +0000 Subject: [PATCH 042/169] 1.21.11 part 1: bump version numbers --- README.md | 2 +- paper/pom.xml | 2 +- plugin/pom.xml | 2 +- v1_21/pom.xml | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 79173dc00b..adf885b898 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, and 1.21.10! +**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, and 1.21.11! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html diff --git a/paper/pom.xml b/paper/pom.xml index 550955154c..a72fc09250 100644 --- a/paper/pom.xml +++ b/paper/pom.xml @@ -25,7 +25,7 @@ io.papermc.paper paper-api - 1.21.10-R0.1-SNAPSHOT + 1.21.11-R0.1-SNAPSHOT provided diff --git a/plugin/pom.xml b/plugin/pom.xml index fce192d44c..4b12edfaa7 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -30,7 +30,7 @@ org.spigotmc spigot-api - 1.21.10-R0.1-SNAPSHOT + 1.21.11-R0.1-SNAPSHOT jar provided diff --git a/v1_21/pom.xml b/v1_21/pom.xml index 0036775b50..8321e004ac 100644 --- a/v1_21/pom.xml +++ b/v1_21/pom.xml @@ -19,13 +19,13 @@ org.spigotmc spigot-api - 1.21.10-R0.1-SNAPSHOT + 1.21.11-R0.1-SNAPSHOT provided org.spigotmc spigot - 1.21.10-R0.1-SNAPSHOT + 1.21.11-R0.1-SNAPSHOT remapped-mojang provided @@ -45,9 +45,9 @@ remap-obf - org.spigotmc:minecraft-server:1.21.10-R0.1-SNAPSHOT:txt:maps-mojang + org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:txt:maps-mojang true - org.spigotmc:spigot:1.21.10-R0.1-SNAPSHOT:jar:remapped-mojang + org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT:jar:remapped-mojang true remapped-obf @@ -60,8 +60,8 @@ remap-spigot ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.21.10-R0.1-SNAPSHOT:csrg:maps-spigot - org.spigotmc:spigot:1.21.10-R0.1-SNAPSHOT:jar:remapped-obf + org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT:jar:remapped-obf From 443b8cadb5d6b7933ca3e1eca977cc62b21374a4 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:09:56 +0000 Subject: [PATCH 043/169] 1.21.11 part 2: bump import revision numbers --- .../denizen/nms/v1_21/Handler.java | 26 +++++++++---------- .../v1_21/helpers/AdvancementHelperImpl.java | 8 +++--- .../v1_21/helpers/AnimationHelperImpl.java | 6 ++--- .../nms/v1_21/helpers/BlockHelperImpl.java | 22 ++++++++-------- .../nms/v1_21/helpers/ChunkHelperImpl.java | 4 +-- .../v1_21/helpers/CustomEntityHelperImpl.java | 4 +-- .../nms/v1_21/helpers/EntityHelperImpl.java | 16 ++++++------ .../nms/v1_21/helpers/FishingHelperImpl.java | 8 +++--- .../nms/v1_21/helpers/ItemHelperImpl.java | 20 +++++++------- .../nms/v1_21/helpers/PacketHelperImpl.java | 16 ++++++------ .../nms/v1_21/helpers/PlayerHelperImpl.java | 16 ++++++------ .../nms/v1_21/helpers/WorldHelperImpl.java | 2 +- .../denizen/nms/v1_21/impl/BiomeNMSImpl.java | 8 +++--- .../v1_21/impl/ImprovedOfflinePlayerImpl.java | 8 +++--- .../nms/v1_21/impl/ProfileEditorImpl.java | 4 +-- .../nms/v1_21/impl/blocks/BlockLightImpl.java | 4 +-- .../impl/entities/CraftFakeArrowImpl.java | 4 +-- .../impl/entities/CraftFakePlayerImpl.java | 4 +-- .../entities/CraftItemProjectileImpl.java | 6 ++--- .../impl/entities/EntityFakeArrowImpl.java | 4 +-- .../impl/entities/EntityFakePlayerImpl.java | 2 +- .../handlers/AbstractListenerPlayInImpl.java | 2 +- .../handlers/DenizenNetworkManagerImpl.java | 6 ++--- .../handlers/DenizenPacketListenerImpl.java | 2 +- .../network/handlers/FakeBlockHelper.java | 8 +++--- .../packet/ActionBarEventPacketHandlers.java | 2 +- .../handlers/packet/AttachPacketHandlers.java | 4 +-- .../packet/DisguisePacketHandlers.java | 2 +- .../packet/FakeEquipmentPacketHandlers.java | 2 +- .../packet/HideParticlesPacketHandlers.java | 2 +- .../network/packets/PacketOutChatImpl.java | 2 +- 31 files changed, 112 insertions(+), 112 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java index 5266fc39f4..43d3061660 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java @@ -67,19 +67,19 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.boss.BossBar; -import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R6.boss.CraftBossBar; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventory; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventoryCustom; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventoryView; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R6.legacy.FieldRename; -import org.bukkit.craftbukkit.v1_21_R6.persistence.CraftPersistentDataContainer; -import org.bukkit.craftbukkit.v1_21_R6.util.*; +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; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java index f67b11f035..a7da1418d6 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java @@ -14,10 +14,10 @@ import net.minecraft.server.ServerAdvancementManager; import net.minecraft.server.level.ServerPlayer; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; +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.*; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AnimationHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AnimationHelperImpl.java index 58f94499b8..b000df11bc 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AnimationHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AnimationHelperImpl.java @@ -2,9 +2,9 @@ import com.denizenscript.denizen.nms.abstracts.AnimationHelper; import net.minecraft.world.entity.Entity; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftHorse; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPolarBear; +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; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java index 880b123dfd..8a8b9188c9 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/BlockHelperImpl.java @@ -34,17 +34,17 @@ import org.bukkit.block.Block; import org.bukkit.block.CreatureSpawner; import org.bukkit.block.Skull; -import org.bukkit.craftbukkit.v1_21_R6.CraftChunk; -import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlock; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlockEntityState; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftSkull; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftMagicNumbers; +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; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ChunkHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ChunkHelperImpl.java index 974ab21f15..4157cf2074 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ChunkHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ChunkHelperImpl.java @@ -20,8 +20,8 @@ import net.minecraft.world.level.levelgen.Heightmap; import org.bukkit.Chunk; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R6.CraftChunk; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +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; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/CustomEntityHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/CustomEntityHelperImpl.java index f5cb6d5eec..0df283220e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/CustomEntityHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/CustomEntityHelperImpl.java @@ -20,8 +20,8 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +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; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java index 38e84804bc..7dac620d1e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java @@ -67,14 +67,14 @@ import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.CreatureSpawner; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlock; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R6.entity.*; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; +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; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/FishingHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/FishingHelperImpl.java index 531f56e824..a6cd25a56c 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/FishingHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/FishingHelperImpl.java @@ -18,10 +18,10 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftFishHook; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftFishHook; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; import org.bukkit.entity.FishHook; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java index 7b7e675059..002eab2868 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java @@ -70,16 +70,16 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntityType; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R6.inventory.*; -import org.bukkit.craftbukkit.v1_21_R6.map.CraftMapView; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftMagicNumbers; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; +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.entity.CraftEntityType; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R7.inventory.*; +import org.bukkit.craftbukkit.v1_21_R7.map.CraftMapView; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.*; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java index 0c6ddcd2b1..04d3898e2f 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java @@ -49,14 +49,14 @@ import org.bukkit.block.Sign; import org.bukkit.block.sign.Side; import org.bukkit.block.sign.SignSide; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R6.map.CraftMapCanvas; -import org.bukkit.craftbukkit.v1_21_R6.map.CraftMapView; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +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.map.CraftMapCanvas; +import org.bukkit.craftbukkit.v1_21_R7.map.CraftMapView; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java index c424ec7cbe..6632c401c1 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java @@ -61,14 +61,14 @@ import net.minecraft.world.phys.AABB; import org.bukkit.*; import org.bukkit.boss.BossBar; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.boss.CraftBossBar; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftMagicNumbers; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.boss.CraftBossBar; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +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.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java index 89c53a537c..994a9b71b4 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java @@ -16,7 +16,7 @@ import net.minecraft.world.level.storage.PrimaryLevelData; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; public class WorldHelperImpl implements WorldHelper { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java index 24f6662195..33315029e8 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java @@ -22,10 +22,10 @@ import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.block.Block; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntityType; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntityType; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; import org.bukkit.entity.EntityType; import java.lang.invoke.MethodHandle; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java index 9c1bff6525..7a33a97f69 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ImprovedOfflinePlayerImpl.java @@ -24,10 +24,10 @@ import net.minecraft.world.level.storage.ValueOutput; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventory; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventoryPlayer; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventoryPlayer; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java index 8507338e11..196c039c05 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java @@ -25,8 +25,8 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerRespawnEvent; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/blocks/BlockLightImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/blocks/BlockLightImpl.java index cb8ecd0997..78c81da8e2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/blocks/BlockLightImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/blocks/BlockLightImpl.java @@ -21,8 +21,8 @@ import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R6.CraftChunk; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlock; +import org.bukkit.craftbukkit.v1_21_R7.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlock; import org.bukkit.util.Vector; import java.lang.invoke.MethodHandle; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java index 41e5f37402..1bc426b044 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java @@ -2,8 +2,8 @@ import com.denizenscript.denizen.nms.interfaces.FakeArrow; import net.minecraft.world.entity.projectile.AbstractArrow; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftAbstractArrow; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftAbstractArrow; public class CraftFakeArrowImpl extends CraftAbstractArrow implements FakeArrow { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakePlayerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakePlayerImpl.java index 3d1687b869..92a5ac8942 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakePlayerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakePlayerImpl.java @@ -4,8 +4,8 @@ import com.denizenscript.denizen.nms.NMSHandler; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftItemProjectileImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftItemProjectileImpl.java index 3504f71463..a2b8de7f84 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftItemProjectileImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftItemProjectileImpl.java @@ -3,9 +3,9 @@ import com.denizenscript.denizen.nms.interfaces.ItemProjectile; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java index f701bb0f71..77beee2417 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java @@ -7,8 +7,8 @@ import net.minecraft.world.item.Items; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; import org.bukkit.event.entity.CreatureSpawnEvent; public class EntityFakeArrowImpl extends SpectralArrow { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakePlayerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakePlayerImpl.java index b0f61cf1ef..9c64a6636b 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakePlayerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakePlayerImpl.java @@ -14,7 +14,7 @@ import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.world.entity.player.Player; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R6.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; import org.bukkit.event.entity.CreatureSpawnEvent; public class EntityFakePlayerImpl extends ServerPlayer { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java index e6d56fbac7..d67b131ff5 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/AbstractListenerPlayInImpl.java @@ -31,7 +31,7 @@ import net.minecraft.world.entity.Relative; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; import org.bukkit.event.player.PlayerTeleportEvent; import java.lang.invoke.MethodHandle; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java index f1d556d7ae..d725381ce0 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -32,9 +32,9 @@ import net.minecraft.util.debugchart.LocalSampleLogger; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; import org.bukkit.entity.Player; import javax.annotation.Nullable; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenPacketListenerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenPacketListenerImpl.java index 7984075272..ed03d1ee48 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenPacketListenerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenPacketListenerImpl.java @@ -17,7 +17,7 @@ import net.minecraft.network.protocol.game.*; import net.minecraft.server.level.ServerPlayer; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlock; +import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlock; import org.bukkit.event.block.SignChangeEvent; public class DenizenPacketListenerImpl extends AbstractListenerPlayInImpl { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index dfe309b3db..13ca382b8b 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -24,10 +24,10 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.Strategy; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R6.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlockStates; -import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockStates; +import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData; import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java index 2726aed312..62ad8bd09b 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java @@ -8,7 +8,7 @@ import com.denizenscript.denizencore.objects.core.ElementTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftChatMessage; public class ActionBarEventPacketHandlers { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/AttachPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/AttachPacketHandlers.java index 9090cd17fa..7219ee9108 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/AttachPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/AttachPacketHandlers.java @@ -13,8 +13,8 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PositionMoveRotation; import net.minecraft.world.phys.Vec3; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftVector; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftVector; import org.bukkit.util.Vector; import java.lang.reflect.Field; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DisguisePacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DisguisePacketHandlers.java index 5c3cd767b4..a15b517fb5 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DisguisePacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DisguisePacketHandlers.java @@ -14,7 +14,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PositionMoveRotation; import net.minecraft.world.level.Level; -import org.bukkit.craftbukkit.v1_21_R6.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java index 8ec2e35795..ab05832bd4 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java @@ -12,7 +12,7 @@ import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; -import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; import java.util.ArrayList; import java.util.List; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/HideParticlesPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/HideParticlesPacketHandlers.java index 4e2109ee9d..09328473fc 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/HideParticlesPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/HideParticlesPacketHandlers.java @@ -4,7 +4,7 @@ import com.denizenscript.denizen.utilities.packets.HideParticles; import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; import org.bukkit.Particle; -import org.bukkit.craftbukkit.v1_21_R6.CraftParticle; +import org.bukkit.craftbukkit.v1_21_R7.CraftParticle; import java.util.Set; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java index e3f8e6444a..13d5d02757 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java @@ -5,7 +5,7 @@ import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftChatMessage; public class PacketOutChatImpl extends PacketOutChat { From cede8b0d621115012f55f792065221cf0314824b Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:11:36 +0000 Subject: [PATCH 044/169] 1.21.11 part 3: update reflection mappings --- .../nms/v1_21/ReflectionMappingsInfo.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index f4839e4a5b..e8391b5089 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -17,21 +17,21 @@ public class ReflectionMappingsInfo { public static String Entity_DATA_CUSTOM_NAME_VISIBLE = "bn"; // net.minecraft.world.entity.LivingEntity - public static String LivingEntity_attackStrengthTicker = "by"; - public static String LivingEntity_autoSpinAttackTicks = "bV"; + 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 = "dq"; + public static String ServerPlayer_respawnConfig = "dr"; // net.minecraft.world.entity.monster.EnderMan - public static String EnderMan_DATA_CREEPY = "cu"; + public static String EnderMan_DATA_CREEPY = "cx"; // net.minecraft.world.entity.monster.Zombie - public static String Zombie_inWaterTime = "cJ"; + public static String Zombie_inWaterTime = ERROR_UNKNOWN_TARGET; // net.minecraft.world.item.Item public static String Item_components = "c"; @@ -43,7 +43,7 @@ public class ReflectionMappingsInfo { public static String ResolvableProfilePartial_id = "d"; // net.minecraft.world.level.Level - public static String Level_isClientSide = "E"; + public static String Level_isClientSide = "D"; // net.minecraft.server.level.ThreadedLevelLightEngine public static String ThreadedLevelLightEngine_addTask_method = "a"; @@ -61,20 +61,20 @@ public class ReflectionMappingsInfo { public static String Biome_climateSettings = "i"; // net.minecraft.world.level.biome.BiomeSpecialEffects - public static String BiomeSpecialEffects_foliageColorOverride = "f"; - public static String BiomeSpecialEffects_fogColor = "b"; - public static String BiomeSpecialEffects_waterFogColor = "d"; + public static String BiomeSpecialEffects_foliageColorOverride = "c"; + public static String BiomeSpecialEffects_fogColor = ERROR_UNKNOWN_TARGET; + public static String BiomeSpecialEffects_waterFogColor = ERROR_UNKNOWN_TARGET; // net.minecraft.network.Connection - public static String Connection_receiving = "k"; - public static String Connection_packetListener = "q"; + public static String Connection_receiving = "h"; + public static String Connection_packetListener = "n"; // net.minecraft.server.network.ServerGamePacketListenerImpl - public static String ServerGamePacketListenerImpl_aboveGroundTickCount = "J"; - public static String ServerGamePacketListenerImpl_aboveGroundVehicleTickCount = "L"; - public static String ServerGamePacketListenerImpl_awaitingPositionFromClient = "F"; - public static String ServerGamePacketListenerImpl_awaitingTeleport = "G"; - public static String ServerGamePacketListenerImpl_chunkSender = "g"; + 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"; From 70b2d5c6fc6a8a589c2bd18a5fb2b145e34c9c62 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:13:08 +0000 Subject: [PATCH 045/169] 1.21.11 part 4: update mappings check --- .../main/java/com/denizenscript/denizen/nms/v1_21/Handler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java index 43d3061660..668991451a 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java @@ -150,7 +150,7 @@ public void undisableAsyncCatcher() { @Override public boolean isExactServerVersionMatch() { - return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("1.21.10") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("614efe5192cd0510bc2ddc5feefa155d"); + return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("1.21.11") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e3cd927e07e6ff434793a0474c51b2b9"); } @Override From 22e543ddd6126e7619ed1ceba9b929e9340b16e7 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 10 Dec 2025 03:54:20 +0000 Subject: [PATCH 046/169] 1.21.11 part 5: initial code updates --- .../WorldGameRuleChangeScriptEvent.java | 5 +- .../denizen/objects/WorldTag.java | 21 +++--- .../commands/world/GameRuleCommand.java | 48 ++++++++++--- .../denizen/tags/core/ServerTagBase.java | 7 +- .../utilities/world/GameRuleReflect.java | 67 +++++++++++++++++++ .../denizen/nms/v1_21/Handler.java | 6 +- .../nms/v1_21/ReflectionMappingsInfo.java | 7 +- .../v1_21/helpers/AdvancementHelperImpl.java | 16 ++--- .../v1_21/helpers/EntityDataNameMapper.java | 56 ++++++++++++---- .../nms/v1_21/helpers/EntityHelperImpl.java | 4 +- .../nms/v1_21/helpers/ItemHelperImpl.java | 10 +-- .../nms/v1_21/helpers/PacketHelperImpl.java | 4 +- .../nms/v1_21/helpers/PlayerHelperImpl.java | 8 +-- .../nms/v1_21/helpers/WorldHelperImpl.java | 2 +- .../denizen/nms/v1_21/impl/BiomeNMSImpl.java | 28 ++++++-- .../impl/entities/CraftFakeArrowImpl.java | 2 +- .../impl/entities/EntityFakeArrowImpl.java | 2 +- 17 files changed, 220 insertions(+), 73 deletions(-) create mode 100644 plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/WorldGameRuleChangeScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/WorldGameRuleChangeScriptEvent.java index faf88722fd..64fc3dbe05 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/WorldGameRuleChangeScriptEvent.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/WorldGameRuleChangeScriptEvent.java @@ -7,6 +7,7 @@ import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.objects.WorldTag; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; +import com.denizenscript.denizen.utilities.world.GameRuleReflect; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; @@ -69,7 +70,7 @@ public boolean matches(ScriptPath path) { if (path.eventArgLowerAt(2).equals("in") && !path.tryArgObject(3, world)) { return false; } - if (!runGenericSwitchCheck(path, "gamerule", event.getGameRule().getName())) { + if (!runGenericSwitchCheck(path, "gamerule", GameRuleReflect.getName(event.getGameRule()))) { return false; } return super.matches(path); @@ -78,7 +79,7 @@ public boolean matches(ScriptPath path) { @Override public ObjectTag getContext(String name) { return switch (name) { - case "gamerule" -> new ElementTag(event.getGameRule().getName(), true); + case "gamerule" -> new ElementTag(GameRuleReflect.getName(event.getGameRule()), true); case "value" -> new ElementTag(event.getValue(), true); case "source_type" -> getSourceType(); case "command_block_location" -> getCommandBlock(); diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java index 1106a9a84c..46a07a49e3 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java @@ -6,6 +6,7 @@ import com.denizenscript.denizen.nms.abstracts.BiomeNMS; import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizen.utilities.flags.WorldFlagHandler; +import com.denizenscript.denizen.utilities.world.GameRuleReflect; import com.denizenscript.denizencore.flags.AbstractFlagTracker; import com.denizenscript.denizencore.flags.FlaggableObject; import com.denizenscript.denizencore.objects.Adjustable; @@ -177,7 +178,7 @@ public T getGameRuleOrDefault(GameRule gameRule) { if (value == null) { value = world.getGameRuleDefault(gameRule); if (value == null) { - throw new IllegalStateException("World " + world_name + " contains no GameRule " + gameRule.getName()); + throw new IllegalStateException("World " + world_name + " contains no GameRule " + GameRuleReflect.getName(gameRule)); } } return value; @@ -859,9 +860,13 @@ else if (time >= 12500) { attribute.echoError("The tag 'worldtag.gamerule[...]' must have an input value."); return null; } - GameRule rule = GameRule.getByName(attribute.getParam()); - Object result = object.getWorld().getGameRuleValue(rule); - return new ElementTag(result == null ? "null" : result.toString()); + GameRule rule = GameRuleReflect.getByName(attribute.getParam()); + if (rule == null) { + attribute.echoError("Invalid game rule specified: " + attribute.getParam() + '.'); + return null; + } + Object result = GameRuleReflect.getValue(object.getWorld(), rule); + return new ElementTag(String.valueOf(result), true); }); // <--[tag] @@ -872,10 +877,10 @@ else if (time >= 12500) { // --> registerTag(MapTag.class, "gamerule_map", (attribute, object) -> { MapTag map = new MapTag(); - for (GameRule rule : GameRule.values()) { - Object result = object.getWorld().getGameRuleValue(rule); + for (GameRule rule : GameRuleReflect.values()) { + Object result = GameRuleReflect.getValue(object.getWorld(), rule); if (result != null) { - map.putObject(rule.getName(), new ElementTag(result.toString())); + map.putObject(GameRuleReflect.getName(rule), new ElementTag(result.toString(), true)); } } return map; @@ -1525,7 +1530,7 @@ else if (time >= 12500) { NMSHandler.worldHelper.wakeUpAllPlayers(world); } // minor change: prior to 1.18, hasStorm/isRaining was not checked - if (object.getGameRuleOrDefault(GameRule.DO_WEATHER_CYCLE) && world.hasStorm()) { + if (object.getGameRuleOrDefault(GameRuleReflect.WEATHER_CYCLE_GAMERULE) && world.hasStorm()) { NMSHandler.worldHelper.clearWeather(world); } }); diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/GameRuleCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/GameRuleCommand.java index 4a2e65b188..06387e6295 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/GameRuleCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/GameRuleCommand.java @@ -1,17 +1,18 @@ package com.denizenscript.denizen.scripts.commands.world; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizen.objects.WorldTag; +import com.denizenscript.denizen.utilities.world.GameRuleReflect; import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; import com.denizenscript.denizencore.objects.Argument; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.commands.AbstractCommand; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.denizenscript.denizencore.utilities.debugging.DebugInternals; import org.bukkit.Bukkit; +import org.bukkit.GameRule; import org.bukkit.generator.WorldInfo; -import java.util.stream.Collectors; - public class GameRuleCommand extends AbstractCommand { public GameRuleCommand() { @@ -45,10 +46,14 @@ public GameRuleCommand() { // - gamerule Adventure mobGriefing false // --> + + @Override public void addCustomTabCompletions(TabCompletionsBuilder tab) { - tab.add(Bukkit.getWorlds().get(0).getGameRules()); - tab.add(Bukkit.getWorlds().stream().map(WorldInfo::getName).collect(Collectors.toSet())); + for (GameRule gameRule : GameRuleReflect.values()) { + tab.add(GameRuleReflect.getName(gameRule)); + } + tab.add(Bukkit.getWorlds().stream().map(WorldInfo::getName).toList()); } @Override @@ -82,12 +87,37 @@ else if (!scriptEntry.hasObject("value")) { @Override public void execute(ScriptEntry scriptEntry) { WorldTag world = scriptEntry.getObjectTag("world"); - ElementTag gamerule = scriptEntry.getElement("gamerule"); - ElementTag value = scriptEntry.getElement("value"); + ElementTag gameRuleInput = scriptEntry.getElement("gamerule"); + ElementTag valueInput = scriptEntry.getElement("value"); if (scriptEntry.dbCallShouldDebug()) { - Debug.report(scriptEntry, getName(), world, gamerule, value); + Debug.report(scriptEntry, getName(), world, gameRuleInput, valueInput); + } + GameRule gameRule = GameRuleReflect.getByName(gameRuleInput.asString()); + if (gameRule == null) { + Debug.echoError("Invalid game rule specified: " + gameRuleInput.asString() + '.'); + return; + } + Class gameRuleType = GameRuleReflect.getType(gameRule); + Object convertedValue; + if (gameRuleType == Integer.class) { + if (!valueInput.isInt()) { + Debug.echoError("Invalid value specified: must be a number."); + return; + } + convertedValue = valueInput.asInt(); + } + else if (gameRuleType == Boolean.class) { + if (!valueInput.isBoolean()) { + Debug.echoError("Invalid value specified: must be a boolean."); + return; + } + convertedValue = valueInput.asBoolean(); + } + else { + Debug.echoError("Unrecognized game rule type '" + DebugInternals.getFullClassNameOpti(gameRuleType) + "'! Please report this to the developers."); + return; } - if (!world.getWorld().setGameRuleValue(gamerule.asString(), value.asString())) { + if (!world.getWorld().setGameRule(gameRule, convertedValue)) { Debug.echoError(scriptEntry, "Invalid gamerule!"); } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java index cec4d36181..9ce0637474 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java +++ b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java @@ -14,6 +14,7 @@ import com.denizenscript.denizen.utilities.*; import com.denizenscript.denizen.utilities.depends.Depends; import com.denizenscript.denizen.utilities.inventory.SlotHelper; +import com.denizenscript.denizen.utilities.world.GameRuleReflect; import com.denizenscript.denizencore.DenizenCore; import com.denizenscript.denizencore.events.ScriptEvent; import com.denizenscript.denizencore.objects.Mechanism; @@ -639,11 +640,7 @@ else if (param.shouldBeType(EntityTag.class)) { // Returns a list of all available gamerules on the server. // --> tagProcessor.registerStaticTag(ListTag.class, "gamerules", (attribute, object) -> { - ListTag gamerules = new ListTag(); - for (GameRule rule : GameRule.values()) { - gamerules.add(rule.getName()); - } - return gamerules; + return new ListTag(Arrays.asList(GameRuleReflect.values()), gameRule -> new ElementTag(GameRuleReflect.getName(gameRule), true)); }); // <--[tag] diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java new file mode 100644 index 0000000000..c8dcb77109 --- /dev/null +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java @@ -0,0 +1,67 @@ +package com.denizenscript.denizen.utilities.world; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import org.bukkit.GameRule; +import org.bukkit.World; + +import java.lang.invoke.MethodHandle; + +public class GameRuleReflect { + + private static final MethodHandle GAMERULE_VALUES = ReflectionHelper.getMethodHandle(GameRule.class, "values"); + private static final MethodHandle GAMERULE_GET_BY_NAME = ReflectionHelper.getMethodHandle(GameRule.class, "getByName", String.class); + private static final MethodHandle GAMERULE_GET_NAME = ReflectionHelper.getMethodHandle(GameRule.class, "getName"); + private static final MethodHandle GAMERULE_GET_TYPE = ReflectionHelper.getMethodHandle(GameRule.class, "getType"); + + public static final GameRule WEATHER_CYCLE_GAMERULE = NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) ? GameRule.ADVANCE_WEATHER : (GameRule) getByName("doWeatherCycle"); + + public static GameRule[] values() { + try { + return (GameRule[]) GAMERULE_VALUES.invokeExact(); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public static GameRule getByName(String name) { + try { + return (GameRule) GAMERULE_GET_BY_NAME.invokeExact(name); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public static String getName(GameRule gameRule) { + try { + return (String) GAMERULE_GET_NAME.invokeExact(gameRule); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public static Class getType(GameRule gameRule) { + try { + return (Class) GAMERULE_GET_TYPE.invokeExact(gameRule); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public static T getValue(World world, GameRule gameRule) { + try { + return world.getGameRuleValue(gameRule); + } + catch (IllegalArgumentException e) { + if (e.getMessage().equals("Tried to access invalid game rule")) { + return null; + } + throw e; + } + } +} diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java index 668991451a..01ffc5fac9 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java @@ -45,7 +45,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.StringTag; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.ProblemReporter; @@ -294,7 +294,7 @@ public ProfileEditor getProfileEditor() { public List getBiomes(World world) { ServerLevel level = ((CraftWorld) world).getHandle(); ArrayList output = new ArrayList<>(); - for (ResourceLocation key : level.registryAccess().lookupOrThrow(Registries.BIOME).keySet()) { + for (Identifier key : level.registryAccess().lookupOrThrow(Registries.BIOME).keySet()) { output.add(new BiomeNMSImpl(level, CraftNamespacedKey.fromMinecraft(key))); } return output; @@ -314,7 +314,7 @@ 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); - ResourceLocation key = level.registryAccess().lookupOrThrow(Registries.BIOME).getKey(biome.value()); + Identifier key = level.registryAccess().lookupOrThrow(Registries.BIOME).getKey(biome.value()); return new BiomeNMSImpl(level, CraftNamespacedKey.fromMinecraft(key)); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index e8391b5089..905e259d71 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -30,8 +30,8 @@ public class ReflectionMappingsInfo { // net.minecraft.world.entity.monster.EnderMan public static String EnderMan_DATA_CREEPY = "cx"; - // net.minecraft.world.entity.monster.Zombie - public static String Zombie_inWaterTime = ERROR_UNKNOWN_TARGET; + // net.minecraft.world.entity.monster.zombie.Zombie + public static String Zombie_inWaterTime = "cL"; // net.minecraft.world.item.Item public static String Item_components = "c"; @@ -59,11 +59,10 @@ public class ReflectionMappingsInfo { // net.minecraft.world.level.biome.Biome public static String Biome_climateSettings = "i"; + public static String Biome_attributes = "l"; // net.minecraft.world.level.biome.BiomeSpecialEffects public static String BiomeSpecialEffects_foliageColorOverride = "c"; - public static String BiomeSpecialEffects_fogColor = ERROR_UNKNOWN_TARGET; - public static String BiomeSpecialEffects_waterFogColor = ERROR_UNKNOWN_TARGET; // net.minecraft.network.Connection public static String Connection_receiving = "h"; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java index a7da1418d6..1c9d91c52c 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java @@ -6,10 +6,10 @@ import com.google.common.collect.ImmutableMap; import net.md_5.bungee.api.ChatColor; import net.minecraft.advancements.*; -import net.minecraft.advancements.critereon.ImpossibleTrigger; +import net.minecraft.advancements.criterion.ImpossibleTrigger; import net.minecraft.core.ClientAsset; import net.minecraft.network.protocol.game.ClientboundUpdateAdvancementsPacket; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.PlayerAdvancements; import net.minecraft.server.ServerAdvancementManager; import net.minecraft.server.level.ServerPlayer; @@ -38,8 +38,8 @@ public void register(com.denizenscript.denizen.nms.util.Advancement advancement) return; } AdvancementHolder nmsAdvancementHolder = asNMSCopy(advancement); - Map nmsAdvancements = getNMSAdvancementManager().advancements; - ImmutableMap.Builder mapBuilder = ImmutableMap.builderWithExpectedSize(nmsAdvancements.size() + 1); + Map nmsAdvancements = getNMSAdvancementManager().advancements; + ImmutableMap.Builder mapBuilder = ImmutableMap.builderWithExpectedSize(nmsAdvancements.size() + 1); mapBuilder.putAll(nmsAdvancements); mapBuilder.put(nmsAdvancementHolder.id(), nmsAdvancementHolder); getNMSAdvancementManager().advancements = mapBuilder.build(); @@ -65,10 +65,10 @@ public void unregister(com.denizenscript.denizen.nms.util.Advancement advancemen if (advancement.temporary || !advancement.registered) { return; } - ResourceLocation nmsKey = CraftNamespacedKey.toMinecraft(advancement.key); - Map nmsAdvancements = getNMSAdvancementManager().advancements; - ImmutableMap.Builder mapBuilder = ImmutableMap.builderWithExpectedSize(nmsAdvancements.size() - 1); - for (Map.Entry entry : nmsAdvancements.entrySet()) { + 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); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityDataNameMapper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityDataNameMapper.java index f55647bb01..01b43c07ca 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityDataNameMapper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityDataNameMapper.java @@ -5,39 +5,69 @@ 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.*; 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.horse.AbstractChestedHorse; -import net.minecraft.world.entity.animal.horse.AbstractHorse; -import net.minecraft.world.entity.animal.horse.Horse; -import net.minecraft.world.entity.animal.horse.Llama; +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; +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.npc.AbstractVillager; -import net.minecraft.world.entity.npc.Villager; +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.*; +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.AbstractMinecart; -import net.minecraft.world.entity.vehicle.Boat; -import net.minecraft.world.entity.vehicle.MinecartCommandBlock; -import net.minecraft.world.entity.vehicle.MinecartFurnace; +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; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java index 7dac620d1e..8899ea0572 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java @@ -685,7 +685,7 @@ public EntityTag getMobSpawnerDisplayEntity(CreatureSpawner spawner) { return new EntityTag(nmsEntity.getBukkitEntity()); } - public static final Field ZOMBIE_INWATERTIME = ReflectionHelper.getFields(net.minecraft.world.entity.monster.Zombie.class).get(ReflectionMappingsInfo.Zombie_inWaterTime, int.class); + 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) { @@ -821,7 +821,7 @@ public void stopUsingItem(LivingEntity entity) { @Override public void openHorseInventory(Player player, AbstractHorse horse) { - net.minecraft.world.entity.animal.horse.AbstractHorse nmsHorse = ((CraftAbstractHorse) horse).getHandle(); + net.minecraft.world.entity.animal.equine.AbstractHorse nmsHorse = ((CraftAbstractHorse) horse).getHandle(); ((CraftPlayer) player).getHandle().openHorseInventory(nmsHorse, nmsHorse.inventory); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java index 002eab2868..86b815add7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java @@ -24,8 +24,8 @@ import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.md_5.bungee.api.ChatColor; -import net.minecraft.advancements.critereon.BlockPredicate; -import net.minecraft.advancements.critereon.DataComponentMatchers; +import net.minecraft.advancements.criterion.BlockPredicate; +import net.minecraft.advancements.criterion.DataComponentMatchers; import net.minecraft.core.*; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentPatch; @@ -36,9 +36,9 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.flag.FeatureFlagSet; @@ -202,7 +202,7 @@ public static Ingredient itemArrayToRecipe(ItemStack[] items, boolean exact) { } public static ResourceKey> createRecipeKey(String name) { - return ResourceKey.create(Registries.RECIPE, ResourceLocation.fromNamespaceAndPath("denizen", name)); + return ResourceKey.create(Registries.RECIPE, Identifier.fromNamespaceAndPath("denizen", name)); } @Override @@ -443,7 +443,7 @@ public MapTag getRawComponentsPatch(ItemStack item, boolean excludeHandled) { DataComponentPatch patch = nmsItemStack.getComponentsPatch(); if (excludeHandled) { patch = patch.forget(componentType -> { - ResourceLocation componentId = BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(componentType); + Identifier componentId = BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(componentType); return ItemComponentsPatch.propertyHandledComponents.contains(componentId.toString()); }); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java index 04d3898e2f..91c60ce77e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java @@ -32,10 +32,10 @@ import net.minecraft.world.entity.Relative; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.monster.CaveSpider; +import net.minecraft.world.entity.monster.spider.CaveSpider; import net.minecraft.world.entity.monster.Creeper; import net.minecraft.world.entity.monster.EnderMan; -import net.minecraft.world.entity.monster.Spider; +import net.minecraft.world.entity.monster.spider.Spider; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java index 6632c401c1..8493e40ade 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java @@ -32,7 +32,7 @@ import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; import net.minecraft.network.protocol.game.*; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerEntity; @@ -339,7 +339,7 @@ public void setTemporaryOp(Player player, boolean op) { NameAndId nameAndId = new NameAndId(((CraftPlayer) player).getProfile()); ServerOpList opList = server.getPlayerList().getOps(); if (op) { - opList.add(new ServerOpListEntry(nameAndId, server.operatorUserPermissionLevel(), opList.canBypassPlayerLimit(nameAndId))); + opList.add(new ServerOpListEntry(nameAndId, server.operatorUserPermissions(), opList.canBypassPlayerLimit(nameAndId))); } else { opList.remove(nameAndId); @@ -465,7 +465,7 @@ public void sendPlayerInfoRemovePacket(Player player, UUID id) { @Override public void sendClimbableMaterials(Player player, List materials) { Map>, TagNetworkSerialization.NetworkPayload> packetInput = TagNetworkSerialization.serializeTagsToNetwork(((CraftServer) Bukkit.getServer()).getServer().registries()); - Map tags = ReflectionHelper.getFieldValue(TagNetworkSerialization.NetworkPayload.class, ReflectionMappingsInfo.TagNetworkSerializationNetworkPayload_tags, packetInput.get(BuiltInRegistries.BLOCK.key())); + Map tags = ReflectionHelper.getFieldValue(TagNetworkSerialization.NetworkPayload.class, ReflectionMappingsInfo.TagNetworkSerializationNetworkPayload_tags, packetInput.get(BuiltInRegistries.BLOCK.key())); IntList climbableBlocks = tags.get(BlockTags.CLIMBABLE.location()); climbableBlocks.clear(); for (Material material : materials) { @@ -492,7 +492,7 @@ public void refreshPlayer(Player player) { } if (!nmsPlayer.getCooldowns().cooldowns.isEmpty()) { int tickCount = nmsPlayer.getCooldowns().tickCount; - for (Map.Entry entry : nmsPlayer.getCooldowns().cooldowns.entrySet()) { + for (Map.Entry entry : nmsPlayer.getCooldowns().cooldowns.entrySet()) { nmsPlayer.connection.send(new ClientboundCooldownPacket(entry.getKey(), entry.getValue().endTime - tickCount)); } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java index 994a9b71b4..75f6c9ded5 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java @@ -98,7 +98,7 @@ public void wakeUpAllPlayers(World world) { // net.minecraft.server.level.ServerLevel#resetWeatherCycle() @Override public void clearWeather(World world) { - PrimaryLevelData data = ((CraftWorld) world).getHandle().J; + PrimaryLevelData data = ((CraftWorld) world).getHandle().I; data.setRaining(false); if (!data.isRaining()) { data.setRainTime(0); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java index 33315029e8..73870f8afd 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java @@ -14,6 +14,9 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.random.Weighted; import net.minecraft.util.random.WeightedList; +import net.minecraft.world.attribute.EnvironmentAttribute; +import net.minecraft.world.attribute.EnvironmentAttributeMap; +import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSpecialEffects; @@ -38,6 +41,7 @@ public class BiomeNMSImpl extends BiomeNMS { public static final MethodHandle BIOME_CLIMATESETTINGS_CONSTRUCTOR = ReflectionHelper.getConstructor(Biome.ClimateSettings.class, boolean.class, float.class, Biome.TemperatureModifier.class, float.class); public static final MethodHandle MAPPED_REGISTRY_REGISTRATION_INFOS = ReflectionHelper.getFields(MappedRegistry.class).getGetter(ReflectionMappingsInfo.MappedRegistry_registrationInfos); + public static final MethodHandle BIOME_ATTRIBUTES_SETTER = ReflectionHelper.getFields(Biome.class).getSetter(ReflectionMappingsInfo.Biome_attributes); public Holder.Reference biomeHolder; public ServerLevel world; @@ -153,23 +157,37 @@ public void setFoliageColor(int color) { @Override public int getFogColor() { - return biomeHolder.value().getFogColor(); + return getEnvironmentAttribute(EnvironmentAttributes.FOG_COLOR); } @Override public void setFogColor(int color) { - ReflectionHelper.setFieldValue(BiomeSpecialEffects.class, ReflectionMappingsInfo.BiomeSpecialEffects_fogColor, biomeHolder.value().getSpecialEffects(), color); - setNetworkedRegistrationInfo(); + setEnvironmentAttribute(EnvironmentAttributes.FOG_COLOR, color); } @Override public int getWaterFogColor() { - return biomeHolder.value().getWaterFogColor(); + return getEnvironmentAttribute(EnvironmentAttributes.WATER_FOG_COLOR); } @Override public void setWaterFogColor(int color) { - ReflectionHelper.setFieldValue(BiomeSpecialEffects.class, ReflectionMappingsInfo.BiomeSpecialEffects_waterFogColor, biomeHolder.value().getSpecialEffects(), color); + setEnvironmentAttribute(EnvironmentAttributes.WATER_FOG_COLOR, color); + } + + public T getEnvironmentAttribute(EnvironmentAttribute attribute) { + return biomeHolder.value().getAttributes().applyModifier(attribute, attribute.defaultValue()); + } + + public void setEnvironmentAttribute(EnvironmentAttribute attribute, T value) { + Biome nmsBiome = biomeHolder.value(); + EnvironmentAttributeMap newAttributeMap = EnvironmentAttributeMap.builder().putAll(nmsBiome.getAttributes()).set(attribute, value).build(); + try { + BIOME_ATTRIBUTES_SETTER.invokeExact(nmsBiome, newAttributeMap); + } + catch (Throwable e) { + Debug.echoError(e); + } setNetworkedRegistrationInfo(); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java index 1bc426b044..4b45bfded0 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/CraftFakeArrowImpl.java @@ -1,7 +1,7 @@ package com.denizenscript.denizen.nms.v1_21.impl.entities; import com.denizenscript.denizen.nms.interfaces.FakeArrow; -import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.entity.projectile.arrow.AbstractArrow; import org.bukkit.craftbukkit.v1_21_R7.CraftServer; import org.bukkit.craftbukkit.v1_21_R7.entity.CraftAbstractArrow; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java index 77beee2417..bad4b878de 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/entities/EntityFakeArrowImpl.java @@ -2,7 +2,7 @@ import com.denizenscript.denizen.nms.v1_21.Handler; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.minecraft.world.entity.projectile.SpectralArrow; +import net.minecraft.world.entity.projectile.arrow.SpectralArrow; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import org.bukkit.Bukkit; From 42b15a8b160ff2d395b419b33001dc945d163914 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 10 Dec 2025 04:04:55 +0000 Subject: [PATCH 047/169] 1.21.11 part 6: minor meta updates --- .../java/com/denizenscript/denizen/objects/WorldTag.java | 7 +++---- .../denizen/scripts/commands/world/GameRuleCommand.java | 7 ++----- .../denizen/utilities/world/GameRuleReflect.java | 1 + 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java index 46a07a49e3..631a9a9090 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java @@ -853,7 +853,6 @@ else if (time >= 12500) { // @returns ElementTag // @description // Returns the current value of the specified gamerule in the world. - // Note that the name is case-sensitive... so "doFireTick" is correct, but "dofiretick" is not. // --> registerTag(ElementTag.class, "gamerule", (attribute, object) -> { if (!attribute.hasParam()) { @@ -992,7 +991,7 @@ else if (time >= 12500) { // @description // Returns whether enough players are sleeping to prepare for the night to advance. // Typically used before checking <@link tag WorldTag.enough_deep_sleeping> - // By default, automatically checks the playersSleepingPercentage gamerule, + // By default, automatically checks the players_sleeping_percentage gamerule, // but this can optionally be overridden by specifying a percentage integer. // Any integer above 100 will always yield 'false'. Requires at least one player to be sleeping to return 'true'. // --> @@ -1013,7 +1012,7 @@ else if (time >= 12500) { // @description // Returns whether enough players have been in bed long enough for the night to advance (generally 100 ticks). // Loops through all online players, so is typically used after checking <@link tag WorldTag.enough_sleeping> - // By default, automatically checks the playersSleepingPercentage gamerule, + // By default, automatically checks the players_sleeping_percentage gamerule, // but this can optionally be overridden by specifying a percentage integer. // Any integer above 100 will always yield 'false'. Requires at least one player to be sleeping to return 'true'. // --> @@ -1514,7 +1513,7 @@ else if (time >= 12500) { // @input None // @description // Skips to the next day as if enough players slept through the night. - // NOTE: This ignores the doDaylightCycle gamerule! + // NOTE: This ignores the advance_time gamerule! // --> tagProcessor.registerMechanism("skip_night", false, (object, mechanism) -> { // general logic from NMS world tick diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/GameRuleCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/GameRuleCommand.java index 06387e6295..3efb74c13d 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/GameRuleCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/GameRuleCommand.java @@ -32,22 +32,19 @@ public GameRuleCommand() { // // @Description // Sets a gamerule on the world. A list of valid gamerules can be found here: <@link url https://minecraft.wiki/w/Game_rule> - // Note: Be careful, gamerules are CASE SENSITIVE. // // @Tags // ]> // // @Usage // Use to disable fire spreading in world "Adventure". - // - gamerule Adventure doFireTick false + // - gamerule Adventure fire_spread_radius_around_player 0 // // @Usage // Use to avoid mobs from destroying blocks (creepers, endermen...) and picking items up (zombies, skeletons...) in world "Adventure". - // - gamerule Adventure mobGriefing false + // - gamerule Adventure mob_griefing false // --> - - @Override public void addCustomTabCompletions(TabCompletionsBuilder tab) { for (GameRule gameRule : GameRuleReflect.values()) { diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java index c8dcb77109..ab8b4e720e 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java @@ -53,6 +53,7 @@ public static Class getType(GameRule gameRule) { } } + // TODO 1.21.11: certain gamemodes (e.g. max_minecart_speed) behave badly on Spigot, need to test with Paper public static T getValue(World world, GameRule gameRule) { try { return world.getGameRuleValue(gameRule); From 8f9438b341b643c866c9711cd48bbd263504a796 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 10 Dec 2025 05:09:54 +0000 Subject: [PATCH 048/169] 1.21.11 part 7: bump citizens version --- paper/pom.xml | 2 +- plugin/pom.xml | 2 +- .../com/denizenscript/denizen/utilities/world/PathFinder.java | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/paper/pom.xml b/paper/pom.xml index a72fc09250..7d3b6b0869 100644 --- a/paper/pom.xml +++ b/paper/pom.xml @@ -31,7 +31,7 @@ net.citizensnpcs citizens-main - 2.0.38-SNAPSHOT + 2.0.41-SNAPSHOT jar provided diff --git a/plugin/pom.xml b/plugin/pom.xml index 4b12edfaa7..1e3abee04d 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -44,7 +44,7 @@ net.citizensnpcs citizens-main - 2.0.38-SNAPSHOT + 2.0.41-SNAPSHOT jar provided diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/PathFinder.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/PathFinder.java index 6a2acd30e5..4bb78544c6 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/PathFinder.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/PathFinder.java @@ -2,6 +2,7 @@ import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.citizensnpcs.api.ai.NavigatorParameters; import net.citizensnpcs.api.astar.AStarMachine; import net.citizensnpcs.api.astar.pathfinder.*; import org.bukkit.Location; @@ -19,7 +20,7 @@ public class PathFinder { public static List getPath(Location start, Location dest) { VectorGoal goal = new VectorGoal(dest, 1); - Path plan = (Path) ASTAR.runFully(goal, new VectorNode(goal, start, new ChunkBlockSource(start, 100), new MinecraftBlockExaminer()), 50000); + Path plan = (Path) ASTAR.runFully(goal, new VectorNode(goal, start, new ChunkBlockSource(start, 100), new NavigatorParameters().examiner(new MinecraftBlockExaminer())), 50000); if (plan == null) { Debug.verboseLog("PathFinder: No path found from " + start + " to " + dest + " (return null)"); return new ArrayList<>(); From 9b6c658b7e402edd0298a83f9c18fb10ef49cb02 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Fri, 12 Dec 2025 15:47:21 -0800 Subject: [PATCH 049/169] ` explosion primes`: updates, meta fixes (#2776) * Made determinations more clear for EntityExplosionPrimesScriptEvent * added deprecation message --- .../EntityExplosionPrimesScriptEvent.java | 61 ++++++++++--------- .../utilities/BukkitImplDeprecations.java | 3 + 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExplosionPrimesScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExplosionPrimesScriptEvent.java index 930b99010f..aab61ed369 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExplosionPrimesScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExplosionPrimesScriptEvent.java @@ -2,9 +2,8 @@ import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.events.BukkitScriptEvent; -import com.denizenscript.denizencore.objects.Argument; +import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.ArgumentHelper; import com.denizenscript.denizencore.objects.ObjectTag; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -25,13 +24,36 @@ public class EntityExplosionPrimesScriptEvent extends BukkitScriptEvent implemen // @Triggers when an entity decides to explode. // // @Context - // returns the EntityTag. - // returns an ElementTag of the explosion's radius. - // returns an ElementTag with a value of "true" if the explosion will create fire and "false" otherwise. + // returns an EntityTag of the explosive. + // returns the explosion's radius. + // returns whether the explosion will create fire. + // + // @Determine + // ElementTag(Decimal) to change the explosion radius. + // "FIRE:" to set whether the explosion will produce fire. // --> public EntityExplosionPrimesScriptEvent() { registerCouldMatcher(" explosion primes"); + this.registerOptionalDetermination(null, ElementTag.class, (evt, context, value) -> { + if (value.isBoolean()) { + BukkitImplDeprecations.explosionPrimeDetermination.warn(); + evt.event.setFire(value.asBoolean()); + return true; + } + if (value.isFloat()) { + evt.event.setRadius(value.asFloat()); + return true; + } + return false; + }); + this.registerOptionalDetermination("fire", ElementTag.class, (evt, context, value) -> { + if (value.isBoolean()) { + evt.event.setFire(value.asBoolean()); + return true; + } + return false; + }); } public EntityTag entity; @@ -48,31 +70,14 @@ public boolean matches(ScriptPath path) { return super.matches(path); } - @Override - public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { - String determination = determinationObj.toString(); - if (ArgumentHelper.matchesDouble(determination)) { - event.setRadius(Float.parseFloat(determination)); - return true; - } - if (Argument.valueOf(determination).matchesBoolean()) { - event.setFire(determination.equalsIgnoreCase("true")); - return true; - } - return super.applyDetermination(path, determinationObj); - } - @Override public ObjectTag getContext(String name) { - switch (name) { - case "entity": - return entity; - case "radius": - return new ElementTag(event.getRadius()); - case "fire": - return new ElementTag(event.getFire()); - } - return super.getContext(name); + return switch (name) { + case "entity" -> entity.getDenizenObject(); + case "radius" -> new ElementTag(event.getRadius()); + case "fire" -> new ElementTag(event.getFire()); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java index 8c862c1172..50ef530154 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java @@ -267,6 +267,9 @@ public class BukkitImplDeprecations { // Added 2025/07/10 public static Warning entityKnockback = new Warning("entityKnockback", "The 'EntityTag.knockback' property is deprecated. You should adjust the knockback enchantment on the weapon itself."); + // Added 2025/10/24 + public static Warning explosionPrimeDetermination = new Warning("explosionPrimeDetermination", "The determination to control fire in the ' explosion primes' event is now formatted as 'FIRE:'."); + // ==================== SLOW deprecations ==================== // These aren't spammed, but will show up repeatedly until fixed. Server owners will probably notice them. From f950c87eac8bb0d456c5cda5a80a1f0ed631168b Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Fri, 12 Dec 2025 16:24:49 -0800 Subject: [PATCH 050/169] `MaterialTag.count`: add wild flowers and leaf litter (#2784) * MaterialCount expanded to FlowerBed and LeafLitter * rearrange checks * minor changes, removed multiple `isX` and `getX` methods * minor fixes * minor changes --- .../properties/material/MaterialCount.java | 250 +++++++----------- 1 file changed, 100 insertions(+), 150 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialCount.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialCount.java index 398d1c5b27..dda2076d26 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialCount.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialCount.java @@ -4,63 +4,98 @@ import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizencore.objects.Mechanism; -import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.properties.Property; import com.denizenscript.denizencore.objects.properties.PropertyParser; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.*; -public class MaterialCount implements Property { +public class MaterialCount extends MaterialProperty { + // TODO: once 1.21 is the minimum supported version, remove PinkPetals interface in favor of FlowerBed - public static boolean describes(ObjectTag material) { - if (!(material instanceof MaterialTag mat)) { - return false; - } - if (!mat.hasModernData()) { - return false; - } - BlockData data = mat.getModernData(); + // <--[property] + // @object MaterialTag + // @name count + // @input ElementTag(Number) + // @description + // Controls the amount of pickles in a Sea Pickle material, eggs in a Turtle Egg material, charges in a Respawn Anchor material, candles in a Candle material, flowers in a flower bed, or leaves in a leaf litter. + // --> + + public static boolean describes(MaterialTag material) { + BlockData data = material.getModernData(); return data instanceof SeaPickle || data instanceof TurtleEgg || data instanceof RespawnAnchor || data instanceof Candle - || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && data instanceof PinkPetals); + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && data instanceof PinkPetals) + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && (data instanceof FlowerBed + || data instanceof LeafLitter)); } - public static MaterialCount getFrom(ObjectTag _material) { - if (!describes(_material)) { - return null; + @Override + public ElementTag getPropertyValue() { + if (getBlockData() instanceof SeaPickle seaPickle) { + return new ElementTag(seaPickle.getPickles()); + } + else if (getBlockData() instanceof TurtleEgg turtleEgg) { + return new ElementTag(turtleEgg.getEggs()); + } + else if (getBlockData() instanceof RespawnAnchor respawnAnchor) { + return new ElementTag(respawnAnchor.getCharges()); } - else { - return new MaterialCount((MaterialTag) _material); + else if (getBlockData() instanceof Candle candle) { + return new ElementTag(candle.getCandles()); } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() instanceof PinkPetals pinkPetals) { + return new ElementTag(pinkPetals.getFlowerAmount()); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof FlowerBed flowerBed) { + return new ElementTag(flowerBed.getFlowerAmount()); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof LeafLitter leafLitter) { + return new ElementTag(leafLitter.getSegmentAmount()); + } + return null; } - public static final String[] handledMechs = new String[] { - "count", "pickle_count" - }; - - public MaterialCount(MaterialTag _material) { - material = _material; + @Override + public void setPropertyValue(ElementTag value, Mechanism mechanism) { + if (mechanism.requireInteger()) { + int count = value.asInt(); + if (count < getMin() || count > getMax()) { + mechanism.echoError("Material count mechanism value '" + count + "' is not valid. Must be between " + getMin() + " and " + getMax() + "."); + return; + } + if (getBlockData() instanceof SeaPickle seaPickle) { + seaPickle.setPickles(count); + } + else if (getBlockData() instanceof TurtleEgg turtleEgg) { + turtleEgg.setEggs(count); + } + else if (getBlockData() instanceof RespawnAnchor respawnAnchor) { + respawnAnchor.setCharges(count); + } + else if (getBlockData() instanceof Candle candle) { + candle.setCandles(count); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() instanceof PinkPetals pinkPetals) { + pinkPetals.setFlowerAmount(count); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof FlowerBed flowerBed) { + flowerBed.setFlowerAmount(count); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof LeafLitter leafLitter) { + leafLitter.setSegmentAmount(count); + } + } } - MaterialTag material; + @Override + public String getPropertyId() { + return "count"; + } public static void register() { - // <--[tag] - // @attribute - // @returns ElementTag(Number) - // @mechanism MaterialTag.count - // @group properties - // @description - // Returns the amount of pickles in a Sea Pickle material, eggs in a Turtle Egg material, charges in a Respawn Anchor material, candles in a Candle material, or petals in a Pink Petals material. - // --> - PropertyParser.registerStaticTag(MaterialCount.class, ElementTag.class, "count", (attribute, material) -> { - return new ElementTag(material.getCurrent()); - }, "pickle_count"); - // <--[tag] // @attribute // @returns ElementTag(Number) @@ -84,142 +119,57 @@ public static void register() { PropertyParser.registerStaticTag(MaterialCount.class, ElementTag.class, "count_min", (attribute, material) -> { return new ElementTag(material.getMin()); }, "pickle_min"); - } - - public boolean isSeaPickle() { - return material.getModernData() instanceof SeaPickle; - } - - public boolean isTurtleEgg() { - return material.getModernData() instanceof TurtleEgg; - } - public boolean isRespawnAnchor() { - return material.getModernData() instanceof RespawnAnchor; - } - - public boolean isCandle() { - return material.getModernData() instanceof Candle; - } - - public TurtleEgg getTurtleEgg() { - return (TurtleEgg) material.getModernData(); - } - - public SeaPickle getSeaPickle() { - return (SeaPickle) material.getModernData(); - } - - public RespawnAnchor getRespawnAnchor() { - return (RespawnAnchor) material.getModernData(); - } - - public Candle getCandle() { - return (Candle) material.getModernData(); - } - - public int getCurrent() { - if (isSeaPickle()) { - return getSeaPickle().getPickles(); - } - else if (isTurtleEgg()) { - return getTurtleEgg().getEggs(); - } - else if (isRespawnAnchor()) { - return getRespawnAnchor().getCharges(); - } - else if (isCandle()) { - return getCandle().getCandles(); - } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && material.getModernData() instanceof PinkPetals pinkPetals) { - return pinkPetals.getFlowerAmount(); - } - throw new UnsupportedOperationException(); + autoRegister("count", MaterialCount.class, ElementTag.class, false, "pickle_count"); } public int getMax() { - if (isSeaPickle()) { - return getSeaPickle().getMaximumPickles(); + if (getBlockData() instanceof SeaPickle seaPickle) { + return seaPickle.getMaximumPickles(); } - else if (isTurtleEgg()) { - return getTurtleEgg().getMaximumEggs(); + else if (getBlockData() instanceof TurtleEgg turtleEgg) { + return turtleEgg.getMaximumEggs(); } - else if (isRespawnAnchor()) { - return getRespawnAnchor().getMaximumCharges(); + else if (getBlockData() instanceof RespawnAnchor respawnAnchor) { + return respawnAnchor.getMaximumCharges(); } - else if (isCandle()) { - return getCandle().getMaximumCandles(); + else if (getBlockData() instanceof Candle candle) { + return candle.getMaximumCandles(); } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && material.getModernData() instanceof PinkPetals pinkPetals) { + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() instanceof PinkPetals pinkPetals) { return pinkPetals.getMaximumFlowerAmount(); } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof FlowerBed flowerBed) { + return flowerBed.getMaximumFlowerAmount(); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof LeafLitter leafLitter) { + return leafLitter.getMaximumSegmentAmount(); + } throw new UnsupportedOperationException(); } public int getMin() { - if (isSeaPickle()) { - return getSeaPickle().getMinimumPickles(); + if (getBlockData() instanceof SeaPickle seaPickle) { + return seaPickle.getMinimumPickles(); } - else if (isTurtleEgg()) { - return getTurtleEgg().getMinimumEggs(); + else if (getBlockData() instanceof TurtleEgg turtleEgg) { + return turtleEgg.getMinimumEggs(); } - else if (isRespawnAnchor()) { + else if (getBlockData() instanceof RespawnAnchor) { return 0; } - else if (isCandle()) { + else if (getBlockData() instanceof Candle) { return 1; } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && material.getModernData() instanceof PinkPetals) { + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() instanceof PinkPetals) { return 1; } - throw new UnsupportedOperationException(); - } - - @Override - public String getPropertyString() { - return String.valueOf(getCurrent()); - } - - @Override - public String getPropertyId() { - return "count"; - } - - @Override - public void adjust(Mechanism mechanism) { - - // <--[mechanism] - // @object MaterialTag - // @name count - // @input ElementTag(Number) - // @description - // Sets the amount of pickles in a Sea Pickle material, eggs in a Turtle Egg material, charges in a Respawn Anchor material, candles in a Candle material, or petals in a Pink Petals material. - // @tags - // - // - // - // --> - if ((mechanism.matches("count") || (mechanism.matches("pickle_count"))) && mechanism.requireInteger()) { - int count = mechanism.getValue().asInt(); - if (count < getMin() || count > getMax()) { - mechanism.echoError("Material count mechanism value '" + count + "' is not valid. Must be between " + getMin() + " and " + getMax() + "."); - return; - } - if (isSeaPickle()) { - getSeaPickle().setPickles(count); - } - else if (isTurtleEgg()) { - getTurtleEgg().setEggs(count); - } - else if (isRespawnAnchor()) { - getRespawnAnchor().setCharges(count); - } - else if (isCandle()) { - getCandle().setCandles(count); - } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && material.getModernData() instanceof PinkPetals pinkPetals) { - pinkPetals.setFlowerAmount(count); - } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof FlowerBed) { + return 1; } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof LeafLitter) { + return 1; + } + throw new UnsupportedOperationException(); } } From edce8c83d473c1396e098fd1e0fdf560fde69a6e Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Fri, 12 Dec 2025 16:46:45 -0800 Subject: [PATCH 051/169] `EntityTag.profession`: 1.21 fix, updates (#2792) * EntityProfession 1.21 fix and modernization * minor changes * minor change --- .../properties/entity/EntityProfession.java | 121 +++++------------- 1 file changed, 30 insertions(+), 91 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityProfession.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityProfession.java index 478f6e9f56..5c8207fd8c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityProfession.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityProfession.java @@ -4,67 +4,46 @@ import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.Mechanism; -import com.denizenscript.denizencore.objects.ObjectTag; -import com.denizenscript.denizencore.objects.properties.Property; -import com.denizenscript.denizencore.tags.Attribute; -import com.denizenscript.denizencore.utilities.CoreUtilities; -import org.bukkit.entity.EntityType; import org.bukkit.entity.Villager; import org.bukkit.entity.ZombieVillager; -public class EntityProfession implements Property { +public class EntityProfession extends EntityProperty { - // TODO This technically has registries on all supported versions - public static boolean describes(ObjectTag entity) { - if (!(entity instanceof EntityTag)) { - return false; - } - return ((EntityTag) entity).getBukkitEntityType() == EntityType.VILLAGER - || ((EntityTag) entity).getBukkitEntityType() == EntityType.ZOMBIE_VILLAGER; - } - - public static EntityProfession getFrom(ObjectTag entity) { - if (!describes(entity)) { - return null; - } - else { - return new EntityProfession((EntityTag) entity); - } - } - - public static final String[] handledTags = new String[] { - "profession" - }; + // <--[property] + // @object EntityTag + // @name profession + // @input ElementTag + // @description + // Controls the profession of a villager or zombie villager. + // For the list of possible professions, refer to <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Villager.Profession.html> + // --> - public static final String[] handledMechs = new String[] { - "profession" - }; - - public EntityProfession(EntityTag entity) { - professional = entity; + public static boolean describes(EntityTag entity) { + return entity.getBukkitEntity() instanceof Villager + || entity.getBukkitEntity() instanceof ZombieVillager; } - EntityTag professional; - - public Villager.Profession getProfession() { - if (professional.getBukkitEntityType() == EntityType.ZOMBIE_VILLAGER) { - return ((ZombieVillager) professional.getBukkitEntity()).getVillagerProfession(); - } - return ((Villager) professional.getBukkitEntity()).getProfession(); - } - - public void setProfession(Villager.Profession profession) { - if (professional.getBukkitEntityType() == EntityType.ZOMBIE_VILLAGER) { - ((ZombieVillager) professional.getBukkitEntity()).setVillagerProfession(profession); + @Override + public ElementTag getPropertyValue() { + if (getEntity() instanceof Villager villager) { + return Utilities.enumlikeToElement(villager.getProfession()); } - else { - ((Villager) professional.getBukkitEntity()).setProfession(profession); + else if (getEntity() instanceof ZombieVillager zvillager) { + return Utilities.enumlikeToElement(zvillager.getVillagerProfession()); } + return null; } @Override - public String getPropertyString() { - return CoreUtilities.toLowerCase(String.valueOf(getProfession())); + public void setPropertyValue(ElementTag value, Mechanism mechanism) { + if (mechanism.requireEnum(Villager.Profession.class)) { + if (getEntity() instanceof Villager villager) { + villager.setProfession(value.asEnum(Villager.Profession.class)); + } + else if (getEntity() instanceof ZombieVillager zvillager) { + zvillager.setVillagerProfession(value.asEnum(Villager.Profession.class)); + } + } } @Override @@ -72,47 +51,7 @@ public String getPropertyId() { return "profession"; } - @Override - public ObjectTag getObjectAttribute(Attribute attribute) { - - if (attribute == null) { - return null; - } - - // <--[tag] - // @attribute - // @returns ElementTag - // @mechanism EntityTag.profession - // @group properties - // @description - // If the entity can have professions, returns the entity's profession. - // Currently, only Villager-type and infected zombie entities can have professions. - // For the list of possible professions, refer to <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Villager.Profession.html> - // --> - if (attribute.startsWith("profession")) { - return new ElementTag(String.valueOf(getProfession()), true) - .getObjectAttribute(attribute.fulfill(1)); - } - - return null; - } - - @Override - public void adjust(Mechanism mechanism) { - - // <--[mechanism] - // @object EntityTag - // @name profession - // @input ElementTag - // @description - // Changes the entity's profession. - // Currently, only Villager-type entities can have professions. - // For the list of possible professions, refer to <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Villager.Profession.html> - // @tags - // - // --> - if (mechanism.matches("profession") && Utilities.requireEnumlike(mechanism, Villager.Profession.class)) { - setProfession(Utilities.elementToEnumlike(mechanism.getValue(), Villager.Profession.class)); - } + public static void register() { + autoRegister("profession", EntityProfession.class, ElementTag.class, false); } } From e2389998e5fcfe166bc2112a06aeb6b83644af1f Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 15 Dec 2025 01:01:38 +0000 Subject: [PATCH 052/169] Various minor cleanups --- .../EntityExplosionPrimesScriptEvent.java | 10 ++++----- .../properties/entity/EntityProfession.java | 21 ++++++++++--------- .../properties/material/MaterialCount.java | 2 +- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExplosionPrimesScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExplosionPrimesScriptEvent.java index aab61ed369..d135e460b7 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExplosionPrimesScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityExplosionPrimesScriptEvent.java @@ -24,7 +24,7 @@ public class EntityExplosionPrimesScriptEvent extends BukkitScriptEvent implemen // @Triggers when an entity decides to explode. // // @Context - // returns an EntityTag of the explosive. + // returns an EntityTag of the exploding entity. // returns the explosion's radius. // returns whether the explosion will create fire. // @@ -36,15 +36,15 @@ public class EntityExplosionPrimesScriptEvent extends BukkitScriptEvent implemen public EntityExplosionPrimesScriptEvent() { registerCouldMatcher(" explosion primes"); this.registerOptionalDetermination(null, ElementTag.class, (evt, context, value) -> { + if (value.isFloat()) { + evt.event.setRadius(value.asFloat()); + return true; + } if (value.isBoolean()) { BukkitImplDeprecations.explosionPrimeDetermination.warn(); evt.event.setFire(value.asBoolean()); return true; } - if (value.isFloat()) { - evt.event.setRadius(value.asFloat()); - return true; - } return false; }); this.registerOptionalDetermination("fire", ElementTag.class, (evt, context, value) -> { diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityProfession.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityProfession.java index 5c8207fd8c..66adee6d3b 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityProfession.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityProfession.java @@ -2,8 +2,8 @@ import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.utilities.Utilities; -import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; import org.bukkit.entity.Villager; import org.bukkit.entity.ZombieVillager; @@ -28,21 +28,22 @@ public ElementTag getPropertyValue() { if (getEntity() instanceof Villager villager) { return Utilities.enumlikeToElement(villager.getProfession()); } - else if (getEntity() instanceof ZombieVillager zvillager) { - return Utilities.enumlikeToElement(zvillager.getVillagerProfession()); + else if (getEntity() instanceof ZombieVillager zombieVillager) { + return Utilities.enumlikeToElement(zombieVillager.getVillagerProfession()); } return null; } @Override public void setPropertyValue(ElementTag value, Mechanism mechanism) { - if (mechanism.requireEnum(Villager.Profession.class)) { - if (getEntity() instanceof Villager villager) { - villager.setProfession(value.asEnum(Villager.Profession.class)); - } - else if (getEntity() instanceof ZombieVillager zvillager) { - zvillager.setVillagerProfession(value.asEnum(Villager.Profession.class)); - } + if (!mechanism.requireEnum(Villager.Profession.class)) { + return; + } + if (getEntity() instanceof Villager villager) { + villager.setProfession(value.asEnum(Villager.Profession.class)); + } + else if (getEntity() instanceof ZombieVillager zombieVillager) { + zombieVillager.setVillagerProfession(value.asEnum(Villager.Profession.class)); } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialCount.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialCount.java index dda2076d26..dd69b8ef8a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialCount.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialCount.java @@ -10,7 +10,7 @@ import org.bukkit.block.data.type.*; public class MaterialCount extends MaterialProperty { - // TODO: once 1.21 is the minimum supported version, remove PinkPetals interface in favor of FlowerBed + // TODO: once 1.21 is the minimum supported version, remove PinkPetals usage in favor of FlowerBed // <--[property] // @object MaterialTag From df4991483341be7866ba7a25ea588eb78c05d925 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 15 Dec 2025 01:04:11 +0000 Subject: [PATCH 053/169] Fix `PlayerHelper(1.21)#refreshPlayer` on Paper --- .../denizen/nms/v1_21/helpers/PlayerHelperImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java index 8493e40ade..6f73e27c02 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java @@ -31,8 +31,8 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; import net.minecraft.network.protocol.game.*; -import net.minecraft.resources.ResourceKey; import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerEntity; @@ -501,7 +501,7 @@ public void refreshPlayer(Player player) { nmsPlayer.connection.send(new ClientboundUpdateMobEffectPacket(nmsPlayer.getId(), nmsEffect, false)); } nmsPlayer.onUpdateAbilities(); - PlayerList nmsPlayerList = nmsPlayer.server.getPlayerList(); + PlayerList nmsPlayerList = MinecraftServer.getServer().getPlayerList(); nmsPlayerList.sendPlayerPermissionLevel(nmsPlayer); nmsPlayerList.sendLevelInfo(nmsPlayer, nmsWorld); nmsPlayerList.sendAllPlayerInfo(nmsPlayer); From 117278fffc97b372c48818aa7b6bb5de2efecafa Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 24 Dec 2025 13:12:02 +0000 Subject: [PATCH 054/169] `BiomeTag.foliage_color` mech: 1.21 fix --- .../denizen/nms/v1_21/ReflectionMappingsInfo.java | 4 +--- .../denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 905e259d71..360d260ee4 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -60,9 +60,7 @@ public class ReflectionMappingsInfo { // net.minecraft.world.level.biome.Biome public static String Biome_climateSettings = "i"; public static String Biome_attributes = "l"; - - // net.minecraft.world.level.biome.BiomeSpecialEffects - public static String BiomeSpecialEffects_foliageColorOverride = "c"; + public static String Biome_specialEffects = "m"; // net.minecraft.network.Connection public static String Connection_receiving = "h"; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java index 73870f8afd..d360c4318a 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/BiomeNMSImpl.java @@ -151,7 +151,11 @@ public void setHasDownfall(boolean hasDownfall) { @Override public void setFoliageColor(int color) { - ReflectionHelper.setFieldValue(BiomeSpecialEffects.class, ReflectionMappingsInfo.BiomeSpecialEffects_foliageColorOverride, biomeHolder.value().getSpecialEffects(), Optional.of(color)); + BiomeSpecialEffects nmsCurrEffects = biomeHolder.value().getSpecialEffects(); + BiomeSpecialEffects nmsNewEffects = new BiomeSpecialEffects( + nmsCurrEffects.waterColor(), Optional.of(color), nmsCurrEffects.dryFoliageColorOverride(), nmsCurrEffects.grassColorOverride(), nmsCurrEffects.grassColorModifier() + ); + ReflectionHelper.setFieldValue(Biome.class, ReflectionMappingsInfo.Biome_specialEffects, biomeHolder.value(), nmsNewEffects); setNetworkedRegistrationInfo(); } From c2c8331edeaa21e3ddbfec66dc6cc6b9285ec13e Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 25 Dec 2025 17:15:38 +0000 Subject: [PATCH 055/169] `NetworkInterceptCodeGen`: 1.21 fix (#2800) --- .../packets/NetworkInterceptCodeGen.java | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/packets/NetworkInterceptCodeGen.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/packets/NetworkInterceptCodeGen.java index 96d5ef3055..9e01916f1c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/packets/NetworkInterceptCodeGen.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/packets/NetworkInterceptCodeGen.java @@ -1,10 +1,13 @@ package com.denizenscript.denizen.utilities.packets; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.utilities.codegen.CodeGenUtil; import com.denizenscript.denizencore.utilities.codegen.MethodGenerator; -import org.objectweb.asm.*; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -12,6 +15,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.List; public class NetworkInterceptCodeGen { @@ -54,18 +59,46 @@ public static void generateClass(Class denClass, Class abstractClass, Clas + ", Public=" + Modifier.isPublic(modifier) + ", final=" + Modifier.isFinal(modifier)); } MethodGenerator gen = MethodGenerator.generateMethod(className, cw, Opcodes.ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method)); - gen.loadThis(); - gen.loadInstanceField(Type.getInternalName(abstractClass), "oldListener", Type.getDescriptor(nmsClass)); + List locals = new ArrayList<>(); int id = 1; for (Class type : method.getParameterTypes()) { if (NMSHandler.debugPackets) { Debug.log("Var " + id + " is type " + type.getName()); } - MethodGenerator.Local local = gen.addLocal("arg_" + (id++), type); - gen.loadLocal(local); + locals.add(gen.addLocal("arg_" + (id++), type)); } + Label returnLabel = new Label(); + gen.loadThis(); + gen.loadInstanceField(Type.getInternalName(abstractClass), "oldListener", Type.getDescriptor(nmsClass)); + gen.jumpIfNullTo(returnLabel); + gen.loadThis(); + gen.loadInstanceField(Type.getInternalName(abstractClass), "oldListener", Type.getDescriptor(nmsClass)); + locals.forEach(gen::loadLocal); gen.invokeVirtual(method); - gen.returnValue(method.getReturnType()); + Class returnType = method.getReturnType(); + gen.returnValue(returnType); + + gen.advanceAndLabel(returnLabel); + if (returnType != Void.TYPE) { + if (returnType.isPrimitive()) { + if (returnType == Long.TYPE) { + gen.mv.visitInsn(Opcodes.LCONST_0); + } + else if (returnType == Float.TYPE) { + gen.mv.visitInsn(Opcodes.FCONST_0); + } + else if (returnType == Double.TYPE) { + gen.mv.visitInsn(Opcodes.DCONST_0); + } + else { + gen.mv.visitInsn(Opcodes.ICONST_0); + } + } + else { + gen.loadNull(); + } + } + gen.returnValue(returnType); gen.end(); } } From e001ec2fa91cd120f4802b1e4ca487079bbe7759 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 26 Dec 2025 23:25:39 +0000 Subject: [PATCH 056/169] `GameRuleReflect`: 1.21.11 paper fixes --- .../denizen/utilities/world/GameRuleReflect.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java index ab8b4e720e..6163452629 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java @@ -2,8 +2,10 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.NMSVersion; +import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.utilities.ReflectionHelper; import org.bukkit.GameRule; +import org.bukkit.Keyed; import org.bukkit.World; import java.lang.invoke.MethodHandle; @@ -15,7 +17,8 @@ public class GameRuleReflect { private static final MethodHandle GAMERULE_GET_NAME = ReflectionHelper.getMethodHandle(GameRule.class, "getName"); private static final MethodHandle GAMERULE_GET_TYPE = ReflectionHelper.getMethodHandle(GameRule.class, "getType"); - public static final GameRule WEATHER_CYCLE_GAMERULE = NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) ? GameRule.ADVANCE_WEATHER : (GameRule) getByName("doWeatherCycle"); + public static final boolean MODERN_GAMERULE_NAMING = NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21); + public static final GameRule WEATHER_CYCLE_GAMERULE = getByName(MODERN_GAMERULE_NAMING ? "advance_weather" : "doWeatherCycle"); public static GameRule[] values() { try { @@ -26,9 +29,9 @@ public static GameRule[] values() { } } - public static GameRule getByName(String name) { + public static GameRule getByName(String name) { try { - return (GameRule) GAMERULE_GET_BY_NAME.invokeExact(name); + return (GameRule) GAMERULE_GET_BY_NAME.invokeExact(name); } catch (Throwable e) { throw new RuntimeException(e); @@ -36,6 +39,9 @@ public static GameRule getByName(String name) { } public static String getName(GameRule gameRule) { + if (MODERN_GAMERULE_NAMING) { + return Utilities.namespacedKeyToString(((Keyed) gameRule).getKey()); + } try { return (String) GAMERULE_GET_NAME.invokeExact(gameRule); } @@ -53,7 +59,7 @@ public static Class getType(GameRule gameRule) { } } - // TODO 1.21.11: certain gamemodes (e.g. max_minecart_speed) behave badly on Spigot, need to test with Paper + // TODO 1.21.11: certain gamemodes (e.g. max_minecart_speed) behave badly for some reason public static T getValue(World world, GameRule gameRule) { try { return world.getGameRuleValue(gameRule); From a9d4e86b61687d2ad9771876ec50912804208645 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Sun, 4 Jan 2026 12:37:19 -0800 Subject: [PATCH 057/169] `MaterialTag.level`: dried ghast support (#2779) * Added Dried Ghast Hydration Level * Removed unnecessary version checks * minor changes, removed multiple `isX` and `getX` methods * getMin added back * whoops * last one --- .../properties/material/MaterialLevel.java | 167 +++++++----------- 1 file changed, 65 insertions(+), 102 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialLevel.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialLevel.java index 054573c513..08b3bff668 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialLevel.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialLevel.java @@ -9,10 +9,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Brushable; import org.bukkit.block.data.Levelled; -import org.bukkit.block.data.type.Beehive; -import org.bukkit.block.data.type.Cake; -import org.bukkit.block.data.type.Farmland; -import org.bukkit.block.data.type.Snow; +import org.bukkit.block.data.type.*; public class MaterialLevel extends MaterialProperty { @@ -32,6 +29,7 @@ public class MaterialLevel extends MaterialProperty { // For farmland, this is the moisture level. // For composters, this is the amount of compost. // For brushable blocks (also referred to as "suspicious blocks"), this is the level of dusting. 1.20+ only. + // For dried ghasts, this is the level of hydration. 1.21+ only. // See also <@link tag MaterialTag.maximum_level> and <@link tag MaterialTag.minimum_level>. // --> @@ -42,12 +40,34 @@ public static boolean describes(MaterialTag material) { || data instanceof Snow || data instanceof Farmland || data instanceof Beehive - || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && data instanceof Brushable); + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && data instanceof Brushable) + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && data instanceof DriedGhast); } @Override public ElementTag getPropertyValue() { - return new ElementTag(getCurrent()); + if (getBlockData() instanceof Cake cake) { + return new ElementTag(cake.getBites()); + } + else if (getBlockData() instanceof Snow snow) { + return new ElementTag(snow.getLayers()); + } + else if (getBlockData() instanceof Beehive beehive) { + return new ElementTag(beehive.getHoneyLevel()); + } + else if (getBlockData() instanceof Farmland farmland) { + return new ElementTag(farmland.getMoisture()); + } + else if (getBlockData() instanceof Levelled levelled) { + return new ElementTag(levelled.getLevel()); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && getBlockData() instanceof Brushable brushable) { + return new ElementTag(brushable.getDusted()); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof DriedGhast driedGhast) { + return new ElementTag(driedGhast.getHydration()); + } + return null; } @Override @@ -65,7 +85,27 @@ public void setPropertyValue(ElementTag value, Mechanism mechanism) { mechanism.echoError("Level value '" + level + "' is not valid. Must be between " + getMin() + " and " + getMax() + " for material '" + getBlockData().getMaterial().name() + "'."); return; } - setCurrent(level); + if (getBlockData() instanceof Cake cake) { + cake.setBites(level); + } + else if (getBlockData() instanceof Snow snow) { + snow.setLayers(level); + } + else if (getBlockData() instanceof Beehive beehive) { + beehive.setHoneyLevel(level); + } + else if (getBlockData() instanceof Farmland farmland) { + farmland.setMoisture(level); + } + else if (getBlockData() instanceof Levelled levelled) { + levelled.setLevel(level); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && getBlockData() instanceof Brushable brushable) { + brushable.setDusted(level); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof DriedGhast driedGhast) { + driedGhast.setHydration(level); + } } public static void register() { @@ -96,112 +136,35 @@ public static void register() { autoRegister("level", MaterialLevel.class, ElementTag.class, false); } - public Levelled getLevelled() { - return (Levelled) getBlockData(); - } - - public boolean isCake() { - return getBlockData() instanceof Cake; - } - - public Cake getCake() { - return (Cake) getBlockData(); - } - - public boolean isSnow() { - return getBlockData() instanceof Snow; - } - - public Snow getSnow() { - return (Snow) getBlockData(); - } - - public boolean isHive() { - return getBlockData() instanceof Beehive; - } - - public Beehive getHive() { - return (Beehive) getBlockData(); - } - - public boolean isFarmland() { - return getBlockData() instanceof Farmland; - } - - public Farmland getFarmland() { - return (Farmland) getBlockData(); - } - - public boolean isBrushable() { - return NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && getBlockData() instanceof Brushable; - } - - public int getCurrent() { - if (isCake()) { - return getCake().getBites(); - } - else if (isSnow()) { - return getSnow().getLayers(); - } - else if (isHive()) { - return getHive().getHoneyLevel(); - } - else if (isFarmland()) { - return getFarmland().getMoisture(); + public int getMax() { + if (getBlockData() instanceof Cake cake) { + return cake.getMaximumBites(); } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && isBrushable()) { - return ((Brushable) getBlockData()).getDusted(); + else if (getBlockData() instanceof Snow snow) { + return snow.getMaximumLayers(); } - return getLevelled().getLevel(); - } - - public int getMax() { - if (isCake()) { - return getCake().getMaximumBites(); + else if (getBlockData() instanceof Beehive beehive) { + return beehive.getMaximumHoneyLevel(); } - else if (isSnow()) { - return getSnow().getMaximumLayers(); + else if (getBlockData() instanceof Farmland farmland) { + return farmland.getMaximumMoisture(); } - else if (isHive()) { - return getHive().getMaximumHoneyLevel(); + else if (getBlockData() instanceof Levelled levelled) { + return levelled.getMaximumLevel(); } - else if (isFarmland()) { - return getFarmland().getMaximumMoisture(); + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && getBlockData() instanceof Brushable brushable) { + return brushable.getMaximumDusted(); } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && isBrushable()) { - return ((Brushable) getBlockData()).getMaximumDusted(); + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof DriedGhast driedGhast) { + return driedGhast.getMaximumHydration(); } - return getLevelled().getMaximumLevel(); + throw new UnsupportedOperationException(); } public int getMin() { - if (isSnow()) { - return getSnow().getMinimumLayers(); + if (getBlockData() instanceof Snow snow) { + return snow.getMinimumLayers(); } return 0; } - - public void setCurrent(int level) { - if (isCake()) { - getCake().setBites(level); - return; - } - else if (isSnow()) { - getSnow().setLayers(level); - return; - } - else if (isHive()) { - getHive().setHoneyLevel(level); - return; - } - else if (isFarmland()) { - getFarmland().setMoisture(level); - return; - } - else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && isBrushable()) { - ((Brushable) getBlockData()).setDusted(level); - return; - } - getLevelled().setLevel(level); - } } From 3206ac07db76e831fed2dca41085f962ffec5e5f Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Sun, 4 Jan 2026 14:36:57 -0800 Subject: [PATCH 058/169] `LocationTag.disabled_slots` tag and mech (#2781) * `Crafter_Disabled_Slots` tag and mechanism * minor changes * separate asInt check * minor fixes * meta correction * renamed the tag and mechanism, cleaned up handling of mechanism --- .../denizen/objects/LocationTag.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java index e686ef7c92..35501f2d69 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java @@ -4507,6 +4507,67 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk } return new ElementTag(chiseledBookshelf.getSlot(input.toVector()) + 1); }); + + // <--[tag] + // @attribute + // @returns ListTag + // @mechanism LocationTag.disabled_slots + // @group world + // @description + // Returns which slots in a crafter are disabled. + // The slots are arranged from left to right, top to bottom. + // --> + tagProcessor.registerTag(ListTag.class, "disabled_slots", (attribute, object) -> { + if (!(object.getBlockStateForTag(attribute) instanceof Crafter crafter)) { + attribute.echoError("The 'LocationTag.disabled_slots' tag can only be called on a crafter block."); + return null; + } + ListTag slots = new ListTag(); + for (int i = 0; i <= 8; i++) { + if (crafter.isSlotDisabled(i)) { + slots.addObject(new ElementTag(i + 1)); + } + } + return slots; + }); + + // <--[mechanism] + // @object LocationTag + // @name disabled_slots + // @input ListTag + // @description + // Sets which slots in a crafter are disabled. + // The slots are arranged from left to right, top to bottom. + // Provide no input to enable all slots. + // @tags + // + // @example + // # Disables the slots in the top left and middle right + // - adjustblock <[location]> disabled_slots:1|6 + // --> + tagProcessor.registerMechanism("disabled_slots", false, ListTag.class, (object, mechanism, input) -> { + if (!(object.getBlockState() instanceof Crafter crafter)) { + mechanism.echoError("The 'LocationTag.disabled_slots' mechanism can only be called on a crafter block."); + return; + } + for (int i = 0; i <= 8; i++) { + crafter.setSlotDisabled(i, false); + } + for (String slot : input) { + ElementTag element = new ElementTag(slot); + if (!element.isInt()) { + mechanism.echoError("Invalid slot '" + slot + "' specified: must be an integer."); + continue; + } + int value = element.asInt(); + if (value < 1 || value > 9) { + mechanism.echoError("Invalid slot '" + slot + "' specified: must between 1 and 9."); + continue; + } + crafter.setSlotDisabled(value - 1, true); + } + crafter.update(); + }); } // <--[mechanism] From eed670897f660cf7f20db2aa6546ac6970bbb4b5 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:16:44 +0000 Subject: [PATCH 059/169] `FakeEquipmentPacketHandlers`: 1.21.11 fix Ref https://discord.com/channels/315163488085475337/1456099547351617680 --- .../network/handlers/packet/FakeEquipmentPacketHandlers.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java index ab05832bd4..97d21d284a 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java @@ -4,7 +4,6 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; import com.mojang.datafixers.util.Pair; -import net.minecraft.core.NonNullList; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; import net.minecraft.server.level.ServerPlayer; @@ -86,7 +85,7 @@ public static ClientboundContainerSetContentPacket processContainerSetContentPac if (override == null) { return setContentPacket; } - NonNullList items = (NonNullList) setContentPacket.items(); + List items = setContentPacket.items(); if (override.head != null) { items.set(5, CraftItemStack.asNMSCopy(override.head.getItemStack())); } From 81a6724215f2532d2f590ac9727720545437237d Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 9 Jan 2026 22:32:32 +0000 Subject: [PATCH 060/169] Adventure NBT: bump, list handling fixes, cleanups Ref https://discord.com/channels/315163488085475337/1421559549311320146 --- plugin/pom.xml | 2 +- .../nms/abstracts/ImprovedOfflinePlayer.java | 2 +- .../denizen/nms/interfaces/ItemHelper.java | 3 +-- .../objects/properties/item/ItemArmorPose.java | 3 +-- .../objects/properties/item/ItemRawNBT.java | 14 ++++++-------- .../utilities/blocks/SpongeSchematicHelper.java | 9 ++++----- .../denizen/utilities/nbt/CustomNBT.java | 4 ++-- .../denizen/nms/v1_17/helpers/NBTAdapter.java | 13 ++++++------- .../denizen/nms/v1_18/helpers/NBTAdapter.java | 13 ++++++------- .../denizen/nms/v1_19/helpers/NBTAdapter.java | 13 ++++++------- .../denizen/nms/v1_20/helpers/ItemHelperImpl.java | 3 +-- .../denizen/nms/v1_20/helpers/NBTAdapter.java | 13 ++++++------- .../denizen/nms/v1_21/helpers/ItemHelperImpl.java | 2 +- .../denizen/nms/v1_21/helpers/NBTAdapter.java | 12 ++++++------ 14 files changed, 48 insertions(+), 58 deletions(-) diff --git a/plugin/pom.xml b/plugin/pom.xml index 1e3abee04d..617aa38e14 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -70,7 +70,7 @@ net.kyori adventure-nbt - 4.23.0 + 4.26.1 diff --git a/plugin/src/main/java/com/denizenscript/denizen/nms/abstracts/ImprovedOfflinePlayer.java b/plugin/src/main/java/com/denizenscript/denizen/nms/abstracts/ImprovedOfflinePlayer.java index 6e6b834478..f031a63c31 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/nms/abstracts/ImprovedOfflinePlayer.java +++ b/plugin/src/main/java/com/denizenscript/denizen/nms/abstracts/ImprovedOfflinePlayer.java @@ -204,7 +204,7 @@ public void setAbsorptionAmount(float input) { } public void setBedSpawnLocation(Location location) { - if (location == null && !compound.keySet().contains("SpawnDimension")) { + if (location == null && !compound.contains("SpawnDimension")) { return; } CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder().put(compound); diff --git a/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/ItemHelper.java b/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/ItemHelper.java index 4ae68a5f7f..f14e1255d6 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/ItemHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/ItemHelper.java @@ -85,8 +85,7 @@ public CompoundBinaryTag getEntityData(ItemStack item) { // TODO: once 1.20 is t public ItemStack setEntityData(ItemStack item, CompoundBinaryTag entityNbt, EntityType entityType) { // TODO: once 1.20 is the minimum supported version, remove default impl boolean shouldRemove = entityNbt == null || entityNbt.isEmpty(); CompoundBinaryTag nbt = getNbtData(item); - // TODO: adventure-nbt: contains - if (shouldRemove && !nbt.keySet().contains("EntityTag")) { + if (shouldRemove && !nbt.contains("EntityTag")) { return item; } if (shouldRemove) { diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemArmorPose.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemArmorPose.java index 306baff5cb..f6521e0f0c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemArmorPose.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemArmorPose.java @@ -78,8 +78,7 @@ public void setPropertyValue(MapTag param, Mechanism mechanism) { if (entityNbt == null) { return; } - // TODO: adventure-nbt: contains - if (!(entityNbt.get("Pose") instanceof CompoundBinaryTag)) { + if (!entityNbt.contains("Pose", BinaryTagTypes.COMPOUND)) { return; } entityNbt = entityNbt.remove("Pose"); diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java index 719addec44..578cc1526c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java @@ -153,11 +153,10 @@ public static CompoundBinaryTag compoundOrEmpty(CompoundBinaryTag compoundTag) { public static BinaryTag convertObjectToNbt(ObjectTag inputObject, TagContext context, String path) { if (inputObject.canBeType(MapTag.class)) { MapTag map = inputObject.asType(MapTag.class, context); - // TODO: adventure-nbt: builders initial size - Map result = new HashMap<>(map.size()); + CompoundBinaryTag.Builder resultBuilder = CompoundBinaryTag.builder(map.size()); for (Map.Entry entry : map.entrySet()) { try { - result.put(entry.getKey().str, convertObjectToNbt(entry.getValue(), context, path + "." + entry.getKey().str)); + resultBuilder.put(entry.getKey().str, convertObjectToNbt(entry.getValue(), context, path + "." + entry.getKey().str)); } catch (Exception ex) { Debug.echoError("Object NBT interpretation failed for key '" + path + "." + entry.getKey().str + "'."); @@ -165,15 +164,14 @@ public static BinaryTag convertObjectToNbt(ObjectTag inputObject, TagContext con return null; } } - return CompoundBinaryTag.from(result); + return resultBuilder.build(); } else if (!HAS_NBT_LIST_TYPES && inputObject.shouldBeType(ListTag.class)) { ListTag list = inputObject.asType(ListTag.class, context); - // TODO: adventure-nbt: builders initial size - List result = new ArrayList<>(list.size()); + ListBinaryTag.Builder resultBuilder = ListBinaryTag.heterogeneousListBinaryTag(list.size()); for (int i = 0; i < list.size(); i++) { try { - result.add(convertObjectToNbt(list.getObject(i), context, path + '[' + i + ']')); + resultBuilder.add(convertObjectToNbt(list.getObject(i), context, path + '[' + i + ']')); } catch (Exception ex) { Debug.echoError("Object NBT interpretation failed for list key '" + path + "' at index " + i + '.'); @@ -181,7 +179,7 @@ else if (!HAS_NBT_LIST_TYPES && inputObject.shouldBeType(ListTag.class)) { return null; } } - return ListBinaryTag.listBinaryTag(BinaryTagTypes.LIST_WILDCARD, result); + return resultBuilder.build(); } String input = inputObject.identify(); if (input.equals("end")) { diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/SpongeSchematicHelper.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/SpongeSchematicHelper.java index 1740d8d6de..be27810e69 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/SpongeSchematicHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/SpongeSchematicHelper.java @@ -63,8 +63,7 @@ public static CuboidBlockSet fromSpongeStream(InputStream is) { throw new Exception("Tag 'Schematic' does not exist or is not first!"); } CompoundBinaryTag schematic = rootTag.getValue(); - // TODO: adventure-nbt: compound tag contains - if (schematic.keySet().contains("DenizenEntities")) { + if (schematic.contains("DenizenEntities")) { String entities = stringifyTag(schematic.get("DenizenEntities")); cbs.entities = ListTag.valueOf(entities, CoreUtilities.errorButNoDebugContext); } @@ -74,7 +73,7 @@ public static CuboidBlockSet fromSpongeStream(InputStream is) { int originX = 0; int originY = 0; int originZ = 0; - if (schematic.keySet().contains("DenizenOffset")) { + if (schematic.contains("DenizenOffset")) { // Note: "Offset" contains complete nonsense from WE, so just don't touch it. int[] offsetArr = getChildTag(schematic, "DenizenOffset", BinaryTagTypes.INT_ARRAY).value(); originX = offsetArr[0]; @@ -122,7 +121,7 @@ public static CuboidBlockSet fromSpongeStream(InputStream is) { } } Map tileEntitiesMap = new HashMap<>(); - if (schematic.keySet().contains("BlockEntities")) { + if (schematic.contains("BlockEntities")) { ListBinaryTag tileEntities = getChildTag(schematic, "BlockEntities", BinaryTagTypes.LIST); for (BinaryTag tag : tileEntities) { if (!(tag instanceof CompoundBinaryTag compoundTag)) { @@ -165,7 +164,7 @@ public static CuboidBlockSet fromSpongeStream(InputStream is) { cbs.blocks[cbsIndex] = block; index++; } - if (schematic.keySet().contains("DenizenFlags")) { + if (schematic.contains("DenizenFlags")) { CompoundBinaryTag flags = getChildTag(schematic, "DenizenFlags", BinaryTagTypes.COMPOUND); for (Map.Entry flagData : flags) { int flagIndex = Integer.parseInt(flagData.getKey()); diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/nbt/CustomNBT.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/nbt/CustomNBT.java index f537851002..96b26865cd 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/nbt/CustomNBT.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/nbt/CustomNBT.java @@ -43,7 +43,7 @@ public static List getNBTMaterials(ItemStack itemStack, String key) { } CompoundBinaryTag compoundTag = NMSHandler.itemHelper.getNbtData(itemStack); List materials = new ArrayList<>(); - if (compoundTag.keySet().contains(key)) { + if (compoundTag.contains(key)) { ListBinaryTag temp = compoundTag.getList(key, BinaryTagTypes.STRING); for (BinaryTag tag : temp) { materials.add(Material.matchMaterial(((StringBinaryTag) tag).value())); @@ -114,7 +114,7 @@ public static boolean hasCustomNBT(ItemStack itemStack, String key, String basek if (customData == null) { return false; } - return customData.getCompound(basekey).keySet().contains(CoreUtilities.toLowerCase(key)); + return customData.getCompound(basekey).contains(CoreUtilities.toLowerCase(key)); } public static String getCustomNBT(ItemStack itemStack, String key, String basekey) { diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/NBTAdapter.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/NBTAdapter.java index 01124e496a..4d335032cf 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/NBTAdapter.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/NBTAdapter.java @@ -103,10 +103,9 @@ else if (nmsTag instanceof EndTag) { } public static ListBinaryTag toAPI(ListTag nmsListTag) { - // TODO: adventure-nbt: builder initial capacity - ListBinaryTag.Builder builder = ListBinaryTag.builder(); - for (Tag nmsEntry : nmsListTag) { - builder.add(toAPI(nmsEntry)); + ListBinaryTag.Builder builder = ListBinaryTag.builder(nmsListTag.size()); + for (Tag nmsValue : nmsListTag) { + builder.add(toAPI(nmsValue)); } return builder.build(); } @@ -120,11 +119,11 @@ public static ListTag toNMS(ListBinaryTag listTag) { } public static CompoundBinaryTag toAPI(CompoundTag nmsCompoundTag) { - Map tags = new HashMap<>(nmsCompoundTag.size()); + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(nmsCompoundTag.size()); for (String key : nmsCompoundTag.getAllKeys()) { - tags.put(key, toAPI(nmsCompoundTag.get(key))); + builder.put(key, toAPI(nmsCompoundTag.get(key))); } - return CompoundBinaryTag.from(tags); + return builder.build(); } public static CompoundTag toNMS(CompoundBinaryTag compoundTag) { diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/NBTAdapter.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/NBTAdapter.java index 7fb6cc6c87..5ee7e4c17e 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/NBTAdapter.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/NBTAdapter.java @@ -103,10 +103,9 @@ else if (nmsTag instanceof EndTag) { } public static ListBinaryTag toAPI(ListTag nmsListTag) { - // TODO: adventure-nbt: builder initial capacity - ListBinaryTag.Builder builder = ListBinaryTag.builder(); - for (Tag nmsEntry : nmsListTag) { - builder.add(toAPI(nmsEntry)); + ListBinaryTag.Builder builder = ListBinaryTag.builder(nmsListTag.size()); + for (Tag nmsValue : nmsListTag) { + builder.add(toAPI(nmsValue)); } return builder.build(); } @@ -120,11 +119,11 @@ public static ListTag toNMS(ListBinaryTag listTag) { } public static CompoundBinaryTag toAPI(CompoundTag nmsCompoundTag) { - Map tags = new HashMap<>(nmsCompoundTag.size()); + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(nmsCompoundTag.size()); for (String key : nmsCompoundTag.getAllKeys()) { - tags.put(key, toAPI(nmsCompoundTag.get(key))); + builder.put(key, toAPI(nmsCompoundTag.get(key))); } - return CompoundBinaryTag.from(tags); + return builder.build(); } public static CompoundTag toNMS(CompoundBinaryTag compoundTag) { diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/NBTAdapter.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/NBTAdapter.java index 0486d9beba..470d0cba60 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/NBTAdapter.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/NBTAdapter.java @@ -103,10 +103,9 @@ else if (nmsTag instanceof EndTag) { } public static ListBinaryTag toAPI(ListTag nmsListTag) { - // TODO: adventure-nbt: builder initial capacity - ListBinaryTag.Builder builder = ListBinaryTag.builder(); - for (Tag nmsEntry : nmsListTag) { - builder.add(toAPI(nmsEntry)); + ListBinaryTag.Builder builder = ListBinaryTag.builder(nmsListTag.size()); + for (Tag nmsValue : nmsListTag) { + builder.add(toAPI(nmsValue)); } return builder.build(); } @@ -120,11 +119,11 @@ public static ListTag toNMS(ListBinaryTag listTag) { } public static CompoundBinaryTag toAPI(CompoundTag nmsCompoundTag) { - Map tags = new HashMap<>(nmsCompoundTag.size()); + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(nmsCompoundTag.size()); for (String key : nmsCompoundTag.getAllKeys()) { - tags.put(key, toAPI(nmsCompoundTag.get(key))); + builder.put(key, toAPI(nmsCompoundTag.get(key))); } - return CompoundBinaryTag.from(tags); + return builder.build(); } public static CompoundTag toNMS(CompoundBinaryTag compoundTag) { diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/ItemHelperImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/ItemHelperImpl.java index cc304f59b4..bbe86f9fb8 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/ItemHelperImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/ItemHelperImpl.java @@ -315,8 +315,7 @@ public CompoundBinaryTag getEntityData(ItemStack item) { @Override public ItemStack setEntityData(ItemStack item, CompoundBinaryTag entityNbt, EntityType entityType) { CompoundTag nmsEntityNbt = EMPTY_TAG; - // TODO: adventure-nbt: contains - if (entityNbt != null && !entityNbt.isEmpty() && (!entityNbt.keySet().contains("id") || entityNbt.size() > 1)) { + if (entityNbt != null && !entityNbt.isEmpty() && (!entityNbt.contains("id") || entityNbt.size() > 1)) { nmsEntityNbt = NBTAdapter.toNMS(entityNbt); nmsEntityNbt.putString("id", entityType.getKey().toString()); } diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/NBTAdapter.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/NBTAdapter.java index c284a1c859..32664fb8d3 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/NBTAdapter.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/NBTAdapter.java @@ -105,10 +105,9 @@ else if (nmsTag instanceof EndTag) { } public static ListBinaryTag toAPI(ListTag nmsListTag) { - // TODO: adventure-nbt: builder initial capacity - ListBinaryTag.Builder builder = ListBinaryTag.builder(); - for (Tag nmsEntry : nmsListTag) { - builder.add(toAPI(nmsEntry)); + ListBinaryTag.Builder builder = ListBinaryTag.builder(nmsListTag.size()); + for (Tag nmsValue : nmsListTag) { + builder.add(toAPI(nmsValue)); } return builder.build(); } @@ -122,11 +121,11 @@ public static ListTag toNMS(ListBinaryTag listTag) { } public static CompoundBinaryTag toAPI(CompoundTag nmsCompoundTag) { - Map tags = new HashMap<>(nmsCompoundTag.size()); + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(nmsCompoundTag.size()); for (String key : nmsCompoundTag.getAllKeys()) { - tags.put(key, toAPI(nmsCompoundTag.get(key))); + builder.put(key, toAPI(nmsCompoundTag.get(key))); } - return CompoundBinaryTag.from(tags); + return builder.build(); } public static CompoundTag toNMS(CompoundBinaryTag compoundTag) { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java index 86b815add7..cd0972113a 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java @@ -426,7 +426,7 @@ public CompoundBinaryTag getEntityData(ItemStack item) { @Override public ItemStack setEntityData(ItemStack item, CompoundBinaryTag entityNbt, EntityType entityType) { net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); - if (entityNbt == null || entityNbt.isEmpty() || (entityNbt.size() == 1 && entityNbt.keySet().contains("id"))) { + if (entityNbt == null || entityNbt.isEmpty() || (entityNbt.size() == 1 && entityNbt.contains("id"))) { nmsItemStack.remove(DataComponents.ENTITY_DATA); } else { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/NBTAdapter.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/NBTAdapter.java index fd6bf645f5..427e1a62b3 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/NBTAdapter.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/NBTAdapter.java @@ -105,11 +105,11 @@ else if (nmsTag instanceof EndTag) { } public static ListBinaryTag toAPI(ListTag nmsListTag) { - List tags = new ArrayList<>(nmsListTag.size()); + ListBinaryTag.Builder builder = ListBinaryTag.heterogeneousListBinaryTag(nmsListTag.size()); for (Tag nmsValue : nmsListTag) { - tags.add(toAPI(nmsValue)); + builder.add(toAPI(nmsValue)); } - return ListBinaryTag.listBinaryTag(BinaryTagTypes.LIST_WILDCARD, tags); + return builder.build(); } public static ListTag toNMS(ListBinaryTag listTag) { @@ -121,11 +121,11 @@ public static ListTag toNMS(ListBinaryTag listTag) { } public static CompoundBinaryTag toAPI(CompoundTag nmsCompoundTag) { - Map tags = new HashMap<>(nmsCompoundTag.size()); + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(nmsCompoundTag.size()); for (Map.Entry nmsEntry : nmsCompoundTag.entrySet()) { - tags.put(nmsEntry.getKey(), toAPI(nmsEntry.getValue())); + builder.put(nmsEntry.getKey(), toAPI(nmsEntry.getValue())); } - return CompoundBinaryTag.from(tags); + return builder.build(); } public static CompoundTag toNMS(CompoundBinaryTag compoundTag) { From afba41b0fcbaa60ea92d03fd9c8027a284042e6e Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Mon, 12 Jan 2026 21:55:10 +0100 Subject: [PATCH 061/169] `WorldTag.respawn_dragon`: workaround API bug (#2804) * fix * fix --- .../java/com/denizenscript/denizen/objects/WorldTag.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java index 631a9a9090..e6690210cc 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/WorldTag.java @@ -1096,7 +1096,12 @@ else if (time >= 12500) { mechanism.echoError("Provided world is not an end world!"); return; } - battle.initiateRespawn(); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { // workaround for upstream bug + battle.initiateRespawn(List.of()); + } + else { + battle.initiateRespawn(); + } }); // <--[mechanism] From 065417a0413bbf982627545222ecc214af52cc53 Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Mon, 12 Jan 2026 23:15:50 +0100 Subject: [PATCH 062/169] `title` command: update to modern format (#2797) * update * add remapped prefixes * list of * tostring * cleanup * OOPS --- .../scripts/commands/player/TitleCommand.java | 116 ++++++------------ 1 file changed, 38 insertions(+), 78 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/TitleCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/TitleCommand.java index b503b62aa7..21ddb49a67 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/TitleCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/TitleCommand.java @@ -2,19 +2,16 @@ import com.denizenscript.denizen.tags.BukkitTagContext; import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizencore.scripts.commands.generator.*; +import com.denizenscript.denizencore.tags.ParseableTag; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; -import com.denizenscript.denizencore.objects.*; import com.denizenscript.denizencore.objects.core.DurationTag; -import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.commands.AbstractCommand; import com.denizenscript.denizencore.tags.TagManager; -import java.util.Collections; import java.util.List; public class TitleCommand extends AbstractCommand { @@ -23,8 +20,9 @@ public TitleCommand() { setName("title"); setSyntax("title (title:) (subtitle:) (fade_in:/{1s}) (stay:/{3s}) (fade_out:/{1s}) (targets:|...) (per_player)"); setRequiredArguments(1, 7); - setParseArgs(false); + addRemappedPrefixes("targets", "target"); isProcedural = false; + autoCompile(); } // <--[command] @@ -58,83 +56,45 @@ public TitleCommand() { // - title "title:Tatooine" "subtitle:What a desolate place this is." // --> - @Override - public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { - for (Argument arg : ArgumentHelper.interpret(scriptEntry, scriptEntry.getOriginalArguments())) { - if (arg.matchesPrefix("title")) { - scriptEntry.addObject("title", arg.asElement()); - } - else if (arg.matchesPrefix("subtitle")) { - scriptEntry.addObject("subtitle", arg.asElement()); - } - else if (arg.matchesPrefix("fade_in")) { - String argStr = TagManager.tag(arg.getValue(), scriptEntry.getContext()); - scriptEntry.addObject("fade_in", DurationTag.valueOf(argStr, scriptEntry.context)); - } - else if (arg.matchesPrefix("stay")) { - String argStr = TagManager.tag(arg.getValue(), scriptEntry.getContext()); - scriptEntry.addObject("stay", DurationTag.valueOf(argStr, scriptEntry.context)); - } - else if (arg.matchesPrefix("fade_out")) { - String argStr = TagManager.tag(arg.getValue(), scriptEntry.getContext()); - scriptEntry.addObject("fade_out", DurationTag.valueOf(argStr, scriptEntry.context)); - } - else if (arg.matchesPrefix("targets", "target")) { - scriptEntry.addObject("targets", ListTag.getListFor(TagManager.tagObject(arg.getValue(), scriptEntry.getContext()), scriptEntry.getContext()).filter(PlayerTag.class, scriptEntry)); + public static void autoExecute(ScriptEntry scriptEntry, + @ArgName("title") @ArgPrefixed @ArgUnparsed @ArgDefaultNull String strTitle, + @ArgName("subtitle") @ArgPrefixed @ArgUnparsed @ArgDefaultNull String strSubTitle, + @ArgName("fade_in") @ArgPrefixed @ArgDefaultText("1s") DurationTag fadeIn, + @ArgName("stay") @ArgPrefixed @ArgDefaultText("3s") DurationTag stay, + @ArgName("fade_out") @ArgPrefixed @ArgDefaultText("1s") DurationTag fadeOut, + @ArgName("targets") @ArgPrefixed @ArgDefaultNull @ArgSubType(PlayerTag.class) List players, + @ArgName("per_player") boolean perPlayer) { + if (strTitle == null && strSubTitle == null) { + Debug.echoError("Must have a title or subtitle!"); + return; + } + if (players == null) { + if (!Utilities.entryHasPlayer(scriptEntry)) { + Debug.echoError("Must specify target(s)."); + return; } - else if (!scriptEntry.hasObject("per_player") - && arg.matches("per_player")) { - scriptEntry.addObject("per_player", new ElementTag(true)); + players = List.of(Utilities.getEntryPlayer(scriptEntry)); + } + BukkitTagContext context = perPlayer ? new BukkitTagContext((BukkitTagContext) scriptEntry.getContext()) : (BukkitTagContext) scriptEntry.getContext(); + ParseableTag parseableTitle = TagManager.parseTextToTag(strTitle, context); + ParseableTag parseableSubTitle = TagManager.parseTextToTag(strSubTitle, context); + String parsedTitle = perPlayer ? null : parse(parseableTitle, context); + String parsedSubTitle = perPlayer ? null : parse(parseableSubTitle, context); + for (PlayerTag player : players) { + if (!player.isOnline()) { + Debug.echoDebug(scriptEntry, "Player is offline, can't send title to them. Skipping."); + continue; } - else { - arg.reportUnhandled(); + if (perPlayer) { + context.player = player; + parsedTitle = parse(parseableTitle, context); + parsedSubTitle = parse(parseableSubTitle, context); } + NMSHandler.packetHelper.showTitle(player.getPlayerEntity(), parsedTitle, parsedSubTitle, fadeIn.getTicksAsInt(), stay.getTicksAsInt(), fadeOut.getTicksAsInt()); } - if (!scriptEntry.hasObject("title") && !scriptEntry.hasObject("subtitle")) { - throw new InvalidArgumentsException("Must have a title or subtitle!"); - } - scriptEntry.defaultObject("fade_in", new DurationTag(1)).defaultObject("stay", new DurationTag(3)) - .defaultObject("fade_out", new DurationTag(1)) - .defaultObject("targets", Collections.singletonList(Utilities.getEntryPlayer(scriptEntry))) - .defaultObject("subtitle", new ElementTag("")).defaultObject("title", new ElementTag("")); } - @Override - public void execute(ScriptEntry scriptEntry) { - String title = scriptEntry.getElement("title").asString(); - String subtitle = scriptEntry.getElement("subtitle").asString(); - DurationTag fade_in = scriptEntry.getObjectTag("fade_in"); - DurationTag stay = scriptEntry.getObjectTag("stay"); - DurationTag fade_out = scriptEntry.getObjectTag("fade_out"); - List targets = (List) scriptEntry.getObject("targets"); - ElementTag perPlayerObj = scriptEntry.getElement("per_player"); - boolean perPlayer = perPlayerObj != null && perPlayerObj.asBoolean(); - BukkitTagContext context = (BukkitTagContext) scriptEntry.getContext(); - if (!perPlayer) { - title = TagManager.tag(title, context); - subtitle = TagManager.tag(subtitle, context); - } - if (scriptEntry.dbCallShouldDebug()) { - Debug.report(scriptEntry, getName(), db("title", title), db("subtitle", subtitle), fade_in, stay, fade_out, db("targets", targets), perPlayerObj); - } - for (PlayerTag player : targets) { - if (player != null) { - if (!player.isOnline()) { - Debug.echoDebug(scriptEntry, "Player is offline, can't send title to them. Skipping."); - continue; - } - String personalTitle = title; - String personalSubtitle = subtitle; - if (perPlayer) { - context.player = player; - personalTitle = TagManager.tag(personalTitle, context); - personalSubtitle = TagManager.tag(personalSubtitle, context); - } - NMSHandler.packetHelper.showTitle(player.getPlayerEntity(), personalTitle, personalSubtitle, fade_in.getTicksAsInt(), stay.getTicksAsInt(), fade_out.getTicksAsInt()); - } - else { - Debug.echoError("Sent title to non-existent player!?"); - } - } + public static String parse(ParseableTag tag, BukkitTagContext context) { + return tag == null ? null : tag.parse(context).toString(); } } From ee236cf3d6c22571a07861be2e7ebee6b12e7d89 Mon Sep 17 00:00:00 2001 From: Remasuri <46802109+Remasuri@users.noreply.github.com> Date: Tue, 13 Jan 2026 01:43:18 +0100 Subject: [PATCH 063/169] `player prepares item enchant`: null entries fix (#2799) * Fix for null entries in PlayerPreparesEnchantScriptEvent * Fix for null entries in PlayerPreparesEnchantScriptEvent * Formatting fix * Added a space at if-statement for formatting purposes --- .../events/player/PlayerPreparesEnchantScriptEvent.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerPreparesEnchantScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerPreparesEnchantScriptEvent.java index af97ebd94b..f6a75c4125 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerPreparesEnchantScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerPreparesEnchantScriptEvent.java @@ -77,6 +77,10 @@ public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { } for (int i = 0; i < offers.size(); i++) { MapTag map = MapTag.getMapFor(offers.getObject(i), getTagContext(path)); + if (map.isEmpty()) { + event.getOffers()[i] = null; + continue; + } event.getOffers()[i].setCost(map.getElement("cost").asInt()); EnchantmentTag enchantment = map.getObjectAs("enchantment_type", EnchantmentTag.class, getTagContext(path)); if (enchantment == null) { @@ -108,6 +112,10 @@ public ObjectTag getContext(String name) { case "offers": ListTag output = new ListTag(); for (EnchantmentOffer offer : event.getOffers()) { + if (offer == null) { + output.addObject(new MapTag()); + continue; + } MapTag map = new MapTag(); map.putObject("cost", new ElementTag(offer.getCost())); map.putObject("enchantment", new ElementTag(offer.getEnchantment().getKey().getKey())); From 2322fb10cbc354a82c67f2570b65daa4c642ca47 Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Tue, 13 Jan 2026 22:38:38 +0100 Subject: [PATCH 064/169] `title` command: avoid null values, packet cleanup (#2806) * fix * fix v2 --- .../scripts/commands/player/TitleCommand.java | 2 +- .../denizen/nms/v1_21/helpers/PacketHelperImpl.java | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/TitleCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/TitleCommand.java index 21ddb49a67..0e85ea309f 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/TitleCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/TitleCommand.java @@ -95,6 +95,6 @@ public static void autoExecute(ScriptEntry scriptEntry, } public static String parse(ParseableTag tag, BukkitTagContext context) { - return tag == null ? null : tag.parse(context).toString(); + return tag == null ? "" : tag.parse(context).toString(); } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java index 91c60ce77e..de8b320707 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java @@ -159,13 +159,11 @@ public void showTabListHeaderFooter(Player player, String header, String footer) @Override public void showTitle(Player player, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { - send(player, new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks)); - if (title != null) { - send(player, new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)))); - } - if (subtitle != null) { - send(player, new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE)))); - } + send(player, new ClientboundBundlePacket(List.of( + new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks), + new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE))), + new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE))) + ))); } @Override From df5cff6098a9079278a8247a6a9f59397f5a4c1e Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Tue, 13 Jan 2026 17:30:03 -0800 Subject: [PATCH 065/169] `EntityTag.variant`: zombie nautilus support (#2801) * Added Zombie Nautiluses to the EntityTag.variant property * space --- .../objects/properties/entity/EntityVariant.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityVariant.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityVariant.java index f97f758b57..5b50f1c822 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityVariant.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityVariant.java @@ -35,12 +35,13 @@ public class EntityVariant extends EntityProperty { // @name variant // @input ElementTag // @description - // Controls which variant a chicken, copper golem, cow, pig, or wolf is. + // Controls which variant a chicken, copper golem, cow, pig, wolf, or zombie nautilus is. // A list of valid chicken variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Chicken.Variant.html>. // A list of valid copper golem variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/CopperGolem.CopperWeatherState.html>. // A list of valid cow variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Cow.Variant.html>. // A list of valid pig variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Pig.Variant.html>. // A list of valid wolf variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Wolf.Variant.html>. + // A list of valid zombie nautilus variants can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/ZombieNautilus.Variant.html>. // --> public static boolean describes(EntityTag entityTag) { @@ -49,7 +50,8 @@ public static boolean describes(EntityTag entityTag) { || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && (entity instanceof Chicken || entity instanceof CopperGolem || entity instanceof Cow - || entity instanceof Pig)); + || entity instanceof Pig + || entity instanceof ZombieNautilus)); } @Override @@ -76,6 +78,9 @@ else if (COW_GET_VARIANT != null && getEntity() instanceof Cow cow) { else if (getEntity() instanceof Pig pig) { return new ElementTag(Utilities.namespacedKeyToString(pig.getVariant().getKey()), true); } + else if (getEntity() instanceof ZombieNautilus zombieNautilus) { + return new ElementTag(Utilities.namespacedKeyToString(zombieNautilus.getVariant().getKey()), true); + } } return null; } @@ -115,6 +120,12 @@ else if (getEntity() instanceof Pig pig) { pig.setVariant(pigVariant); } } + else if (getEntity() instanceof ZombieNautilus zombieNautilus) { + ZombieNautilus.Variant zombieNautilusVariant = Utilities.elementToRequiredEnumLike(variant, ZombieNautilus.Variant.class, mechanism); + if (zombieNautilusVariant != null) { + zombieNautilus.setVariant(zombieNautilusVariant); + } + } } } From 1932e42152a0101e6a05496312375879ef0025d8 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 16 Jan 2026 12:43:11 +0000 Subject: [PATCH 066/169] `BlockProperty#as(Type)` util method --- .../denizen/objects/properties/material/MaterialProperty.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialProperty.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialProperty.java index 4cbb516800..2f6046bbe2 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialProperty.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialProperty.java @@ -17,4 +17,8 @@ public MaterialProperty(MaterialTag material) { public BlockData getBlockData() { return object.getModernData(); } + + public T as(Class dataType) { + return (T) getBlockData(); + } } From e6d312354c8a6514a2987120433614f2b33bbdf0 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:10:37 +0000 Subject: [PATCH 067/169] `item_enchanted:` namespace matching support --- .../main/java/com/denizenscript/denizen/objects/ItemTag.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/ItemTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/ItemTag.java index f6143fa045..87b2d98b98 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/ItemTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/ItemTag.java @@ -856,12 +856,13 @@ public boolean advancedMatches(String matcher, TagContext context) { return BukkitScriptEvent.coreFlaggedCheck(matcher.substring("item_flagged:".length()), getFlagTracker()); } else if (matcherLow.startsWith("item_enchanted:")) { - String enchMatcher = matcher.substring("item_enchanted:".length()); + String enchMatcherStr = matcher.substring("item_enchanted:".length()); if (getBukkitMaterial().isAir() || !getItemMeta().hasEnchants()) { return false; } + ScriptEvent.MatchHelper enchMatcher = ScriptEvent.createMatcher(enchMatcherStr); for (Enchantment enchant : getItemMeta().getEnchants().keySet()) { - if (BukkitScriptEvent.runGenericCheck(enchMatcher, enchant.getKey().getKey())) { + if (enchMatcher.doesMatch(enchant.getKey().getKey()) || enchMatcher.doesMatch(enchant.getKey().toString())) { return true; } } From 0eca54f964a93b5476d43b47ee57c1e7a8f8ab95 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Sun, 25 Jan 2026 16:34:07 -0800 Subject: [PATCH 068/169] Modernize 10 block events (#2774) * Modernize 11 block events * deprecation date updated * whoops * reworked `matches` section * fixed slight mistake * Minor changes and fixes * slight shortening * CauldronLevelChangeScriptEvent fixes * value checking * minor fixes * minor changes * same context and determination name * fixed * determination fix --- .../block/BrewingStandFueledScriptEvent.java | 56 +++++++------- .../block/CauldronLevelChangeScriptEvent.java | 65 ++++++++++------ .../block/FurnaceBurnsItemScriptEvent.java | 36 +++++---- .../FurnaceStartsSmeltingScriptEvent.java | 35 +++------ .../events/block/LeafDecaysScriptEvent.java | 10 +-- .../block/LiquidLevelChangeScriptEvent.java | 12 +-- .../block/NoteBlockPlaysNoteScriptEvent.java | 74 ++++++++----------- .../block/PistonExtendsScriptEvent.java | 27 +++---- .../block/PistonRetractsScriptEvent.java | 27 +++---- .../events/block/RedstoneScriptEvent.java | 31 ++++---- .../utilities/BukkitImplDeprecations.java | 3 + 11 files changed, 174 insertions(+), 202 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/BrewingStandFueledScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/BrewingStandFueledScriptEvent.java index cc6732dceb..8c1a68708e 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/BrewingStandFueledScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/BrewingStandFueledScriptEvent.java @@ -3,6 +3,7 @@ import com.denizenscript.denizen.events.BukkitScriptEvent; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; import org.bukkit.event.EventHandler; @@ -31,13 +32,30 @@ public class BrewingStandFueledScriptEvent extends BukkitScriptEvent implements // // @Determine // "FUEL_POWER:" to set the fuel power level to be added. - // "CONSUMING" to indicate that the fuel item should be consumed. - // "NOT_CONSUMING" to indicate that the fuel item should not be consumed. + // "CONSUMING:" to indicate whether the fuel item should be consumed. // // --> public BrewingStandFueledScriptEvent() { registerCouldMatcher("brewing stand fueled (with )"); + this.registerOptionalDetermination("fuel_power", ElementTag.class, (evt, context, power) -> { + if (power.isInt()) { + evt.event.setFuelPower(power.asInt()); + return true; + } + return false; + }); + this.registerOptionalDetermination("consuming", ElementTag.class, (evt, context, value) -> { + if (value.isBoolean()) { + evt.event.setConsuming(value.asBoolean()); + return true; + } + return false; + }); + this.registerTextDetermination("not_consuming", (evt) -> { + BukkitImplDeprecations.brewingStandConsumeDetermination.warn(); + evt.event.setConsuming(false); + }); } public LocationTag location; @@ -55,35 +73,15 @@ public boolean matches(ScriptPath path) { return super.matches(path); } - @Override - public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { - if (determinationObj instanceof ElementTag element) { - String val = element.asString(); - if (val.startsWith("fuel_power:")) { - event.setFuelPower(Integer.parseInt(val.substring("fuel_power:".length()))); - return true; - } - else if (val.equalsIgnoreCase("consuming")) { - event.setConsuming(true); - return true; - } - else if (val.equalsIgnoreCase("not_consuming")) { - event.setConsuming(false); - return true; - } - } - return super.applyDetermination(path, determinationObj); - } - @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "item": return item; - case "fuel_power": return new ElementTag(event.getFuelPower()); - case "consuming": return new ElementTag(event.isConsuming()); - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "item" -> item; + case "fuel_power" -> new ElementTag(event.getFuelPower()); + case "consuming" -> new ElementTag(event.isConsuming()); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/CauldronLevelChangeScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/CauldronLevelChangeScriptEvent.java index a6134f62c9..599cc491c1 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/CauldronLevelChangeScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/CauldronLevelChangeScriptEvent.java @@ -5,6 +5,9 @@ import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.Levelled; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.CauldronLevelChangeEvent; @@ -39,10 +42,37 @@ public class CauldronLevelChangeScriptEvent extends BukkitScriptEvent implements public CauldronLevelChangeScriptEvent() { registerCouldMatcher("cauldron level changes|raises|lowers"); registerSwitches("cause"); + this.registerOptionalDetermination(null, ElementTag.class, (evt, context, value) -> { + if (!value.isInt()) { + return false; + } + int level = value.asInt(); + BlockState cauldronState = evt.event.getNewState(); + if (level <= 0) { + cauldronState.setType(Material.CAULDRON); + return true; + } + if (level > 3) { + return false; + } + if (cauldronState.getType() != Material.WATER_CAULDRON && cauldronState.getType() != Material.LAVA_CAULDRON) { + cauldronState.setType(cauldronType); + } + if (cauldronState.getBlockData() instanceof Levelled levelled) { + levelled.setLevel(level); + cauldronState.setBlockData(levelled); + evt.newLevel = level; + return true; + } + return false; + }); } public LocationTag location; public CauldronLevelChangeEvent event; + public Material cauldronType; + public int oldLevel; + public int newLevel; @Override public boolean matches(ScriptPath path) { @@ -54,12 +84,12 @@ public boolean matches(ScriptPath path) { } String changeType = path.eventArgLowerAt(2); if (changeType.equals("raises")) { - if (event.getNewLevel() <= event.getOldLevel()) { + if (newLevel <= oldLevel) { return false; } } else if (changeType.equals("lowers")) { - if (event.getNewLevel() >= event.getOldLevel()) { + if (newLevel >= oldLevel) { return false; } } @@ -69,33 +99,24 @@ else if (!changeType.equals("changes")) { return super.matches(path); } - @Override - public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { - if (determinationObj instanceof ElementTag element && element.isInt()) { - event.setNewLevel(element.asInt()); - } - return super.applyDetermination(path, determinationObj); - } - @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "cause": return new ElementTag(event.getReason()); - case "old_level": return new ElementTag(event.getOldLevel()); - case "new_level": return new ElementTag(event.getNewLevel()); - case "entity": - if (event.getEntity() != null) { - return new EntityTag(event.getEntity()).getDenizenObject(); - } - break; - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "cause" -> new ElementTag(event.getReason()); + case "old_level" -> new ElementTag(oldLevel); + case "new_level" -> new ElementTag(newLevel); + case "entity" -> event.getEntity() != null ? new EntityTag(event.getEntity()).getDenizenObject() : null; + default -> super.getContext(name); + }; } @EventHandler public void onCauldronLevelChange(CauldronLevelChangeEvent event) { location = new LocationTag(event.getBlock().getLocation()); + cauldronType = event.getBlock().getType(); + oldLevel = event.getBlock().getBlockData() instanceof Levelled levelled ? levelled.getLevel() : 0; + newLevel = event.getNewState().getBlockData() instanceof Levelled levelled ? levelled.getLevel() : 0; this.event = event; fire(event); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/FurnaceBurnsItemScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/FurnaceBurnsItemScriptEvent.java index fe34ed02b7..82c69cdf00 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/FurnaceBurnsItemScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/FurnaceBurnsItemScriptEvent.java @@ -35,6 +35,17 @@ public class FurnaceBurnsItemScriptEvent extends BukkitScriptEvent implements Li public FurnaceBurnsItemScriptEvent() { registerCouldMatcher("furnace burns "); + this.registerOptionalDetermination(null, ObjectTag.class, (evt, context, time) -> { + if (time instanceof ElementTag elementTag && elementTag.isInt()) { // Backwards compatibility for non-duration tick input + evt.event.setBurnTime(elementTag.asInt()); + return true; + } + else if (time.canBeType(DurationTag.class)) { + evt.event.setBurnTime(time.asType(DurationTag.class, context).getTicksAsInt()); + return true; + } + return false; + }); } public ItemTag item; @@ -52,30 +63,17 @@ public boolean matches(ScriptPath path) { return super.matches(path); } - @Override - public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { - if (determinationObj instanceof ElementTag element && element.isInt()) { - event.setBurnTime(element.asInt()); - return true; - } - else if (determinationObj.canBeType(DurationTag.class)) { - event.setBurnTime(determinationObj.asType(DurationTag.class, getTagContext(path)).getTicksAsInt()); - return true; - } - return super.applyDetermination(path, determinationObj); - } - @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "item": return item; - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "item" -> item; + default -> super.getContext(name); + }; } @EventHandler - public void onBrews(FurnaceBurnEvent event) { + public void onFurnaceBurns(FurnaceBurnEvent event) { location = new LocationTag(event.getBlock().getLocation()); item = new ItemTag(event.getFuel()); this.event = event; diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/FurnaceStartsSmeltingScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/FurnaceStartsSmeltingScriptEvent.java index 0e4d82c441..498f5f4c72 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/FurnaceStartsSmeltingScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/FurnaceStartsSmeltingScriptEvent.java @@ -31,19 +31,13 @@ public class FurnaceStartsSmeltingScriptEvent extends BukkitScriptEvent implemen // @Determine // DurationTag to set the total cook time for the item being smelted. // - // @Example - // # Sets the total cook time of every item to always be 2 seconds. - // on furnace starts smelting item: - // - determine 2s - // - // @Example - // # Sets the total cook time of iron ore to be 2 seconds. - // on furnace starts smelting iron_ore: - // - determine 2s // --> public FurnaceStartsSmeltingScriptEvent() { registerCouldMatcher("furnace starts smelting "); + this.registerDetermination(null, DurationTag.class, (evt, context, time) -> { + evt.event.setTotalCookTime(time.getTicksAsInt()); + }); } public ItemTag item; @@ -61,24 +55,15 @@ public boolean matches(ScriptPath path) { return super.matches(path); } - @Override - public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { - if (determinationObj.canBeType(DurationTag.class)) { - event.setTotalCookTime(determinationObj.asType(DurationTag.class, getTagContext(path)).getTicksAsInt()); - return true; - } - return super.applyDetermination(path, determinationObj); - } - @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "item": return item; - case "recipe_id": return new ElementTag(event.getRecipe().getKey().toString()); - case "total_cook_time": return new DurationTag((long) event.getTotalCookTime()); - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "item" -> item; + case "recipe_id" -> new ElementTag(event.getRecipe().getKey().toString(), true); + case "total_cook_time" -> new DurationTag((long) event.getTotalCookTime()); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/LeafDecaysScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/LeafDecaysScriptEvent.java index 6d6a4993be..447af73882 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/LeafDecaysScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/LeafDecaysScriptEvent.java @@ -52,11 +52,11 @@ public boolean matches(ScriptPath path) { @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "material": return material; - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "material" -> material; + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/LiquidLevelChangeScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/LiquidLevelChangeScriptEvent.java index d3fdc67897..63d0e1e3c5 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/LiquidLevelChangeScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/LiquidLevelChangeScriptEvent.java @@ -62,12 +62,12 @@ public boolean matches(ScriptPath path) { @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "old_material": return old_material; - case "new_material": return new MaterialTag(event.getNewData()); - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "old_material" -> old_material; + case "new_material" -> new MaterialTag(event.getNewData()); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/NoteBlockPlaysNoteScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/NoteBlockPlaysNoteScriptEvent.java index d0743dc37b..53ab43d02a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/NoteBlockPlaysNoteScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/NoteBlockPlaysNoteScriptEvent.java @@ -62,55 +62,39 @@ public Sound getSound() { if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { return event.getInstrument().getSound(); } - switch (event.getInstrument()) { - case PIANO: - return Sound.BLOCK_NOTE_BLOCK_HARP; - case BASS_DRUM: - return Sound.BLOCK_NOTE_BLOCK_BASEDRUM; - case SNARE_DRUM: - return Sound.BLOCK_NOTE_BLOCK_SNARE; - case STICKS: - return Sound.BLOCK_NOTE_BLOCK_HAT; - case BASS_GUITAR: - return Sound.BLOCK_NOTE_BLOCK_BASS; - case FLUTE: - return Sound.BLOCK_NOTE_BLOCK_FLUTE; - case BELL: - return Sound.BLOCK_NOTE_BLOCK_BELL; - case GUITAR: - return Sound.BLOCK_NOTE_BLOCK_GUITAR; - case CHIME: - return Sound.BLOCK_NOTE_BLOCK_CHIME; - case XYLOPHONE: - return Sound.BLOCK_NOTE_BLOCK_XYLOPHONE; - case IRON_XYLOPHONE: - return Sound.BLOCK_NOTE_BLOCK_IRON_XYLOPHONE; - case COW_BELL: - return Sound.BLOCK_NOTE_BLOCK_COW_BELL; - case DIDGERIDOO: - return Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO; - case BIT: - return Sound.BLOCK_NOTE_BLOCK_BIT; - case BANJO: - return Sound.BLOCK_NOTE_BLOCK_BANJO; - case PLING: - return Sound.BLOCK_NOTE_BLOCK_PLING; - } - return null; + return switch (event.getInstrument()) { + case PIANO -> Sound.BLOCK_NOTE_BLOCK_HARP; + case BASS_DRUM -> Sound.BLOCK_NOTE_BLOCK_BASEDRUM; + case SNARE_DRUM -> Sound.BLOCK_NOTE_BLOCK_SNARE; + case STICKS -> Sound.BLOCK_NOTE_BLOCK_HAT; + case BASS_GUITAR -> Sound.BLOCK_NOTE_BLOCK_BASS; + case FLUTE -> Sound.BLOCK_NOTE_BLOCK_FLUTE; + case BELL -> Sound.BLOCK_NOTE_BLOCK_BELL; + case GUITAR -> Sound.BLOCK_NOTE_BLOCK_GUITAR; + case CHIME -> Sound.BLOCK_NOTE_BLOCK_CHIME; + case XYLOPHONE -> Sound.BLOCK_NOTE_BLOCK_XYLOPHONE; + case IRON_XYLOPHONE -> Sound.BLOCK_NOTE_BLOCK_IRON_XYLOPHONE; + case COW_BELL -> Sound.BLOCK_NOTE_BLOCK_COW_BELL; + case DIDGERIDOO -> Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO; + case BIT -> Sound.BLOCK_NOTE_BLOCK_BIT; + case BANJO -> Sound.BLOCK_NOTE_BLOCK_BANJO; + case PLING -> Sound.BLOCK_NOTE_BLOCK_PLING; + default -> null; + }; } @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "instrument": return new ElementTag(event.getInstrument()); - case "sound": return Utilities.enumLikeToLegacyElement(getSound()); - case "tone": return new ElementTag(event.getNote().getTone()); - case "octave": return new ElementTag(event.getNote().getOctave()); - case "sharp": return new ElementTag(event.getNote().isSharped()); - case "pitch": return new ElementTag(Math.pow(2.0, (double) (event.getNote().getId() - 12) / 12.0)); // based on minecraft source - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "instrument" -> new ElementTag(event.getInstrument()); + case "sound" -> Utilities.enumLikeToLegacyElement(getSound()); + case "tone" -> new ElementTag(event.getNote().getTone()); + case "octave" -> new ElementTag(event.getNote().getOctave()); + case "sharp" -> new ElementTag(event.getNote().isSharped()); + case "pitch" -> new ElementTag(Math.pow(2.0, (double) (event.getNote().getId() - 12) / 12.0)); // based on minecraft source + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/PistonExtendsScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/PistonExtendsScriptEvent.java index f544ce7200..eaf1dccd83 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/PistonExtendsScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/PistonExtendsScriptEvent.java @@ -6,7 +6,6 @@ import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.objects.ObjectTag; -import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPistonExtendEvent; @@ -59,22 +58,16 @@ public boolean matches(ScriptPath path) { @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "material": return material; - case "sticky": return new ElementTag(event.isSticky()); - case "direction": return new LocationTag(event.getDirection().getDirection()); - case "relative": return new LocationTag(event.getBlock().getRelative(event.getDirection()).getLocation()); // Silently deprecated - case "blocks": { - ListTag blocks = new ListTag(); - for (Block block : event.getBlocks()) { - blocks.addObject(new LocationTag(block.getLocation())); - } - return blocks; - } - case "length": return new ElementTag(event.getBlocks().size()); - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "material" -> material; + case "sticky" -> new ElementTag(event.isSticky()); + case "direction" -> new LocationTag(event.getDirection().getDirection()); + case "relative" -> new LocationTag(event.getBlock().getRelative(event.getDirection()).getLocation()); // Silently deprecated + case "blocks" -> new ListTag(event.getBlocks(), block -> new LocationTag(block.getLocation())); + case "length" -> new ElementTag(event.getBlocks().size()); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/PistonRetractsScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/PistonRetractsScriptEvent.java index 88ae3d2a0a..f048b60963 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/PistonRetractsScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/PistonRetractsScriptEvent.java @@ -6,7 +6,6 @@ import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.objects.ObjectTag; -import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPistonRetractEvent; @@ -59,22 +58,16 @@ public boolean matches(ScriptPath path) { @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "material": return material; - case "sticky": return new ElementTag(event.isSticky()); - case "direction": return new LocationTag(event.getDirection().getDirection()); - case "relative": return new LocationTag(event.getBlock().getRelative(event.getDirection().getOppositeFace()).getLocation()); // Silently deprecated - case "blocks": { - ListTag blocks = new ListTag(); - for (Block block : event.getBlocks()) { - blocks.addObject(new LocationTag(block.getLocation())); - } - return blocks; - } - case "retract_location": return new LocationTag(event.getBlock().getRelative(event.getDirection().getOppositeFace(), 2).getLocation()); - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "material" -> material; + case "sticky" -> new ElementTag(event.isSticky()); + case "direction" -> new LocationTag(event.getDirection().getDirection()); + case "relative" -> new LocationTag(event.getBlock().getRelative(event.getDirection().getOppositeFace()).getLocation()); // Silently deprecated + case "blocks" -> new ListTag(event.getBlocks(), block -> new LocationTag(block.getLocation())); + case "retract_location" -> new LocationTag(event.getBlock().getRelative(event.getDirection().getOppositeFace(), 2).getLocation()); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/RedstoneScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/RedstoneScriptEvent.java index be845be4ae..ccc981d329 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/RedstoneScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/RedstoneScriptEvent.java @@ -28,15 +28,21 @@ public class RedstoneScriptEvent extends BukkitScriptEvent implements Listener { // returns what the redstone power level is becoming. // // @Determine - // ElementTag (Number) set the current value to a specific value. + // ElementTag(Number) set the current value to a specific value. // // --> public RedstoneScriptEvent() { registerCouldMatcher("redstone recalculated"); + this.registerOptionalDetermination(null, ElementTag.class, (evt, context, power) -> { + if (power.isInt()) { + evt.event.setNewCurrent(power.asInt()); + return true; + } + return false; + }); } - public LocationTag location; public BlockRedstoneEvent event; @@ -48,23 +54,14 @@ public boolean matches(ScriptPath path) { return super.matches(path); } - @Override - public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { - if (determinationObj instanceof ElementTag element && element.isInt()) { - event.setNewCurrent(element.asInt()); - return true; - } - return super.applyDetermination(path, determinationObj); - } - @Override public ObjectTag getContext(String name) { - switch (name) { - case "location": return location; - case "old_current": return new ElementTag(event.getOldCurrent()); - case "new_current": return new ElementTag(event.getNewCurrent()); - } - return super.getContext(name); + return switch (name) { + case "location" -> location; + case "old_current" -> new ElementTag(event.getOldCurrent()); + case "new_current" -> new ElementTag(event.getNewCurrent()); + default -> super.getContext(name); + }; } @EventHandler diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java index 50ef530154..949a31a77f 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java @@ -488,6 +488,9 @@ public class BukkitImplDeprecations { // Added 2025/08/23 public static Warning advancementBackgroundFormat = new FutureWarning("advancementBackgroundFormat", "The 'background:' input in the advancement command no longer uses the 'textures/' path or '.png' suffix, so for example 'minecraft:textures/gui/advancements/backgrounds/stone.png' would be 'minecraft:gui/advancements/backgrounds/stone'."); + // Added 2025/09/07 + public static Warning brewingStandConsumeDetermination = new FutureWarning("brewingStandConsumeDetermination", "The 'consuming' and 'not_consuming' determinations in the 'brewing stand fueled' event have been deprecated in favor of 'CONSUMING:'."); + // Added 2025/09/22 public static Warning playerSteerEntityEvent = new FutureWarning("playerSteerEntityEvent", "The 'player steers ' event is deprecated in favor of the 'player input' event in MC 1.21+."); From 727c1e16eea7786b970dc99731ddad8108e815b7 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Sun, 25 Jan 2026 16:51:28 -0800 Subject: [PATCH 069/169] `MaterialTag.mode`: creaking heart support, update (#2783) * CreakingHeartState tag and mechanism * moved creaking heart state setting to the MaterialTag.mode property * forgotten import * slight fix * or < and * options -> modes * minor changes --- .../properties/material/MaterialMode.java | 328 ++++++------------ 1 file changed, 101 insertions(+), 227 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java index 3dfb61c2cc..d9dcb0f0c9 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java @@ -4,25 +4,34 @@ import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizencore.objects.Mechanism; -import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.properties.Property; -import com.denizenscript.denizencore.objects.properties.PropertyParser; -import com.denizenscript.denizencore.utilities.CoreUtilities; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.*; -public class MaterialMode implements Property { - - public static boolean describes(ObjectTag material) { - if (!(material instanceof MaterialTag)) { - return false; - } - MaterialTag mat = (MaterialTag) material; - if (!mat.hasModernData()) { - return false; - } - BlockData data = mat.getModernData(); +public class MaterialMode extends MaterialProperty { + + // <--[property] + // @object MaterialTag + // @name mode + // @input ElementTag + // @description + // Controls a block's mode. + // For comparators, modes are COMPARE and SUBTRACT. + // For piston_heads, modes are NORMAL and SHORT. + // For bubble_columns, modes are NORMAL and DRAG. + // For structure_blocks, modes are CORNER, DATA, LOAD, and SAVE. + // For sculk_sensors, modes are ACTIVE, COOLDOWN, and INACTIVE. + // For daylight_detectors, modes are INVERTED and NORMAL. + // For command_blocks, modes are CONDITIONAL and NORMAL. + // For big_dripleafs, modes are FULL, NONE, PARTIAL, and UNSTABLE. + // For sculk_catalysts, modes are BLOOM and NORMAL. + // For sculk_shriekers, modes are SHRIEKING and NORMAL. + // For tripwires, modes are ARMED and DISARMED. + // For creaking_hearts, modes are AWAKE, DORMANT, and UPROOTED. + // --> + + public static boolean describes(MaterialTag material) { + BlockData data = material.getModernData(); return data instanceof Comparator || data instanceof PistonHead || data instanceof BubbleColumn @@ -33,178 +42,99 @@ public static boolean describes(ObjectTag material) { || data instanceof BigDripleaf || data instanceof Tripwire || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && (data instanceof SculkCatalyst - || data instanceof SculkShrieker)); + || data instanceof SculkShrieker)) + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && data instanceof CreakingHeart); } - public static MaterialMode getFrom(ObjectTag _material) { - if (!describes(_material)) { - return null; + @Override + public ElementTag getPropertyValue() { + if (getBlockData() instanceof Comparator comparator) { + return new ElementTag(comparator.getMode()); } - else { - return new MaterialMode((MaterialTag) _material); + else if (getBlockData() instanceof BubbleColumn bubbleColumn) { + return new ElementTag(bubbleColumn.isDrag() ? "DRAG" : "NORMAL", true); } + else if (getBlockData() instanceof PistonHead pistonHead) { + return new ElementTag(pistonHead.isShort() ? "SHORT" : "NORMAL", true); + } + else if (getBlockData() instanceof StructureBlock structureBlock) { + return new ElementTag(structureBlock.getMode()); + } + else if (getBlockData() instanceof DaylightDetector daylightDetector) { + return new ElementTag(daylightDetector.isInverted() ? "INVERTED" : "NORMAL", true); + } + else if (getBlockData() instanceof CommandBlock cmdBlock) { + return new ElementTag(cmdBlock.isConditional() ? "CONDITIONAL" : "NORMAL", true); + } + else if (getBlockData() instanceof SculkSensor sculkSensor) { + return new ElementTag(sculkSensor.getPhase()); + } + else if (getBlockData() instanceof BigDripleaf bigDripleaf) { + return new ElementTag(bigDripleaf.getTilt()); + } + else if (getBlockData() instanceof Tripwire tripwire) { + return new ElementTag(tripwire.isDisarmed() ? "DISARMED" : "ARMED", true); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() instanceof SculkCatalyst sculkCatalyst) { + return new ElementTag(sculkCatalyst.isBloom() ? "BLOOM" : "NORMAL", true); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() instanceof SculkShrieker sculkShrieker) { + return new ElementTag(sculkShrieker.isShrieking() ? "SHRIEKING" : "NORMAL", true); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof CreakingHeart creakingHeart) { + return new ElementTag(creakingHeart.getCreakingHeartState()); + } + return null; } - public static final String[] handledMechs = new String[] { - "mode" - }; - - public MaterialMode(MaterialTag _material) { - material = _material; - } - - public MaterialTag material; - - public static void register() { - - // <--[tag] - // @attribute - // @returns ElementTag - // @mechanism MaterialTag.mode - // @group properties - // @description - // Returns a block's mode. - // For comparators, output is COMPARE or SUBTRACT. - // For piston_heads, output is NORMAL or SHORT. - // For bubble_columns, output is NORMAL or DRAG. - // For structure_blocks, output is CORNER, DATA, LOAD, or SAVE. - // For sculk_sensors, output is ACTIVE, COOLDOWN, or INACTIVE. - // For daylight_detectors, output is INVERTED or NORMAL. - // For command_blocks, output is CONDITIONAL or NORMAL. - // For big_dripleafs, output is FULL, NONE, PARTIAL, or UNSTABLE. - // For sculk_catalysts, output is BLOOM or NORMAL. - // For sculk_shriekers, output is SHRIEKING or NORMAL. - // For tripwires, output is ARMED or DISARMED. - // --> - PropertyParser.registerStaticTag(MaterialMode.class, ElementTag.class, "mode", (attribute, material) -> { - return new ElementTag(material.getPropertyString()); - }); - } - - public boolean isComparator() { - return material.getModernData() instanceof Comparator; - } - - public boolean isPistonHead() { - return material.getModernData() instanceof PistonHead; - } - - public boolean isBubbleColumn() { - return material.getModernData() instanceof BubbleColumn; - } - - public boolean isStructureBlock() { - return material.getModernData() instanceof StructureBlock; - } - - public boolean isDaylightDetector() { - return material.getModernData() instanceof DaylightDetector; - } - - public boolean isCommandBlock() { - return material.getModernData() instanceof CommandBlock; - } - - public boolean isSculkSensor() { - return material.getModernData() instanceof SculkSensor; - } - - public boolean isBigDripleaf() { - return material.getModernData() instanceof BigDripleaf; - } - - public boolean isTripwire() { - return material.getModernData() instanceof Tripwire; - } - - public boolean isSculkCatalyst() { - return NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && material.getModernData() instanceof SculkCatalyst; - } - - public boolean isSculkShrieker() { - return NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && material.getModernData() instanceof SculkShrieker; - } - - public Comparator getComparator() { - return (Comparator) material.getModernData(); - } - - public PistonHead getPistonHead() { - return (PistonHead) material.getModernData(); - } - - public BubbleColumn getBubbleColumn() { - return (BubbleColumn) material.getModernData(); - } - - public StructureBlock getStructureBlock() { - return (StructureBlock) material.getModernData(); - } - - public DaylightDetector getDaylightDetector() { - return (DaylightDetector) material.getModernData(); - } - - public CommandBlock getCommandBlock() { - return (CommandBlock) material.getModernData(); - } - - public SculkSensor getSculkSensor() { - return (SculkSensor) material.getModernData(); - } - - public BigDripleaf getBigDripleaf() { - return (BigDripleaf) material.getModernData(); - } - - public Tripwire getTripwire() { - return (Tripwire) material.getModernData(); - } - - /*public SculkCatalyst getSculkCatalyst() { // TODO: 1.19 - return (SculkCatalyst) material.getModernData(); - } - - public SculkShrieker getSculkShrieker() { - return (SculkShrieker) material.getModernData(); - }*/ - @Override - public String getPropertyString() { - if (isComparator()) { - return getComparator().getMode().name(); + public void setPropertyValue(ElementTag value, Mechanism mechanism) { + if (getBlockData() instanceof Comparator comparator) { + if (mechanism.requireEnum(Comparator.Mode.class)) { + comparator.setMode(value.asEnum(Comparator.Mode.class)); + } + } + else if (getBlockData() instanceof BubbleColumn bubbleColumn) { + bubbleColumn.setDrag(value.asLowerString().equals("drag")); } - else if (isBubbleColumn()) { - return getBubbleColumn().isDrag() ? "DRAG" : "NORMAL"; + else if (getBlockData() instanceof PistonHead pistonHead) { + pistonHead.setShort(value.asLowerString().equals("short")); } - else if (isPistonHead()) { - return getPistonHead().isShort() ? "SHORT" : "NORMAL"; + else if (getBlockData() instanceof StructureBlock structureBlock) { + if (mechanism.requireEnum(StructureBlock.Mode.class)) { + structureBlock.setMode(value.asEnum(StructureBlock.Mode.class)); + } } - else if (isStructureBlock()) { - return getStructureBlock().getMode().name(); + else if (getBlockData() instanceof DaylightDetector daylightDetector) { + daylightDetector.setInverted(value.asLowerString().equals("inverted")); } - else if (isDaylightDetector()) { - return getDaylightDetector().isInverted() ? "INVERTED" : "NORMAL"; + else if (getBlockData() instanceof CommandBlock cmdBlock) { + cmdBlock.setConditional(value.asLowerString().equals("conditional")); } - else if (isCommandBlock()) { - return getCommandBlock().isConditional() ? "CONDITIONAL" : "NORMAL"; + else if (getBlockData() instanceof SculkSensor sculkSensor) { + if (mechanism.requireEnum(SculkSensor.Phase.class)) { + sculkSensor.setPhase(value.asEnum(SculkSensor.Phase.class)); + } } - else if (isSculkSensor()) { - return getSculkSensor().getPhase().name(); + else if (getBlockData() instanceof BigDripleaf bigDripleaf) { + if (mechanism.requireEnum(BigDripleaf.Tilt.class)) { + bigDripleaf.setTilt(value.asEnum(BigDripleaf.Tilt.class)); + } } - else if (isBigDripleaf()) { - return getBigDripleaf().getTilt().name(); + else if (getBlockData() instanceof Tripwire tripwire) { + tripwire.setDisarmed(value.asLowerString().equals("disarmed")); } - else if (isTripwire()) { - return getTripwire().isDisarmed() ? "DISARMED" : "ARMED"; + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() instanceof SculkCatalyst sculkCatalyst) { + sculkCatalyst.setBloom(value.asLowerString().equals("bloom")); } - else if (isSculkCatalyst()) { - return ((SculkCatalyst) material.getModernData()).isBloom() ? "BLOOM" : "NORMAL"; // TODO: 1.19 + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() instanceof SculkShrieker sculkShrieker) { + sculkShrieker.setShrieking(value.asLowerString().equals("shrieking")); } - else if (isSculkShrieker()) { - return ((SculkShrieker) material.getModernData()).isShrieking() ? "SHRIEKING" : "NORMAL"; // TODO: 1.19 + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof CreakingHeart creakingHeart) { + if (mechanism.requireEnum(CreakingHeart.State.class)) { + creakingHeart.setCreakingHeartState(value.asEnum(CreakingHeart.State.class)); + } } - return null; // Unreachable } @Override @@ -212,63 +142,7 @@ public String getPropertyId() { return "mode"; } - @Override - public void adjust(Mechanism mechanism) { - - // <--[mechanism] - // @object MaterialTag - // @name mode - // @input ElementTag - // @description - // Set a block's mode. - // For comparators, input is COMPARE or SUBTRACT. - // For piston_heads, input is NORMAL or SHORT. - // For bubble_columns, input is NORMAL or DRAG. - // For structure_blocks, input is CORNER, DATA, LOAD, or SAVE. - // For sculk_sensors, input is ACTIVE, COOLDOWN, or INACTIVE. - // For daylight_detectors, input is INVERTED or NORMAL. - // For command_blocks, input is CONDITIONAL or NORMAL. - // For big_dripleafs, input is FULL, NONE, PARTIAL, or UNSTABLE. - // For sculk_catalysts, input is BLOOM or NORMAL. - // For sculk_shriekers, input is SHRIEKING or NORMAL. - // For tripwires, input is ARMED or DISARMED. - // @tags - // - // --> - if (mechanism.matches("mode")) { - if (isComparator() && mechanism.requireEnum(Comparator.Mode.class)) { - getComparator().setMode(Comparator.Mode.valueOf(mechanism.getValue().asString().toUpperCase())); - } - else if (isBubbleColumn()) { - getBubbleColumn().setDrag(CoreUtilities.equalsIgnoreCase(mechanism.getValue().asString(), "drag")); - } - else if (isPistonHead()) { - getPistonHead().setShort(CoreUtilities.equalsIgnoreCase(mechanism.getValue().asString(), "short")); - } - else if (isStructureBlock() && mechanism.requireEnum(StructureBlock.Mode.class)) { - getStructureBlock().setMode(StructureBlock.Mode.valueOf(mechanism.getValue().asString().toUpperCase())); - } - else if (isDaylightDetector()) { - getDaylightDetector().setInverted(CoreUtilities.equalsIgnoreCase(mechanism.getValue().asString(), "inverted")); - } - else if (isCommandBlock()) { - getCommandBlock().setConditional(CoreUtilities.equalsIgnoreCase(mechanism.getValue().asString(), "conditional")); - } - else if (isSculkSensor() && mechanism.requireEnum(SculkSensor.Phase.class)) { - getSculkSensor().setPhase(SculkSensor.Phase.valueOf(mechanism.getValue().asString().toUpperCase())); - } - else if (isBigDripleaf() && mechanism.requireEnum(BigDripleaf.Tilt.class)) { - getBigDripleaf().setTilt(BigDripleaf.Tilt.valueOf(mechanism.getValue().asString().toUpperCase())); - } - else if (isTripwire()) { - getTripwire().setDisarmed(CoreUtilities.equalsIgnoreCase(mechanism.getValue().asString(), "disarmed")); - } - else if (isSculkCatalyst()) { - ((SculkCatalyst) material.getModernData()).setBloom(CoreUtilities.equalsIgnoreCase(mechanism.getValue().asString(), "bloom")); // TODO: 1.19 - } - else if (isSculkShrieker()) { - ((SculkShrieker) material.getModernData()).setShrieking(CoreUtilities.equalsIgnoreCase(mechanism.getValue().asString(), "shrieking")); // TODO: 1.19 - } - } + public static void register() { + autoRegister("mode", MaterialMode.class, ElementTag.class, false); } } From 35af4624269212c64d45d65d8ec981c69d399589 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Mon, 26 Jan 2026 17:24:17 -0800 Subject: [PATCH 070/169] Add `EntityTag.state` to control armadillo states (#2802) * Added EntityTag.State property for armadillo rolling * NMS updates * minor changes * ; * removed unneeded imports * isDefaultValue change * isDefaultValue change --- .../denizen/nms/interfaces/EntityHelper.java | 9 ++++ .../objects/properties/PropertyRegistry.java | 3 ++ .../properties/entity/EntityState.java | 54 +++++++++++++++++++ .../nms/v1_20/helpers/EntityHelperImpl.java | 24 +++++++++ .../nms/v1_21/helpers/EntityHelperImpl.java | 24 +++++++++ 5 files changed, 114 insertions(+) create mode 100644 plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityState.java diff --git a/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java b/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java index 0501930cd7..f18202f90e 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java @@ -5,6 +5,7 @@ import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizen.objects.properties.entity.EntityState; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.MapTag; import net.kyori.adventure.nbt.CompoundBinaryTag; @@ -514,4 +515,12 @@ public void onEntityMount(EntityDismountEvent event) { public Class getExitsVehicleEventImpl() { // TODO: once 1.20 is the minimum supported version, implement in the ScriptEvent class as usual return EntityExitsVehicleScriptEventImpl.class; } + + public EntityState.ArmadilloState getArmadilloState(Armadillo entity) { + throw new UnsupportedOperationException(); + } + + public void setArmadilloState(Armadillo entity, EntityState.ArmadilloState state) { + throw new UnsupportedOperationException(); + } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java index 477c8bb129..abfdd8ef35 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java @@ -173,6 +173,9 @@ public static void registerMainProperties() { } PropertyParser.registerProperty(EntitySpeed.class, EntityTag.class); PropertyParser.registerProperty(EntitySpell.class, EntityTag.class); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + PropertyParser.registerProperty(EntityState.class, EntityTag.class); + } if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19)) { PropertyParser.registerProperty(EntityStepHeight.class, EntityTag.class); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityState.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityState.java new file mode 100644 index 0000000000..e68ce63ea6 --- /dev/null +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityState.java @@ -0,0 +1,54 @@ +package com.denizenscript.denizen.objects.properties.entity; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.objects.EntityTag; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; +import org.bukkit.entity.Armadillo; + +public class EntityState extends EntityProperty { + + // <--[property] + // @object EntityTag + // @name state + // @input ElementTag + // @description + // Controls the current state of an armadillo. + // Valid states are IDLE, ROLLING, SCARED, and UNROLLING. + // The entity may roll or unroll due to normal vanilla conditions. If this is not desired, disable <@link property EntityTag.has_ai>. + // --> + + public static boolean describes(EntityTag entity) { + return entity.getBukkitEntity() instanceof Armadillo; + } + + public enum ArmadilloState { + IDLE, ROLLING, SCARED, UNROLLING + } + + @Override + public boolean isDefaultValue(ElementTag val) { + return val.asEnum(ArmadilloState.class).equals(ArmadilloState.IDLE); + } + + @Override + public ElementTag getPropertyValue() { + return new ElementTag(NMSHandler.entityHelper.getArmadilloState(as(Armadillo.class))); + } + + @Override + public void setPropertyValue(ElementTag param, Mechanism mechanism) { + if (mechanism.requireEnum(ArmadilloState.class)) { + NMSHandler.entityHelper.setArmadilloState(as(Armadillo.class), param.asEnum(ArmadilloState.class)); + } + } + + @Override + public String getPropertyId() { + return "state"; + } + + public static void register() { + autoRegister("state", EntityState.class, ElementTag.class, false); + } +} diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityHelperImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityHelperImpl.java index 58fb9ba367..e4ce519430 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityHelperImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityHelperImpl.java @@ -6,6 +6,7 @@ import com.denizenscript.denizen.nms.v1_20.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v1_20.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; @@ -43,6 +44,7 @@ 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; @@ -848,4 +850,26 @@ public void modifyRawNBT(Entity entity, CompoundBinaryTag tag) { nmsEntity.load(nmsMergedTag); nmsEntity.setUUID(uuid); } + + @Override + public EntityState.ArmadilloState getArmadilloState(org.bukkit.entity.Armadillo entity) { + Armadillo armadillo = (Armadillo) ((CraftEntity) entity).getHandle(); + return switch (armadillo.getState()) { + case IDLE -> EntityState.ArmadilloState.IDLE; + case ROLLING -> EntityState.ArmadilloState.ROLLING; + case SCARED -> EntityState.ArmadilloState.SCARED; + case UNROLLING -> EntityState.ArmadilloState.UNROLLING; + }; + } + + @Override + public void setArmadilloState(org.bukkit.entity.Armadillo entity, EntityState.ArmadilloState state) { + Armadillo armadillo = (Armadillo) ((CraftEntity) entity).getHandle(); + armadillo.switchToState(switch (state) { + case IDLE -> Armadillo.ArmadilloState.IDLE; + case ROLLING -> Armadillo.ArmadilloState.ROLLING; + case SCARED -> Armadillo.ArmadilloState.SCARED; + case UNROLLING -> Armadillo.ArmadilloState.UNROLLING; + }); + } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java index 8899ea0572..b57de3441d 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/EntityHelperImpl.java @@ -7,6 +7,7 @@ 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; @@ -45,6 +46,7 @@ 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; @@ -843,4 +845,26 @@ public void modifyRawNBT(Entity entity, CompoundBinaryTag tag) { Handler.useValueInput(nmsMergedTag, nmsEntity::load); nmsEntity.setUUID(uuid); } + + @Override + public EntityState.ArmadilloState getArmadilloState(org.bukkit.entity.Armadillo entity) { + Armadillo armadillo = (Armadillo) ((CraftEntity) entity).getHandle(); + return switch (armadillo.getState()) { + case IDLE -> EntityState.ArmadilloState.IDLE; + case ROLLING -> EntityState.ArmadilloState.ROLLING; + case SCARED -> EntityState.ArmadilloState.SCARED; + case UNROLLING -> EntityState.ArmadilloState.UNROLLING; + }; + } + + @Override + public void setArmadilloState(org.bukkit.entity.Armadillo entity, EntityState.ArmadilloState state) { + Armadillo armadillo = (Armadillo) ((CraftEntity) entity).getHandle(); + armadillo.switchToState(switch (state) { + case IDLE -> Armadillo.ArmadilloState.IDLE; + case ROLLING -> Armadillo.ArmadilloState.ROLLING; + case SCARED -> Armadillo.ArmadilloState.SCARED; + case UNROLLING -> Armadillo.ArmadilloState.UNROLLING; + }); + } } From d53c6e12064d6ab04eaba47ed42fe366e3f70392 Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Thu, 5 Feb 2026 00:28:35 +0100 Subject: [PATCH 071/169] smithing recipes: 1.21 fix (#2807) * fix * fix --- .../denizen/nms/v1_21/helpers/ItemHelperImpl.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java index cd0972113a..ade89727a1 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java @@ -54,6 +54,7 @@ import net.minecraft.world.item.crafting.BlastingRecipe; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.ShapelessRecipe; +import net.minecraft.world.item.crafting.SmithingTransformRecipe; import net.minecraft.world.item.crafting.SmokingRecipe; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; @@ -239,15 +240,13 @@ public void registerStonecuttingRecipe(String keyName, String group, ItemStack r @Override public void registerSmithingRecipe(String keyName, ItemStack result, ItemStack[] baseItem, boolean baseExact, ItemStack[] upgradeItem, boolean upgradeExact, ItemStack[] templateItem, boolean templateExact) { ResourceKey> key = createRecipeKey(keyName); - Ingredient templateItemRecipe = itemArrayToRecipe(templateItem, templateExact); + Ingredient templateItemRecipe = templateItem.length == 0 ? null : itemArrayToRecipe(templateItem, templateExact); Ingredient baseItemRecipe = itemArrayToRecipe(baseItem, baseExact); Ingredient upgradeItemRecipe = itemArrayToRecipe(upgradeItem, upgradeExact); - // TODO: 1.21.5: TransmuteRecipe? - /* - SmithingTransformRecipe recipe = new SmithingTransformRecipe(Optional.of(templateItemRecipe), baseItemRecipe, Optional.of(upgradeItemRecipe), CraftItemStack.asNMSCopy(result)); + net.minecraft.world.item.ItemStack nmsCopy = CraftItemStack.asNMSCopy(result); + SmithingTransformRecipe recipe = new SmithingTransformRecipe(Optional.ofNullable(templateItemRecipe), baseItemRecipe, Optional.of(upgradeItemRecipe), new TransmuteResult(nmsCopy.getItemHolder(), nmsCopy.getCount(), nmsCopy.getComponentsPatch())); RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); - */ } @Override From 54b3dabccbb8b5dd35272731e1be955b2fd37862 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Mon, 9 Feb 2026 12:46:46 -0800 Subject: [PATCH 072/169] consistency correction --- .../main/java/com/denizenscript/denizen/objects/BiomeTag.java | 2 +- .../java/com/denizenscript/denizen/objects/LocationTag.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/BiomeTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/BiomeTag.java index d0f02e6750..e8b2e53caa 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/BiomeTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/BiomeTag.java @@ -508,7 +508,7 @@ else if (attribute.startsWith("water", 2)) { }); } - public static final ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); + public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); @Override public ObjectTag getObjectAttribute(Attribute attribute) { diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java index 35501f2d69..a57c200884 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java @@ -4637,7 +4637,7 @@ else if (mechanism.requireObject(EntityTag.class)) { }); } - public static final ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); + public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); @Override public ObjectTag getObjectAttribute(Attribute attribute) { From 95d7ce4ecbdfe8af9fd6cc96f8e8fd1187d234bd Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Mon, 9 Feb 2026 12:52:20 -0800 Subject: [PATCH 073/169] patch for citizens change --- .../denizen/scripts/commands/npc/PauseCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/PauseCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/PauseCommand.java index 7b33411c51..a4e8a8d0d6 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/PauseCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/PauseCommand.java @@ -159,7 +159,7 @@ public void pause(NPCTag denizen, PauseType pauseType, boolean pause) { } return; case ACTIVITY: - denizen.getCitizen().getDefaultGoalController().setPaused(pause); + denizen.getCitizen().getDefaultBehaviorController().setPaused(pause); return; case NAVIGATION: // TODO: Finish this From b1286a361657f5ac834da47107befc68bf80f8ad Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Wed, 11 Feb 2026 20:26:44 -0800 Subject: [PATCH 074/169] Compat with Spigot 1.21.11 R0.2 --- plugin/pom.xml | 2 +- v1_21/pom.xml | 12 ++++++------ .../denizen/nms/v1_21/helpers/WorldHelperImpl.java | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugin/pom.xml b/plugin/pom.xml index 617aa38e14..f1abe6f709 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -30,7 +30,7 @@ org.spigotmc spigot-api - 1.21.11-R0.1-SNAPSHOT + 1.21.11-R0.2-SNAPSHOT jar provided diff --git a/v1_21/pom.xml b/v1_21/pom.xml index 8321e004ac..1449c8e8a8 100644 --- a/v1_21/pom.xml +++ b/v1_21/pom.xml @@ -19,13 +19,13 @@ org.spigotmc spigot-api - 1.21.11-R0.1-SNAPSHOT + 1.21.11-R0.2-SNAPSHOT provided org.spigotmc spigot - 1.21.11-R0.1-SNAPSHOT + 1.21.11-R0.2-SNAPSHOT remapped-mojang provided @@ -45,9 +45,9 @@ remap-obf - org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:txt:maps-mojang + org.spigotmc:minecraft-server:1.21.11-R0.2-SNAPSHOT:txt:maps-mojang true - org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT:jar:remapped-mojang + org.spigotmc:spigot:1.21.11-R0.2-SNAPSHOT:jar:remapped-mojang true remapped-obf @@ -60,8 +60,8 @@ remap-spigot ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:csrg:maps-spigot - org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT:jar:remapped-obf + 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 diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java index 75f6c9ded5..5f70b7347e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/WorldHelperImpl.java @@ -98,7 +98,7 @@ public void wakeUpAllPlayers(World world) { // net.minecraft.server.level.ServerLevel#resetWeatherCycle() @Override public void clearWeather(World world) { - PrimaryLevelData data = ((CraftWorld) world).getHandle().I; + PrimaryLevelData data = ((CraftWorld) world).getHandle().serverLevelData; data.setRaining(false); if (!data.isRaining()) { data.setRainTime(0); From 19c7dfe3dbe266b1ff33413c78c8df6bfde55240 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Wed, 11 Feb 2026 20:27:08 -0800 Subject: [PATCH 075/169] new tag: server.bukkit_name --- .../denizenscript/denizen/tags/core/ServerTagBase.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java index 9ce0637474..08122dc15d 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java +++ b/plugin/src/main/java/com/denizenscript/denizen/tags/core/ServerTagBase.java @@ -1120,6 +1120,16 @@ else if (param.shouldBeType(EntityTag.class)) { return new ElementTag(Denizen.versionTag); }); + // <--[tag] + // @attribute + // @returns ElementTag + // @description + // Returns the name of the Bukkit platform, such as "Paper". + // --> + tagProcessor.registerStaticTag(ElementTag.class, "bukkit_name", (attribute, object) -> { + return new ElementTag(Bukkit.getName()); + }); + // <--[tag] // @attribute // @returns ElementTag From 9b0ff5d7f055d1cf388def66777445b153c3ea2d Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Wed, 11 Feb 2026 20:27:18 -0800 Subject: [PATCH 076/169] fix monkeystats platform name --- .../denizen/utilities/debugging/StatsRecord.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/debugging/StatsRecord.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/debugging/StatsRecord.java index c4614d3711..3de0ccb75a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/debugging/StatsRecord.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/debugging/StatsRecord.java @@ -30,16 +30,13 @@ public void gather() { String deprecations = String.join("\n", Deprecations.firedRecently.keySet()); Deprecations.firedRecently.clear(); String mcVersion = Bukkit.getVersion(); - int firstDash = mcVersion.indexOf('-'); - int secondDash = firstDash == -1 ? -1 : mcVersion.indexOf('-', firstDash + 1); int mcPart = mcVersion.indexOf("(MC: "); int endPart = mcPart == -1 ? -1 : mcVersion.indexOf(")", mcPart); - String platform = secondDash == -1 ? "" : mcVersion.substring(firstDash + 1, secondDash); mcVersion = (endPart == -1) ? "" : mcVersion.substring(mcPart + "(MC: ".length(), endPart); content = "postid=pluginstats&plugin=Denizen" + "&differentiator=" + differentiator + "&pl_plugin_version=" + URLEncoder.encode(denizenVersion) - + "&pl_platform=" + URLEncoder.encode(platform) + + "&pl_platform=" + URLEncoder.encode(Bukkit.getName()) + "&pl_minecraft_version=" + URLEncoder.encode(mcVersion) + "&pl_player_count=" + Bukkit.getOnlinePlayers().size() + "&pl_script_count=" + ScriptRegistry.scriptContainers.size() From edf91f4a5e95fff8ae6a5ebfd9bc923262177c83 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:05:17 +0000 Subject: [PATCH 077/169] Item components framework (#2760) * Item data component framework * Only register mapping when needed * Field modifiers * Reorder * Move `DataComponentAdapter` * Meta cleanups * s * Minor cleanups * Remove `MaterialTag` parts * Semi-finalize components system * Add `remove_component` * `setIfValid`: support all object types * `toPaper` -> `fromDenizen` * Fix error * Fix generics naming * Meta * Minor cleanup --- .../denizen/paper/PaperModule.java | 7 + .../ComponentAdaptersRegistry.java | 9 + .../datacomponents/DataComponentAdapter.java | 227 ++++++++++++++++++ .../paper/datacomponents/FoodAdapter.java | 46 ++++ .../paper/datacomponents/GliderAdapter.java | 20 ++ .../properties/ItemRemovedComponents.java | 86 +++++++ .../nms/v1_21/helpers/ItemHelperImpl.java | 7 + 7 files changed, 402 insertions(+) create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ComponentAdaptersRegistry.java create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/DataComponentAdapter.java create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/FoodAdapter.java create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/GliderAdapter.java create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/properties/ItemRemovedComponents.java diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index 016e6b9694..305f8e41ce 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -6,6 +6,7 @@ import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.paper.datacomponents.ComponentAdaptersRegistry; import com.denizenscript.denizen.paper.events.*; import com.denizenscript.denizen.paper.properties.*; import com.denizenscript.denizen.paper.tags.PaperTagBase; @@ -130,6 +131,12 @@ public static void init() { PropertyParser.registerProperty(EntityWitherInvulnerable.class, EntityTag.class); PropertyParser.registerProperty(ItemArmorStand.class, ItemTag.class); + // Components system + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + PropertyParser.registerProperty(ItemRemovedComponents.class, ItemTag.class); + ComponentAdaptersRegistry.register(); + } + // Paper object extensions PaperElementExtensions.register(); PaperEntityExtensions.register(); diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ComponentAdaptersRegistry.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ComponentAdaptersRegistry.java new file mode 100644 index 0000000000..ad691abf2b --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ComponentAdaptersRegistry.java @@ -0,0 +1,9 @@ +package com.denizenscript.denizen.paper.datacomponents; + +public class ComponentAdaptersRegistry { + + public static void register() { + DataComponentAdapter.register(new FoodAdapter()); + DataComponentAdapter.register(new GliderAdapter()); + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/DataComponentAdapter.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/DataComponentAdapter.java new file mode 100644 index 0000000000..82349b5660 --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/DataComponentAdapter.java @@ -0,0 +1,227 @@ +package com.denizenscript.denizen.paper.datacomponents; + +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.objects.properties.item.ItemComponentsPatch; +import com.denizenscript.denizen.objects.properties.item.ItemProperty; +import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizencore.objects.Mechanism; +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.properties.PropertyParser; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import io.papermc.paper.datacomponent.DataComponentType; +import org.bukkit.Registry; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +public abstract class DataComponentAdapter { + + // <--[language] + // @name Item Components + // @group Minecraft Logic + // @description + // Minecraft item components (see <@link url https://minecraft.wiki/w/Data_component_format>) are managed as follows: + // Each item type has a default set of component values; a food item will have food components by default, a tool item will have tool components by default, etc. + // Different items can override their type's default components, either by setting values that weren't there previously (e.g. making an inedible item edible), or by removing values that are there by default (e.g. making a shield item that can't block). + // Items' overrides can later be reset, making them use their type's default values again. + // + // In Denizen, different item components are represented by item properties. + // These properties allow both setting a component override on an item, and clearing/resetting it by providing no input. + // Item properties' name will generally match their respective item component's name, but not always! + // Due to this, features that take item component names as input (such as <@link tag ItemTag.is_overridden>) accept both Minecraft component names and Denizen property names. + // + // Here is an example of applying all of this in a script: + // + // # We define a default apple item + // - define apple + // # We remove the apple's "food" component, making eating it restore no food points (it is still consumable due to the "consumable" component). + // - adjust def:apple remove_component:food + // # This check will pass, as the apple's "food" component is overridden to have no value. + // - if <[apple].is_overridden[food]>: + // - narrate "The apple has a modified food component! It will behave differently to a normal apple." + // # We reset the apple item's food component by adjusting with no value, making it a normal apple. + // - adjust def:apple food: + // + // --> + + public static final Map COMPONENTS_BY_PROPERTY = new HashMap<>(); + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + + public static DataComponentType getComponentType(String name) { + String nameLower = CoreUtilities.toLowerCase(name); + DataComponentType componentType = Registry.DATA_COMPONENT_TYPE.get(Utilities.parseNamespacedKey(nameLower)); + if (componentType == null) { + componentType = COMPONENTS_BY_PROPERTY.get(nameLower); + } + return componentType; + } + + public static void register(DataComponentAdapter adapter) { + DataComponentAdapter.Property.currentlyRegisteringComponentAdapter = adapter; + PropertyParser.registerPropertyGetter( + item -> !item.getItemStack().isEmpty() ? adapter.new Property(item) : null, + ItemTag.class, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, DataComponentAdapter.Property.class); + DataComponentAdapter.Property.currentlyRegisteringComponentAdapter = null; + String componentName = adapter.componentType.key().asMinimalString(); + ItemComponentsPatch.registerHandledComponent(componentName); + if (!adapter.name.equals(componentName)) { + COMPONENTS_BY_PROPERTY.put(adapter.name, adapter.componentType); + } + } + + static { + + // <--[tag] + // @attribute ]> + // @returns ElementTag(Boolean) + // @description + // Returns whether an item has a specific item component type overridden, see <@link language Item Components>. + // --> + ItemTag.tagProcessor.registerTag(ElementTag.class, ElementTag.class, "is_overridden", (attribute, object, param) -> { + DataComponentType componentType = getComponentType(param.asString()); + if (componentType == null) { + attribute.echoError("Invalid type specified, must be a valid item component type or property name."); + return null; + } + return new ElementTag(object.getItemStack().isDataOverridden(componentType)); + }); + } + + public final C componentType; + public final Class denizenType; + public final String name; + + public DataComponentAdapter(C componentType, Class denizenType, String name) { + this.componentType = componentType; + this.denizenType = denizenType; + this.name = name; + } + + public abstract D getValue(ItemStack item); + + public abstract void setValue(ItemStack item, D value, Mechanism mechanism); + + public boolean isDefaultValue(D value) { + return false; + } + + public static abstract class NonValued extends DataComponentAdapter { + + public NonValued(DataComponentType.NonValued componentType, String name) { + super(componentType, ElementTag.class, name); + } + + @Override + public ElementTag getValue(ItemStack item) { + return new ElementTag(item.hasData(componentType)); + } + + @Override + public void setValue(ItemStack item, ElementTag value, Mechanism mechanism) { + if (!mechanism.requireBoolean()) { + return; + } + if (value.asBoolean()) { + item.setData(componentType); + } + else { + item.unsetData(componentType); + } + } + + // Overridden and false = removed, managed by ItemTag.removed_components + @Override + public boolean isDefaultValue(ElementTag value) { + return !value.asBoolean(); + } + } + + public static abstract class Valued extends DataComponentAdapter> { + + public static void setIfValid(Consumer setter, MapTag data, String key, Class objectType, Predicate checker, Function converter, String type, Mechanism mechanism) { + D value = data.getObjectAs(key, objectType, mechanism.context); + if (value == null) { + return; + } + T converted; + if ((checker != null && !checker.test(value)) || (converted = converter.apply(value)) == null) { + mechanism.echoError("Invalid '" + key + "' specified: must be a " + type + '.'); + return; + } + setter.accept(converted); + } + + public Valued(Class denizenType, DataComponentType.Valued

componentType, String name) { + super(componentType, denizenType, name); + } + + public abstract D toDenizen(P value); + + public abstract P fromDenizen(D value, Mechanism mechanism); + + @Override + public D getValue(ItemStack item) { + P data = item.getData(componentType); + return data != null ? toDenizen(data) : null; + } + + @Override + public void setValue(ItemStack item, D value, Mechanism mechanism) { + P converted = fromDenizen(value, mechanism); + if (converted != null) { + item.setData(componentType, converted); + } + } + } + + public class Property extends ItemProperty { + + private static DataComponentAdapter currentlyRegisteringComponentAdapter; + + public Property(ItemTag item) { + this.object = item; + } + + @Override + public D getPropertyValue() { + return getValue(getItemStack()); + } + + @Override + public D getPropertyValueNoDefault() { + if (!getItemStack().isDataOverridden(componentType)) { + return null; + } + return super.getPropertyValueNoDefault(); + } + + @Override + public boolean isDefaultValue(D value) { + return DataComponentAdapter.this.isDefaultValue(value); + } + + @Override + public void setPropertyValue(D value, Mechanism mechanism) { + if (value == null) { + getItemStack().resetData(componentType); + return; + } + setValue(getItemStack(), value, mechanism); + } + + @Override + public String getPropertyId() { + return name; + } + + public static void register() { + autoRegisterNullable(currentlyRegisteringComponentAdapter.name, DataComponentAdapter.Property.class, currentlyRegisteringComponentAdapter.denizenType, false); + } + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/FoodAdapter.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/FoodAdapter.java new file mode 100644 index 0000000000..4f6710f1fd --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/FoodAdapter.java @@ -0,0 +1,46 @@ +package com.denizenscript.denizen.paper.datacomponents; + +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.MapTag; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.FoodProperties; + +public class FoodAdapter extends DataComponentAdapter.Valued { + + // <--[property] + // @object ItemTag + // @name food + // @input MapTag + // @description + // Controls an item's food <@link language Item Components>. + // The map includes keys: + // - "nutrition", ElementTag(Number) representing the amount of food points restored by this item. + // - "saturation", ElementTag(Decimal) representing the amount of saturation points restored by this item. + // - "can_always_eat", ElementTag(Boolean) controlling whether the item can always be eaten, even if the player isn't hungry. + // @mechanism + // Provide no input to reset the item to its default value. + // --> + + public FoodAdapter() { + super(MapTag.class, DataComponentTypes.FOOD, "food"); + } + + @Override + public MapTag toDenizen(FoodProperties value) { + MapTag foodData = new MapTag(); + foodData.putObject("nutrition", new ElementTag(value.nutrition())); + foodData.putObject("saturation", new ElementTag(value.saturation())); + foodData.putObject("can_always_eat", new ElementTag(value.canAlwaysEat())); + return foodData; + } + + @Override + public FoodProperties fromDenizen(MapTag value, Mechanism mechanism) { + FoodProperties.Builder builder = FoodProperties.food(); + setIfValid(builder::nutrition, value, "nutrition", ElementTag.class, ElementTag::isInt, ElementTag::asInt, "number", mechanism); + setIfValid(builder::saturation, value, "saturation", ElementTag.class, ElementTag::isFloat, ElementTag::asFloat, "decimal number", mechanism); + setIfValid(builder::canAlwaysEat, value, "can_always_eat", ElementTag.class, ElementTag::isBoolean, ElementTag::asBoolean, "boolean", mechanism); + return builder.build(); + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/GliderAdapter.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/GliderAdapter.java new file mode 100644 index 0000000000..838f02ca72 --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/GliderAdapter.java @@ -0,0 +1,20 @@ +package com.denizenscript.denizen.paper.datacomponents; + +import io.papermc.paper.datacomponent.DataComponentTypes; + +public class GliderAdapter extends DataComponentAdapter.NonValued { + + // <--[property] + // @object ItemTag + // @name glider + // @input ElementTag(Boolean) + // @description + // Controls whether an item can be used to glide when equipped (like elytras by default), see <@link language Item Components>. + // @mechanism + // Provide no input to reset the item to its default value. + // --> + + public GliderAdapter() { + super(DataComponentTypes.GLIDER, "glider"); + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/properties/ItemRemovedComponents.java b/paper/src/main/java/com/denizenscript/denizen/paper/properties/ItemRemovedComponents.java new file mode 100644 index 0000000000..cd272bdda8 --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/properties/ItemRemovedComponents.java @@ -0,0 +1,86 @@ +package com.denizenscript.denizen.paper.properties; + +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.objects.properties.item.ItemProperty; +import com.denizenscript.denizen.paper.datacomponents.DataComponentAdapter; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.ListTag; +import com.denizenscript.denizencore.objects.properties.PropertyParser; +import io.papermc.paper.datacomponent.DataComponentType; + +public class ItemRemovedComponents extends ItemProperty { + + // <--[property] + // @object ItemTag + // @name removed_components + // @input ListTag + // @description + // Controls the item components explicitly removed from an item. + // This can be used to remove item's default behavior, such as making consumable items non-consumable. + // Alternatively, use <@link mechanism ItemTag.remove_component> to remove a single component. + // See <@link language Item Components> for more information. + // --> + + public static boolean describes(ItemTag item) { + return !item.getItemStack().isEmpty(); + } + + public boolean isRemoved(DataComponentType componentType) { + return getItemStack().isDataOverridden(componentType) && !getItemStack().hasData(componentType); + } + + @Override + public ListTag getPropertyValue() { + return new ListTag(getMaterial().getDefaultDataTypes(), this::isRemoved, componentType -> new ElementTag(componentType.key().asMinimalString(), true)); + } + + @Override + public boolean isDefaultValue(ListTag value) { + return value.isEmpty(); + } + + @Override + public void setPropertyValue(ListTag value, Mechanism mechanism) { + for (DataComponentType componentType : getMaterial().getDefaultDataTypes()) { + if (isRemoved(componentType)) { + getItemStack().resetData(componentType); + } + } + for (String input : value) { + DataComponentType componentType = DataComponentAdapter.getComponentType(input); + if (componentType == null) { + mechanism.echoError("Invalid type to remove '" + input + "' specified: must be a valid property or item component name."); + continue; + } + getItemStack().unsetData(componentType); + } + } + + @Override + public String getPropertyId() { + return "removed_components"; + } + + public static void register() { + autoRegister("removed_components", ItemRemovedComponents.class, ListTag.class, false); + + // <--[mechanism] + // @object ItemTag + // @name remove_component + // @input ElementTag + // @description + // Removes the specified item component from the item, see <@link language Item Components> for more information. + // This can be used to remove item's default behavior, such as making consumable items non-consumable. + // See also <@link property ItemTag.removed_components>. + // --> + PropertyParser.registerMechanism(ItemRemovedComponents.class, ElementTag.class, "remove_component", (prop, mechanism, input) -> { + DataComponentType componentType = DataComponentAdapter.getComponentType(input.asString()); + if (componentType == null) { + mechanism.echoError("Invalid type to remove specified: must be a valid property or item component name."); + return; + } + prop.getItemStack().unsetData(componentType); + }); + } +} diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java index ade89727a1..5ab295a2d6 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java @@ -1,5 +1,6 @@ package com.denizenscript.denizen.nms.v1_21.helpers; +import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.interfaces.ItemHelper; import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v1_21.Handler; @@ -451,6 +452,12 @@ public MapTag getRawComponentsPatch(ItemStack item, boolean excludeHandled) { } RegistryOps registryOps = CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE); CompoundTag nmsPatch = (CompoundTag) DataComponentPatch.CODEC.encodeStart(registryOps, patch).getOrThrow(); + if (excludeHandled && Denizen.supportsPaper) { + nmsPatch.keySet().removeIf(s -> s.charAt(0) == '!'); + if (nmsPatch.isEmpty()) { + return new MapTag(); + } + } MapTag rawComponents = (MapTag) ItemRawNBT.nbtTagToObject(NBTAdapter.toAPI(nmsPatch)); rawComponents.putObject(ItemComponentsPatch.DATA_VERSION_KEY, new ElementTag(CraftMagicNumbers.INSTANCE.getDataVersion())); return rawComponents; From 321d1ae05d8124154cfe78f9c730a0e0b13a4d20 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 7 Mar 2026 22:43:35 +0000 Subject: [PATCH 078/169] `inventory` command: fix value-less adjusts --- .../denizen/scripts/commands/item/InventoryCommand.java | 3 ++- .../denizen/scripts/commands/player/ChatCommand.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/item/InventoryCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/item/InventoryCommand.java index 1bac8fa481..fe00ec1e52 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/item/InventoryCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/item/InventoryCommand.java @@ -442,7 +442,8 @@ else if (destination.getIdHolder() instanceof EntityTag entity && entity.getLivi } ItemTag toAdjust = new ItemTag(destination.getInventory().getItem(slotId)); Argument mechanismArgument = new Argument(dataAction); - toAdjust.safeAdjust(new Mechanism(mechanismArgument.getPrefix().getValue(), mechanismArgument.object, scriptEntry.getContext())); + boolean hasValue = mechanismArgument.hasPrefix(); + toAdjust.safeAdjust(new Mechanism(hasValue ? mechanismArgument.getPrefix().getValue() : mechanismArgument.getValue(), hasValue ? mechanismArgument.object : null, scriptEntry.getContext())); NMSHandler.itemHelper.setInventoryItem(destination.getInventory(), toAdjust.getItemStack(), slotId); break; case FLAG: diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ChatCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ChatCommand.java index 552a8c2de2..8fcb71877f 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ChatCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ChatCommand.java @@ -18,6 +18,7 @@ import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.ai.speech.Talkable; import net.citizensnpcs.api.ai.speech.TalkableEntity; import net.citizensnpcs.api.ai.speech.event.NPCSpeechEvent; @@ -137,7 +138,7 @@ public static void autoExecute(ScriptEntry scriptEntry, public static void speak(DenizenSpeechContext speechContext) { Entity talker = speechContext.getTalker().getEntity(); if (EntityTag.isCitizensNPC(talker)) { - NPCSpeechEvent event = new NPCSpeechEvent(speechContext); + NPCSpeechEvent event = new NPCSpeechEvent(CitizensAPI.getNPCRegistry().getNPC(talker), speechContext); Bukkit.getPluginManager().callEvent(event); if (event.isCancelled()) { return; 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 079/169] 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 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 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 dataItem = dataItemsById.get(id); + if (dataItem == null) { + Debug.echoError("Invalid internal data id '" + id + "': couldn't be matched to any internal data for entity of type '" + entity.getType() + "'."); + return; + } + Object converted = ReflectionSetCommand.convertObjectTypeFor(dataItem.getValue().getClass(), entry.getValue()); + if (converted != null) { + processConverted.accept(dataItem, converted); + } + } + } + + @Override + public List convertInternalEntityDataValues(Entity entity, MapTag internalData) { + List dataValues = new ArrayList<>(internalData.size()); + convertToInternalData(entity, internalData, (dataItem, converted) -> dataValues.add(PacketHelperImpl.createEntityData(dataItem.getAccessor(), converted))); + return dataValues; + } + + @Override + public void modifyInternalEntityData(Entity entity, MapTag internalData) { + SynchedEntityData nmsEntityData = ((CraftEntity) entity).getHandle().getEntityData(); + convertToInternalData(entity, internalData, (dataItem, converted) -> nmsEntityData.set(dataItem.getAccessor(), converted)); + } + + @Override + public void startUsingItem(LivingEntity entity, EquipmentSlot hand) { + ((CraftLivingEntity) entity).getHandle().startUsingItem(hand == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); + } + + @Override + public void stopUsingItem(LivingEntity entity) { + ((CraftLivingEntity) entity).getHandle().stopUsingItem(); + } + + @Override + public void openHorseInventory(Player player, AbstractHorse horse) { + net.minecraft.world.entity.animal.equine.AbstractHorse nmsHorse = ((CraftAbstractHorse) horse).getHandle(); + ((CraftPlayer) player).getHandle().openHorseInventory(nmsHorse, nmsHorse.inventory); + } + + private CompoundTag getRawEntityNBT(net.minecraft.world.entity.Entity entity) { + return Handler.useValueOutput(entity::saveWithoutId); + } + + @Override + public CompoundBinaryTag getRawNBT(Entity entity) { + return NBTAdapter.toAPI(getRawEntityNBT(((CraftEntity) entity).getHandle())); + } + + @Override + public void modifyRawNBT(Entity entity, CompoundBinaryTag tag) { + net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle(); + CompoundTag nmsTag = NBTAdapter.toNMS(tag); + CompoundTag nmsMergedTag = getRawEntityNBT(nmsEntity).merge(nmsTag); + UUID uuid = nmsEntity.getUUID(); + Handler.useValueInput(nmsMergedTag, nmsEntity::load); + nmsEntity.setUUID(uuid); + } + + @Override + public EntityState.ArmadilloState getArmadilloState(org.bukkit.entity.Armadillo entity) { + Armadillo armadillo = (Armadillo) ((CraftEntity) entity).getHandle(); + return switch (armadillo.getState()) { + case IDLE -> EntityState.ArmadilloState.IDLE; + case ROLLING -> EntityState.ArmadilloState.ROLLING; + case SCARED -> EntityState.ArmadilloState.SCARED; + case UNROLLING -> EntityState.ArmadilloState.UNROLLING; + }; + } + + @Override + public void setArmadilloState(org.bukkit.entity.Armadillo entity, EntityState.ArmadilloState state) { + Armadillo armadillo = (Armadillo) ((CraftEntity) entity).getHandle(); + armadillo.switchToState(switch (state) { + case IDLE -> Armadillo.ArmadilloState.IDLE; + case ROLLING -> Armadillo.ArmadilloState.ROLLING; + case SCARED -> Armadillo.ArmadilloState.SCARED; + case UNROLLING -> Armadillo.ArmadilloState.UNROLLING; + }); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java new file mode 100644 index 0000000000..a6cd25a56c --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java @@ -0,0 +1,157 @@ +package com.denizenscript.denizen.nms.v1_21.helpers; + +import com.denizenscript.denizen.nms.interfaces.FishingHelper; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.projectile.FishingHook; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.level.storage.loot.BuiltInLootTables; +import net.minecraft.world.level.storage.loot.LootParams; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftFishHook; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; +import org.bukkit.entity.FishHook; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.Field; +import java.util.List; + +public class FishingHelperImpl implements FishingHelper { + + @Override + public org.bukkit.inventory.ItemStack getResult(FishHook fishHook, CatchType catchType) { + FishingHook nmsHook = ((CraftFishHook) fishHook).getHandle(); + ItemStack result = switch (catchType) { + case DEFAULT -> { + ServerLevel nmsWorld = ((CraftWorld) fishHook.getWorld()).getHandle(); + ItemStack nmsFishingRod = nmsHook.getPlayerOwner().getMainHandItem(); + float f = nmsWorld.random.nextFloat(); + float i = EnchantmentHelper.getFishingTimeReduction(nmsWorld, nmsFishingRod, nmsHook.getPlayerOwner()); + int j = EnchantmentHelper.getFishingLuckBonus(nmsWorld, nmsFishingRod, nmsHook.getPlayerOwner()); + float f1 = 0.1F - i * 0.025F - (float) j * 0.01F; + float f2 = 0.05F + i * 0.01F - (float) j * 0.01F; + + f1 = Mth.clamp(f1, 0.0F, 1.0F); + f2 = Mth.clamp(f2, 0.0F, 1.0F); + if (f < f1) { + yield catchRandomJunk(nmsHook); + } + else { + f -= f1; + if (f < f2) { + yield catchRandomTreasure(nmsHook); + } + else { + yield catchRandomFish(nmsHook); + } + } + } + case JUNK -> catchRandomJunk(nmsHook); + case TREASURE -> catchRandomTreasure(nmsHook); + case FISH -> catchRandomFish(nmsHook); + default -> null; + }; + return result != null ? CraftItemStack.asBukkitCopy(result) : null; + } + + public ItemStack getRandomReward(FishingHook nmsHook, ResourceKey key) { + ServerLevel nmsWorld = (ServerLevel) nmsHook.level(); + LootParams nmsLootParams = new LootParams.Builder(nmsWorld) + .withParameter(LootContextParams.ORIGIN, new Vec3(nmsHook.getX(), nmsHook.getY(), nmsHook.getZ())) + .withParameter(LootContextParams.TOOL, new ItemStack(Items.FISHING_ROD)) + .create(LootContextParamSets.FISHING); + List nmsItems = nmsWorld.getServer().reloadableRegistries().getLootTable(key).getRandomItems(nmsLootParams); + return nmsItems.get(nmsWorld.random.nextInt(nmsItems.size())); + } + + @Override + public FishHook spawnHook(Location location, Player player) { + ServerLevel nmsWorld = ((CraftWorld) location.getWorld()).getHandle(); + FishingHook hook = new FishingHook(((CraftPlayer) player).getHandle(), nmsWorld, 0, 0); + nmsWorld.addFreshEntity(hook, CreatureSpawnEvent.SpawnReason.CUSTOM); + return (FishHook) hook.getBukkitEntity(); + } + + private ItemStack catchRandomJunk(FishingHook fishHook) { + return getRandomReward(fishHook, BuiltInLootTables.FISHING_JUNK); + } + + private ItemStack catchRandomTreasure(FishingHook fishHook) { + return getRandomReward(fishHook, BuiltInLootTables.FISHING_TREASURE); + } + + private ItemStack catchRandomFish(FishingHook fishHook) { + return getRandomReward(fishHook, BuiltInLootTables.FISHING_FISH); + } + + public static final Field FISHING_HOOK_NIBBLE = ReflectionHelper.getFields(FishingHook.class).get(ReflectionMappingsInfo.FishingHook_nibble, int.class); + public static final Field FISHING_HOOK_LURE_TIME = ReflectionHelper.getFields(FishingHook.class).get(ReflectionMappingsInfo.FishingHook_timeUntilLured, int.class); + public static final Field FISHING_HOOK_HOOK_TIME = ReflectionHelper.getFields(FishingHook.class).get(ReflectionMappingsInfo.FishingHook_timeUntilHooked, int.class); + + @Override + public FishHook getHookFrom(Player player) { + FishingHook nmsHook = ((CraftPlayer) player).getHandle().fishing; + if (nmsHook == null) { + return null; + } + return (FishHook) nmsHook.getBukkitEntity(); + } + + @Override + public void setNibble(FishHook hook, int ticks) { + FishingHook nmsHook = ((CraftFishHook) hook).getHandle(); + try { + FISHING_HOOK_NIBBLE.setInt(nmsHook, ticks); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void setHookTime(FishHook hook, int ticks) { + FishingHook nmsHook = ((CraftFishHook) hook).getHandle(); + try { + FISHING_HOOK_HOOK_TIME.setInt(nmsHook, ticks); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public int getLureTime(FishHook hook) { + FishingHook nmsHook = ((CraftFishHook) hook).getHandle(); + try { + return FISHING_HOOK_LURE_TIME.getInt(nmsHook); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return -1; + } + + @Override + public void setLureTime(FishHook hook, int ticks) { + FishingHook nmsHook = ((CraftFishHook) hook).getHandle(); + try { + FISHING_HOOK_LURE_TIME.setInt(nmsHook, ticks); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java new file mode 100644 index 0000000000..5ab295a2d6 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java @@ -0,0 +1,779 @@ +package com.denizenscript.denizen.nms.v1_21.helpers; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.interfaces.ItemHelper; +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.ItemTag; +import com.denizenscript.denizen.objects.properties.item.ItemComponentsPatch; +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.core.ElementTag; +import com.denizenscript.denizencore.objects.core.MapTag; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.collect.*; +import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.JsonOps; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.advancements.criterion.BlockPredicate; +import net.minecraft.advancements.criterion.DataComponentMatchers; +import net.minecraft.core.*; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.item.AdventureModePredicate; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.alchemy.PotionBrewing; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ItemLore; +import net.minecraft.world.item.component.ResolvableProfile; +import net.minecraft.world.item.component.TypedEntityData; +import net.minecraft.world.item.crafting.*; +import net.minecraft.world.item.crafting.BlastingRecipe; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.ShapelessRecipe; +import net.minecraft.world.item.crafting.SmithingTransformRecipe; +import net.minecraft.world.item.crafting.SmokingRecipe; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.level.saveddata.maps.MapId; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.data.BlockData; +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.entity.CraftEntityType; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R7.inventory.*; +import org.bukkit.craftbukkit.v1_21_R7.map.CraftMapView; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.*; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.SmithingTrimRecipe; +import org.bukkit.inventory.TransmuteRecipe; +import org.bukkit.map.MapView; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class ItemHelperImpl extends ItemHelper { + + public static net.minecraft.world.item.crafting.RecipeHolder getNMSRecipe(NamespacedKey key) { + ResourceKey> nmsKey = ResourceKey.create(Registries.RECIPE, CraftNamespacedKey.toMinecraft(key)); + return ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager().byKey(nmsKey).orElse(null); + } + + public static final Field Item_components = ReflectionHelper.getFields(Item.class).get(ReflectionMappingsInfo.Item_components, DataComponentMap.class); + + public static final Field RecipeManager_featureFlagSet = ReflectionHelper.getFields(RecipeManager.class).getFirstOfType(FeatureFlagSet.class); + + public void setMaxStackSize(Material material, int size) { + try { + ReflectionHelper.getFinalSetter(Material.class, "maxStack").invoke(material, size); + Item nmsItem = BuiltInRegistries.ITEM.getValue(CraftNamespacedKey.toMinecraft(material.getKey())); + DataComponentMap currentComponents = nmsItem.components(); + Item_components.set(nmsItem, DataComponentMap.composite(currentComponents, DataComponentMap.builder().set(DataComponents.MAX_STACK_SIZE, size).build())); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public static RecipeManager getRecipeManager() { + return ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager(); + } + + public static CompoundTag serializeNmsItem(net.minecraft.world.item.ItemStack nmsItem) { + return (CompoundTag) net.minecraft.world.item.ItemStack.CODEC.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE), nmsItem).getOrThrow(); + } + + public static net.minecraft.world.item.ItemStack parseNmsItem(CompoundTag nmsTag) { + return net.minecraft.world.item.ItemStack.CODEC.parse(CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE), nmsTag).getOrThrow(); + } + + public Object recipeManagerFeatureFlagSetCache = null; + + @Override + public void blockRecipeFinalization() { + try { + RecipeManager manager = getRecipeManager(); + Object flags = RecipeManager_featureFlagSet.get(manager); + if (flags != null) { + recipeManagerFeatureFlagSetCache = flags; + RecipeManager_featureFlagSet.set(manager, null); + + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void restoreRecipeFinalization() { + try { + RecipeManager manager = getRecipeManager(); + if (recipeManagerFeatureFlagSetCache != null) { + RecipeManager_featureFlagSet.set(manager, recipeManagerFeatureFlagSetCache); + manager.finalizeRecipeLoading(); + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void removeRecipes(List keys) { + blockRecipeFinalization(); + RecipeManager manager = getRecipeManager(); + for (NamespacedKey key: keys) { + ResourceKey> nmsKey = ResourceKey.create(Registries.RECIPE, CraftNamespacedKey.toMinecraft(key)); + manager.removeRecipe(nmsKey); + } + restoreRecipeFinalization(); + } + + @Override + public Integer burnTime(Material material) { + return MinecraftServer.getServer().fuelValues().burnDuration(new net.minecraft.world.item.ItemStack(CraftMagicNumbers.getItem(material))); + } + + @Override + public void setShapedRecipeIngredient(ShapedRecipe recipe, char c, ItemStack[] item, boolean exact) { + if (item.length == 1 && item[0].getType() == Material.AIR) { + recipe.setIngredient(c, new RecipeChoice.MaterialChoice(Material.AIR)); + } + else if (exact) { + recipe.setIngredient(c, new RecipeChoice.ExactChoice(item)); + } + else { + Material[] mats = new Material[item.length]; + for (int i = 0; i < item.length; i++) { + mats[i] = item[i].getType(); + } + recipe.setIngredient(c, new RecipeChoice.MaterialChoice(mats)); + } + } + + // TODO: Recipe registration should be moved to the API + public static Ingredient itemArrayToRecipe(ItemStack[] items, boolean exact) { + if (!exact) { + return Ingredient.of(Arrays.stream(items).map(item -> CraftMagicNumbers.getItem(item.getType()))); + } + return Ingredient.ofStacks(Arrays.stream(items).map(CraftItemStack::asNMSCopy).toList()); + } + + public static ResourceKey> createRecipeKey(String name) { + return ResourceKey.create(Registries.RECIPE, Identifier.fromNamespaceAndPath("denizen", name)); + } + + @Override + public void registerFurnaceRecipe(String keyName, String group, ItemStack result, ItemStack[] ingredient, float exp, int time, String type, boolean exact, String category) { + ResourceKey> key = createRecipeKey(keyName); + Ingredient itemRecipe = itemArrayToRecipe(ingredient, exact); + AbstractCookingRecipe recipe; + CookingBookCategory categoryValue = category == null ? CookingBookCategory.MISC : CookingBookCategory.valueOf(CoreUtilities.toUpperCase(category)); + if (type.equalsIgnoreCase("smoker")) { + recipe = new SmokingRecipe(group, categoryValue, itemRecipe, CraftItemStack.asNMSCopy(result), exp, time); + } + else if (type.equalsIgnoreCase("blast")) { + recipe = new BlastingRecipe(group, categoryValue, itemRecipe, CraftItemStack.asNMSCopy(result), exp, time); + } + else if (type.equalsIgnoreCase("campfire")) { + recipe = new CampfireCookingRecipe(group, categoryValue, itemRecipe, CraftItemStack.asNMSCopy(result), exp, time); + } + else { + recipe = new SmeltingRecipe(group, categoryValue, itemRecipe, CraftItemStack.asNMSCopy(result), exp, time); + } + RecipeHolder holder = new RecipeHolder<>(key, recipe); + getRecipeManager().addRecipe(holder); + } + + @Override + public void registerStonecuttingRecipe(String keyName, String group, ItemStack result, ItemStack[] ingredient, boolean exact) { + ResourceKey> key = createRecipeKey(keyName); + Ingredient itemRecipe = itemArrayToRecipe(ingredient, exact); + StonecutterRecipe recipe = new StonecutterRecipe(group, itemRecipe, CraftItemStack.asNMSCopy(result)); + RecipeHolder holder = new RecipeHolder<>(key, recipe); + getRecipeManager().addRecipe(holder); + } + + @Override + public void registerSmithingRecipe(String keyName, ItemStack result, ItemStack[] baseItem, boolean baseExact, ItemStack[] upgradeItem, boolean upgradeExact, ItemStack[] templateItem, boolean templateExact) { + ResourceKey> key = createRecipeKey(keyName); + Ingredient templateItemRecipe = templateItem.length == 0 ? null : itemArrayToRecipe(templateItem, templateExact); + Ingredient baseItemRecipe = itemArrayToRecipe(baseItem, baseExact); + Ingredient upgradeItemRecipe = itemArrayToRecipe(upgradeItem, upgradeExact); + net.minecraft.world.item.ItemStack nmsCopy = CraftItemStack.asNMSCopy(result); + SmithingTransformRecipe recipe = new SmithingTransformRecipe(Optional.ofNullable(templateItemRecipe), baseItemRecipe, Optional.of(upgradeItemRecipe), new TransmuteResult(nmsCopy.getItemHolder(), nmsCopy.getCount(), nmsCopy.getComponentsPatch())); + RecipeHolder holder = new RecipeHolder<>(key, recipe); + getRecipeManager().addRecipe(holder); + } + + @Override + public void registerShapelessRecipe(String keyName, String group, ItemStack result, List ingredients, boolean[] exact, String category) { + ResourceKey> key = createRecipeKey(keyName); + ArrayList ingredientList = new ArrayList<>(); + CraftingBookCategory categoryValue = category == null ? CraftingBookCategory.MISC : CraftingBookCategory.valueOf(CoreUtilities.toUpperCase(category)); + for (int i = 0; i < ingredients.size(); i++) { + ingredientList.add(itemArrayToRecipe(ingredients.get(i), exact[i])); + } + // TODO: 1.19.3: Add support for choosing a CraftingBookCategory + ShapelessRecipe recipe = new ShapelessRecipe(group, categoryValue, CraftItemStack.asNMSCopy(result), NonNullList.of(null, ingredientList.toArray(new Ingredient[0]))); + RecipeHolder holder = new RecipeHolder<>(key, recipe); + getRecipeManager().addRecipe(holder); + } + + @Override + public void registerOtherRecipe(org.bukkit.inventory.Recipe recipe) { + // This method copied from Bukkit CraftServer source, just to bypass unwanted paper patch + CraftRecipe toAdd; + if (recipe instanceof CraftRecipe craft) { + toAdd = craft; + } + else if (recipe instanceof ShapedRecipe) { + toAdd = CraftShapedRecipe.fromBukkitRecipe((ShapedRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.ShapelessRecipe) { + toAdd = CraftShapelessRecipe.fromBukkitRecipe((org.bukkit.inventory.ShapelessRecipe)recipe); + } + else if (recipe instanceof FurnaceRecipe) { + toAdd = CraftFurnaceRecipe.fromBukkitRecipe((FurnaceRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.BlastingRecipe) { + toAdd = CraftBlastingRecipe.fromBukkitRecipe((org.bukkit.inventory.BlastingRecipe)recipe); + } + else if (recipe instanceof CampfireRecipe) { + toAdd = CraftCampfireRecipe.fromBukkitRecipe((CampfireRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.SmokingRecipe) { + toAdd = CraftSmokingRecipe.fromBukkitRecipe((org.bukkit.inventory.SmokingRecipe)recipe); + } + else if (recipe instanceof StonecuttingRecipe) { + toAdd = CraftStonecuttingRecipe.fromBukkitRecipe((StonecuttingRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.SmithingTransformRecipe) { + toAdd = CraftSmithingTransformRecipe.fromBukkitRecipe((org.bukkit.inventory.SmithingTransformRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.SmithingTrimRecipe) { + toAdd = CraftSmithingTrimRecipe.fromBukkitRecipe((SmithingTrimRecipe)recipe); + } + else { + if (!(recipe instanceof org.bukkit.inventory.TransmuteRecipe)) { + if (recipe instanceof ComplexRecipe) { + throw new UnsupportedOperationException("Cannot add custom complex recipe"); + } + return; + } + toAdd = CraftTransmuteRecipe.fromBukkitRecipe((TransmuteRecipe)recipe); + } + toAdd.addToCraftingManager(); + } + + @Override + public String getJsonString(ItemStack itemStack) { + String json = CraftItemStack.asNMSCopy(itemStack).getDisplayName().getStyle().toString().replace("\\", "\\\\").replace("\"", "\\\""); + return json.substring(176, json.length() - 185); + } + + @Override + public JsonObject getRawHoverComponentsJson(ItemStack item) { + DataComponentPatch nmsComponents = CraftItemStack.asNMSCopy(item).getComponentsPatch(); + if (nmsComponents.isEmpty()) { + return null; + } + return DataComponentPatch.CODEC.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE), nmsComponents).getOrThrow().getAsJsonObject(); + } + + @Override + public ItemStack applyRawHoverComponentsJson(ItemStack item, JsonObject components) { + return DataComponentPatch.CODEC.parse(CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE), components).mapOrElse( + nmsComponents -> { + net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); + nmsItem.applyComponents(nmsComponents); + return CraftItemStack.asCraftMirror(nmsItem); + }, + error -> { + Debug.echoError("Invalid hover item data '" + components + "': " + error.message()); + return item; + }); + } + + @Override + public PlayerProfile getSkullSkin(ItemStack is) { + net.minecraft.world.item.ItemStack itemStack = CraftItemStack.asNMSCopy(is); + ResolvableProfile profile = itemStack.get(DataComponents.PROFILE); + if (profile != null) { + 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, + property != null ? property.signature() : null); + } + return null; + } + + @Override + public ItemStack setSkullSkin(ItemStack itemStack, PlayerProfile playerProfile) { + GameProfile gameProfile = ProfileEditorImpl.getGameProfile(playerProfile); + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); + nmsItemStack.set(DataComponents.PROFILE, ResolvableProfile.createResolved(gameProfile)); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + @Override + public ItemStack addNbtData(ItemStack itemStack, String key, BinaryTag value) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); + nmsItemStack.update(DataComponents.CUSTOM_DATA, CustomData.EMPTY, customData -> customData.update(nmsCompoundTag -> nmsCompoundTag.put(key, NBTAdapter.toNMS(value)))); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + // TODO: 1.20.6: this now needs to serialize components into NBT every single time, should probably only return custom NBT data with specialized methods for other usages + // TODO: 1.20.6: NBT structure is different basically everywhere, usages of this will need an update + @Override + public CompoundBinaryTag getNbtData(ItemStack itemStack) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); + if (nmsItemStack != null && !nmsItemStack.isEmpty()) { + return NBTAdapter.toAPI(serializeNmsItem(nmsItemStack)); + } + return CompoundBinaryTag.empty(); + } + + // TODO: 1.20.6: same as getNbtData, ideally needs to only set custom NBT data and have specialized methods for other usages + @Override + public ItemStack setNbtData(ItemStack itemStack, CompoundBinaryTag compoundTag) { + return CraftItemStack.asBukkitCopy(parseNmsItem(NBTAdapter.toNMS(compoundTag))); + } + + @Override + public CompoundBinaryTag getCustomData(ItemStack item) { + CustomData customData = CraftItemStack.asNMSCopy(item).get(DataComponents.CUSTOM_DATA); + return customData != null ? NBTAdapter.toAPI(customData.copyTag()) : null; + } + + @Override + public ItemStack setCustomData(ItemStack item, CompoundBinaryTag data) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + if (data == null) { + nmsItemStack.remove(DataComponents.CUSTOM_DATA); + } + else { + nmsItemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(NBTAdapter.toNMS(data))); + } + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + public static final int DATA_VERSION_1_20_4 = 3700; + + @Override + public ItemStack setPartialOldNbt(ItemStack item, CompoundBinaryTag oldTag) { + int currentDataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + CompoundTag nmsOldTag = new CompoundTag(); + nmsOldTag.putString("id", item.getType().getKey().toString()); + nmsOldTag.putByte("Count", (byte) item.getAmount()); + nmsOldTag.put("tag", NBTAdapter.toNMS(oldTag)); + CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, nmsOldTag), DATA_VERSION_1_20_4, currentDataVersion).getValue(); + CompoundTag nmsCurrentTag = serializeNmsItem(CraftItemStack.asNMSCopy(item)); + CompoundTag nmsMergedTag = nmsCurrentTag.merge(nmsUpdatedTag); + return CraftItemStack.asBukkitCopy(parseNmsItem(nmsMergedTag)); + } + + @Override + public CompoundBinaryTag getEntityData(ItemStack item) { + TypedEntityData> entityData = CraftItemStack.asNMSCopy(item).get(DataComponents.ENTITY_DATA); + return entityData != null ? NBTAdapter.toAPI(entityData.getUnsafe()) : null; + } + + @Override + public ItemStack setEntityData(ItemStack item, CompoundBinaryTag entityNbt, EntityType entityType) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + if (entityNbt == null || entityNbt.isEmpty() || (entityNbt.size() == 1 && entityNbt.contains("id"))) { + nmsItemStack.remove(DataComponents.ENTITY_DATA); + } + else { + CompoundTag nmsEntityNbt = NBTAdapter.toNMS(entityNbt); + nmsEntityNbt.remove("id"); + nmsItemStack.set(DataComponents.ENTITY_DATA, TypedEntityData.of(CraftEntityType.bukkitToMinecraft(entityType), nmsEntityNbt)); + } + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + @Override + public MapTag getRawComponentsPatch(ItemStack item, boolean excludeHandled) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + DataComponentPatch patch = nmsItemStack.getComponentsPatch(); + if (excludeHandled) { + patch = patch.forget(componentType -> { + Identifier componentId = BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(componentType); + return ItemComponentsPatch.propertyHandledComponents.contains(componentId.toString()); + }); + } + if (patch.isEmpty()) { + return new MapTag(); + } + RegistryOps registryOps = CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE); + CompoundTag nmsPatch = (CompoundTag) DataComponentPatch.CODEC.encodeStart(registryOps, patch).getOrThrow(); + if (excludeHandled && Denizen.supportsPaper) { + nmsPatch.keySet().removeIf(s -> s.charAt(0) == '!'); + if (nmsPatch.isEmpty()) { + return new MapTag(); + } + } + MapTag rawComponents = (MapTag) ItemRawNBT.nbtTagToObject(NBTAdapter.toAPI(nmsPatch)); + rawComponents.putObject(ItemComponentsPatch.DATA_VERSION_KEY, new ElementTag(CraftMagicNumbers.INSTANCE.getDataVersion())); + return rawComponents; + } + + @Override + public ItemStack setRawComponentsPatch(ItemStack item, MapTag rawComponentsMap, int dataVersion, Consumer errorHandler) { + int currentDataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + CompoundBinaryTag rawComponents = (CompoundBinaryTag) ItemRawNBT.convertObjectToNbt(rawComponentsMap, CoreUtilities.errorButNoDebugContext, ""); + CompoundTag nmsRawComponents = NBTAdapter.toNMS(rawComponents); + RegistryOps registryOps = CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE); + if (dataVersion < currentDataVersion) { + CompoundTag legacyItemData = new CompoundTag(); + legacyItemData.putString("id", item.getType().getKey().toString()); + legacyItemData.putInt("count", item.getAmount()); + legacyItemData.put("components", nmsRawComponents); + CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(registryOps, legacyItemData), dataVersion, currentDataVersion).getValue(); + nmsRawComponents = nmsUpdatedTag.getCompound("components").orElseGet(CompoundTag::new); + } + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + DataComponentPatch.CODEC.parse(registryOps, nmsRawComponents) + .ifError(error -> errorHandler.accept(error.message())) + .ifSuccess(nmsItemStack::applyComponents); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + public static final Field AdventureModePredicate_predicates = ReflectionHelper.getFields(AdventureModePredicate.class).get(ReflectionMappingsInfo.AdventureModePredicate_predicates); + + @Override + public List getCanPlaceOn(ItemStack item) { + return getAdventureModePredicateMaterials(item, DataComponents.CAN_PLACE_ON); + } + + @Override + public ItemStack setCanPlaceOn(ItemStack item, List canPlaceOn) { + return setAdventureModePredicateMaterials(item, DataComponents.CAN_PLACE_ON, canPlaceOn); + } + + @Override + public List getCanBreak(ItemStack item) { + return getAdventureModePredicateMaterials(item, DataComponents.CAN_BREAK); + } + + @Override + public ItemStack setCanBreak(ItemStack item, List canBreak) { + return setAdventureModePredicateMaterials(item, DataComponents.CAN_BREAK, canBreak); + } + + private List getAdventureModePredicateMaterials(ItemStack item, DataComponentType nmsComponent) { + AdventureModePredicate nmsAdventurePredicate = CraftItemStack.asNMSCopy(item).get(nmsComponent); + if (nmsAdventurePredicate == null) { + return null; + } + List nmsPredicates; + try { + nmsPredicates = (List) AdventureModePredicate_predicates.get(nmsAdventurePredicate); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + List materials = new ArrayList<>(); + for (BlockPredicate nmsPredicate : nmsPredicates) { + nmsPredicate.blocks().ifPresent(nmsHolderSet -> { + for (Holder nmsHolder : nmsHolderSet) { + materials.add(CraftMagicNumbers.getMaterial(nmsHolder.value())); + } + }); + } + return materials; + } + + private ItemStack setAdventureModePredicateMaterials(ItemStack item, DataComponentType nmsComponent, List materials) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + AdventureModePredicate nmsAdventurePredicate = nmsItemStack.get(nmsComponent); + if (materials == null) { + if (nmsAdventurePredicate == null) { + return item; + } + nmsItemStack.remove(nmsComponent); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + BlockPredicate nmsPredicate = new BlockPredicate(Optional.of( + HolderSet.direct(material -> BuiltInRegistries.BLOCK.get(CraftNamespacedKey.toMinecraft(material.getKey())).orElseThrow(), materials) + ), Optional.empty(), Optional.empty(), DataComponentMatchers.ANY); + nmsItemStack.set(nmsComponent, new AdventureModePredicate(List.of(nmsPredicate))); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + @Override + public void setInventoryItem(Inventory inventory, ItemStack item, int slot) { + if (inventory instanceof CraftInventoryPlayer && ((CraftInventoryPlayer) inventory).getInventory().player == null) { + ((CraftInventoryPlayer) inventory).getInventory().setItem(slot, CraftItemStack.asNMSCopy(item)); + } + else { + inventory.setItem(slot, item); + } + } + + @Override + public String getDisplayName(ItemTag item) { + if (!item.getItemMeta().hasDisplayName()) { + return null; + } + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); + Component nmsDisplayName = nmsItemStack.get(DataComponents.CUSTOM_NAME); + return FormattedTextHelper.stringify(Handler.componentToSpigot(nmsDisplayName)); + } + + @Override + public List getLore(ItemTag item) { + if (!item.getItemMeta().hasLore()) { + return null; + } + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); + ItemLore nmsLore = nmsItemStack.get(DataComponents.LORE); + List outList = new ArrayList<>(nmsLore.lines().size()); + for (Component nmsLoreLine : nmsLore.lines()) { + outList.add(FormattedTextHelper.stringify(Handler.componentToSpigot(nmsLoreLine))); + } + return outList; + } + + @Override + public void setDisplayName(ItemTag item, String name) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); + if (name == null || name.isEmpty()) { + nmsItemStack.remove(DataComponents.CUSTOM_NAME); + } + else { + nmsItemStack.set(DataComponents.CUSTOM_NAME, Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE))); + } + item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); + } + + @Override + public void setLore(ItemTag item, List lore) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); + if (lore == null || lore.isEmpty()) { + nmsItemStack.remove(DataComponents.LORE); + } + else { + List nmsLore = new ArrayList<>(lore.size()); + for (String loreLine : lore) { + nmsLore.add(Handler.componentToNMS(FormattedTextHelper.parse(loreLine, ChatColor.WHITE))); + } + nmsItemStack.set(DataComponents.LORE, new ItemLore(nmsLore)); + } + item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); + } + + /** + * Copied from MapItem.getCorrectStateForFluidBlock. + */ + public static BlockState getCorrectStateForFluidBlock(Level world, BlockState blockState, BlockPos blockPos) { + FluidState fluid = blockState.getFluidState(); + return !fluid.isEmpty() && !blockState.isFaceSturdy(world, blockPos, Direction.UP) ? fluid.createLegacyBlock() : blockState; + } + + /** + * Copied from MapItem.update, redesigned slightly to render totally rather than just relative to a player. + * Some variables manually renamed for readability. + */ + public static void renderFullMap(MapItemSavedData worldmap, int xMin, int zMin, int xMax, int zMax) { + Level world = ((CraftWorld) worldmap.mapView.getWorld()).getHandle(); + int scale = 1 << worldmap.scale; + int mapX = worldmap.centerX; + int mapZ = worldmap.centerZ; + for (int x = xMin; x < xMax; x++) { + double d0 = 0.0D; + for (int z = zMin; z < zMax; z++) { + int k2 = (mapX / scale + x - 64) * scale; + int l2 = (mapZ / scale + z - 64) * scale; + Multiset multiset = LinkedHashMultiset.create(); + LevelChunk chunk = world.getChunkAt(new BlockPos(k2, 0, l2)); + if (!chunk.isEmpty()) { + ChunkPos chunkcoordintpair = chunk.getPos(); + int i3 = k2 & 15; + int j3 = l2 & 15; + int k3 = 0; + double d1 = 0.0D; + if (world.dimensionType().hasCeiling()) { + int l3 = k2 + l2 * 231871; + l3 = l3 * l3 * 31287121 + l3 * 11; + if ((l3 >> 20 & 1) == 0) { + multiset.add(Blocks.DIRT.defaultBlockState().getMapColor(world, BlockPos.ZERO), 10); + } + else { + multiset.add(Blocks.STONE.defaultBlockState().getMapColor(world, BlockPos.ZERO), 100); + } + + d1 = 100.0D; + } + else { + BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); + BlockPos.MutableBlockPos blockposition_mutableblockposition1 = new BlockPos.MutableBlockPos(); + for (int i4 = 0; i4 < scale; ++i4) { + for (int j4 = 0; j4 < scale; ++j4) { + int k4 = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i4 + i3, j4 + j3) + 1; + BlockState iblockdata; + if (k4 <= world.getMinY() + 1) { + iblockdata = Blocks.BEDROCK.defaultBlockState(); + } + else { + do { + --k4; + blockposition_mutableblockposition.set(chunkcoordintpair.getMinBlockX() + i4 + i3, k4, chunkcoordintpair.getMinBlockZ() + j4 + j3); + iblockdata = chunk.getBlockState(blockposition_mutableblockposition); + } while (iblockdata.getMapColor(world, blockposition_mutableblockposition) == MapColor.NONE && k4 > world.getMinY()); + if (k4 > world.getMinY() && !iblockdata.getFluidState().isEmpty()) { + int l4 = k4 - 1; + blockposition_mutableblockposition1.set(blockposition_mutableblockposition); + + BlockState iblockdata1; + do { + blockposition_mutableblockposition1.setY(l4--); + iblockdata1 = chunk.getBlockState(blockposition_mutableblockposition1); + k3++; + } while (l4 > world.getMinY() && !iblockdata1.getFluidState().isEmpty()); + iblockdata = getCorrectStateForFluidBlock(world, iblockdata, blockposition_mutableblockposition); + } + } + worldmap.checkBanners(world, chunkcoordintpair.getMinBlockX() + i4 + i3, chunkcoordintpair.getMinBlockZ() + j4 + j3); + d1 += (double) k4 / (double) (scale * scale); + multiset.add(iblockdata.getMapColor(world, blockposition_mutableblockposition)); + } + } + } + k3 /= scale * scale; + double d2 = (d1 - d0) * 4.0D / (double) (scale + 4) + ((double) (x + z & 1) - 0.5D) * 0.4D; + byte b0 = 1; + if (d2 > 0.6D) { + b0 = 2; + } + if (d2 < -0.6D) { + b0 = 0; + } + MapColor materialmapcolor = Iterables.getFirst(Multisets.copyHighestCountFirst(multiset), MapColor.NONE); + if (materialmapcolor == MapColor.WATER) { + d2 = (double) k3 * 0.1D + (double) (x + z & 1) * 0.2D; + b0 = 1; + if (d2 < 0.5D) { + b0 = 2; + } + if (d2 > 0.9D) { + b0 = 0; + } + } + d0 = d1; + worldmap.updateColor(x, z, (byte) (materialmapcolor.id * 4 + b0)); + } + } + } + } + + @Override + public boolean renderEntireMap(int mapId, int xMin, int zMin, int xMax, int zMax) { + MapItemSavedData worldmap = ((CraftServer) Bukkit.getServer()).getServer().getLevel(net.minecraft.world.level.Level.OVERWORLD).getMapData(new MapId(mapId)); + if (worldmap == null) { + return false; + } + renderFullMap(worldmap, xMin, zMin, xMax, zMax); + return true; + } + + @Override + public BlockData getPlacedBlock(Material material) { + Item nmsItem = BuiltInRegistries.ITEM.getOptional(CraftNamespacedKey.toMinecraft(material.getKey())).orElse(null); + if (nmsItem instanceof BlockItem) { + Block block = ((BlockItem) nmsItem).getBlock(); + return CraftBlockData.fromData(block.defaultBlockState()); + } + return null; + } + + @Override + public boolean isValidMix(ItemStack input, ItemStack ingredient) { + net.minecraft.world.item.ItemStack nmsInput = CraftItemStack.asNMSCopy(input); + net.minecraft.world.item.ItemStack nmsIngredient = CraftItemStack.asNMSCopy(ingredient); + return MinecraftServer.getServer().potionBrewing().hasMix(nmsInput, nmsIngredient); + } + + public static Class PaperPotionMix_CLASS = null; + public static Map customBrewingRecipes = null; + + @Override + public Map getCustomBrewingRecipes() { + if (customBrewingRecipes == null) { + customBrewingRecipes = Maps.transformValues((Map) ReflectionHelper.getFieldValue(PotionBrewing.class, "customMixes", MinecraftServer.getServer().potionBrewing()), paperMix -> { + if (PaperPotionMix_CLASS == null) { + PaperPotionMix_CLASS = paperMix.getClass(); + } + RecipeChoice ingredient = convertChoice(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "ingredient", paperMix)); + RecipeChoice input = convertChoice(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "input", paperMix)); + ItemStack result = CraftItemStack.asBukkitCopy(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "result", paperMix)); + return new BrewingRecipe(input, ingredient, result); + }); + } + return customBrewingRecipes; + } + + private RecipeChoice convertChoice(Predicate nmsPredicate) { + // Not an instance of net.minecraft.world.item.crafting.Ingredient = a predicate recipe choice + if (nmsPredicate instanceof Ingredient ingredient) { + return CraftRecipe.toBukkit(ingredient); + } + return PaperAPITools.instance.createPredicateRecipeChoice(item -> nmsPredicate.test(CraftItemStack.asNMSCopy(item))); + } + + @Override + public byte[] renderMap(MapView mapView, Player player) { + return ((CraftMapView) mapView).render((CraftPlayer) player).buffer; + } + + @Override + public int getFoodPoints(Material itemType) { + return CraftMagicNumbers.getItem(itemType).components().get(DataComponents.FOOD).nutrition(); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/NBTAdapter.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/NBTAdapter.java new file mode 100644 index 0000000000..427e1a62b3 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/NBTAdapter.java @@ -0,0 +1,143 @@ +package com.denizenscript.denizen.nms.v1_21.helpers; + +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import net.kyori.adventure.nbt.*; +import net.minecraft.nbt.*; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NBTAdapter { + + public static final MethodHandle COMPOUND_TAG_MAP_CONSTRUCTOR = ReflectionHelper.getConstructor(CompoundTag.class, Map.class); + + public static Tag toNMS(BinaryTag tag) { + if (tag instanceof ByteBinaryTag byteTag) { + return switch (byteTag.value()) { + case 0 -> ByteTag.ZERO; + case 1 -> ByteTag.ONE; + default -> ByteTag.valueOf(byteTag.value()); + }; + } + else if (tag instanceof ShortBinaryTag shortTag) { + return ShortTag.valueOf(shortTag.value()); + } + else if (tag instanceof IntBinaryTag intTag) { + return IntTag.valueOf(intTag.value()); + } + else if (tag instanceof LongBinaryTag longTag) { + return LongTag.valueOf(longTag.value()); + } + else if (tag instanceof FloatBinaryTag floatTag) { + return FloatTag.valueOf(floatTag.value()); + } + else if (tag instanceof DoubleBinaryTag doubleTag) { + return DoubleTag.valueOf(doubleTag.value()); + } + else if (tag instanceof ByteArrayBinaryTag byteArrayTag) { + return new ByteArrayTag(byteArrayTag.value()); + } + else if (tag instanceof IntArrayBinaryTag intArrayTag) { + return new IntArrayTag(intArrayTag.value()); + } + else if (tag instanceof LongArrayBinaryTag longArrayTag) { + return new LongArrayTag(longArrayTag.value()); + } + else if (tag instanceof StringBinaryTag stringTag) { + return StringTag.valueOf(stringTag.value()); + } + else if (tag instanceof ListBinaryTag listTag) { + return toNMS(listTag); + } + else if (tag instanceof CompoundBinaryTag compoundTag) { + return toNMS(compoundTag); + } + else if (tag instanceof EndBinaryTag) { + return EndTag.INSTANCE; + } + throw new IllegalStateException("Unrecognized API tag of type '" + tag.type() + "': " + tag); + } + + public static BinaryTag toAPI(Tag nmsTag) { + if (nmsTag instanceof ByteTag nmsByteTag) { + return ByteBinaryTag.byteBinaryTag(nmsByteTag.value()); + } + else if (nmsTag instanceof ShortTag nmsShortTag) { + return ShortBinaryTag.shortBinaryTag(nmsShortTag.value()); + } + else if (nmsTag instanceof IntTag nmsIntTag) { + return IntBinaryTag.intBinaryTag(nmsIntTag.value()); + } + else if (nmsTag instanceof LongTag nmsLongTag) { + return LongBinaryTag.longBinaryTag(nmsLongTag.value()); + } + else if (nmsTag instanceof FloatTag nmsFloatTag) { + return FloatBinaryTag.floatBinaryTag(nmsFloatTag.value()); + } + else if (nmsTag instanceof DoubleTag nmsDoubleTag) { + return DoubleBinaryTag.doubleBinaryTag(nmsDoubleTag.value()); + } + else if (nmsTag instanceof ByteArrayTag nmsByteArrayTag) { + return ByteArrayBinaryTag.byteArrayBinaryTag(nmsByteArrayTag.getAsByteArray()); + } + else if (nmsTag instanceof IntArrayTag nmsIntArrayTag) { + return IntArrayBinaryTag.intArrayBinaryTag(nmsIntArrayTag.getAsIntArray()); + } + else if (nmsTag instanceof LongArrayTag nmsLongArrayTag) { + return LongArrayBinaryTag.longArrayBinaryTag(nmsLongArrayTag.getAsLongArray()); + } + else if (nmsTag instanceof StringTag nmsStringTag) { + return StringBinaryTag.stringBinaryTag(nmsStringTag.value()); + } + else if (nmsTag instanceof ListTag nmsListTag) { + return toAPI(nmsListTag); + } + else if (nmsTag instanceof CompoundTag nmsCompoundTag) { + return toAPI(nmsCompoundTag); + } + else if (nmsTag instanceof EndTag) { + return EndBinaryTag.endBinaryTag(); + } + throw new IllegalStateException("Unrecognized NMS tag of type '" + nmsTag.getClass().getName() + '/' + nmsTag.getType().getName() + "': " + nmsTag); + } + + public static ListBinaryTag toAPI(ListTag nmsListTag) { + ListBinaryTag.Builder builder = ListBinaryTag.heterogeneousListBinaryTag(nmsListTag.size()); + for (Tag nmsValue : nmsListTag) { + builder.add(toAPI(nmsValue)); + } + return builder.build(); + } + + public static ListTag toNMS(ListBinaryTag listTag) { + List nmsTags = new ArrayList<>(listTag.size()); + for (BinaryTag value : listTag) { + nmsTags.add(toNMS(value)); + } + return new ListTag(nmsTags); + } + + public static CompoundBinaryTag toAPI(CompoundTag nmsCompoundTag) { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(nmsCompoundTag.size()); + for (Map.Entry nmsEntry : nmsCompoundTag.entrySet()) { + builder.put(nmsEntry.getKey(), toAPI(nmsEntry.getValue())); + } + return builder.build(); + } + + public static CompoundTag toNMS(CompoundBinaryTag compoundTag) { + Map nmsTags = new HashMap<>(compoundTag.size()); + for (Map.Entry entry : compoundTag) { + nmsTags.put(entry.getKey(), toNMS(entry.getValue())); + } + try { + return (CompoundTag) COMPOUND_TAG_MAP_CONSTRUCTOR.invokeExact(nmsTags); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java new file mode 100644 index 0000000000..de8b320707 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java @@ -0,0 +1,435 @@ +package com.denizenscript.denizen.nms.v1_21.helpers; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.interfaces.PacketHelper; +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v1_21.impl.SidebarImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizen.utilities.maps.MapImage; +import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; +import com.denizenscript.denizencore.objects.core.ColorTag; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.custom.BrandPayload; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.Relative; +import net.minecraft.world.entity.ai.attributes.AttributeInstance; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.monster.spider.CaveSpider; +import net.minecraft.world.entity.monster.Creeper; +import net.minecraft.world.entity.monster.EnderMan; +import net.minecraft.world.entity.monster.spider.Spider; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.scores.PlayerTeam; +import net.minecraft.world.scores.Team; +import org.bukkit.Bukkit; +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Sign; +import org.bukkit.block.sign.Side; +import org.bukkit.block.sign.SignSide; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +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.map.CraftMapCanvas; +import org.bukkit.craftbukkit.v1_21_R7.map.CraftMapView; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapPalette; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.*; + +public class PacketHelperImpl implements PacketHelper { + + public static final EntityDataAccessor PLAYER_DATA_ACCESSOR_ABSORPTION = ReflectionHelper.getFieldValue(net.minecraft.world.entity.player.Player.class, ReflectionMappingsInfo.Player_DATA_PLAYER_ABSORPTION_ID, null); + + public static final EntityDataAccessor ENTITY_DATA_ACCESSOR_FLAGS = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, ReflectionMappingsInfo.Entity_DATA_SHARED_FLAGS_ID, null); + + public static final MethodHandle ABILITIES_PACKET_FOV_SETTER = ReflectionHelper.getFinalSetter(ClientboundPlayerAbilitiesPacket.class, ReflectionMappingsInfo.ClientboundPlayerAbilitiesPacket_walkingSpeed); + + public static final Field ENTITY_TRACKER_ENTRY_GETTER = ReflectionHelper.getFields(ChunkMap.TrackedEntity.class).getFirstOfType(ServerEntity.class); + + public static final MethodHandle CANVAS_GET_BUFFER = ReflectionHelper.getMethodHandle(CraftMapCanvas.class, "getBuffer"); + public static final Field MAPVIEW_WORLDMAP = ReflectionHelper.getFields(CraftMapView.class).get("worldMap"); + + public static final EntityDataAccessor> ENTITY_DATA_ACCESSOR_CUSTOM_NAME = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, ReflectionMappingsInfo.Entity_DATA_CUSTOM_NAME, null); + public static final EntityDataAccessor ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, ReflectionMappingsInfo.Entity_DATA_CUSTOM_NAME_VISIBLE, null); + + @Override + public void setFakeAbsorption(Player player, float value) { + send(player, new ClientboundSetEntityDataPacket(player.getEntityId(), List.of(createEntityData(PLAYER_DATA_ACCESSOR_ABSORPTION, value)))); + } + + @Override + public void setSlot(Player player, int slot, ItemStack itemStack, boolean playerOnly) { + AbstractContainerMenu menu = ((CraftPlayer) player).getHandle().containerMenu; + int windowId = playerOnly ? 0 : menu.containerId; + send(player, new ClientboundContainerSetSlotPacket(windowId, menu.incrementStateId(), slot, CraftItemStack.asNMSCopy(itemStack))); + } + + @Override + public void setFieldOfView(Player player, float fov) { + ClientboundPlayerAbilitiesPacket packet = new ClientboundPlayerAbilitiesPacket(((CraftPlayer) player).getHandle().getAbilities()); + if (!Float.isNaN(fov)) { + try { + ABILITIES_PACKET_FOV_SETTER.invoke(packet, fov); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + send(player, packet); + } + + @Override + public void respawn(Player player) { + ((CraftPlayer) player).getHandle().connection.handleClientCommand(new ServerboundClientCommandPacket(ServerboundClientCommandPacket.Action.PERFORM_RESPAWN)); + } + + @Override + public void setVision(Player player, EntityType entityType) { + final net.minecraft.world.entity.LivingEntity entity; + if (entityType == EntityType.CREEPER) { + entity = new Creeper(net.minecraft.world.entity.EntityType.CREEPER, ((CraftWorld) player.getWorld()).getHandle()); + } + else if (entityType == EntityType.SPIDER) { + entity = new Spider(net.minecraft.world.entity.EntityType.SPIDER, ((CraftWorld) player.getWorld()).getHandle()); + } + else if (entityType == EntityType.CAVE_SPIDER) { + entity = new CaveSpider(net.minecraft.world.entity.EntityType.CAVE_SPIDER, ((CraftWorld) player.getWorld()).getHandle()); + } + else if (entityType == EntityType.ENDERMAN) { + entity = new EnderMan(net.minecraft.world.entity.EntityType.ENDERMAN, ((CraftWorld) player.getWorld()).getHandle()); + } + else { + return; + } + + // Spectating an entity then immediately respawning the player prevents a client shader update, + // allowing the player to retain whatever vision the mob they spectated had. + send(player, new ClientboundAddEntityPacket(entity, 0, BlockPos.ZERO)); + send(player, new ClientboundSetCameraPacket(entity)); + NMSHandler.playerHelper.refreshPlayer(player); + send(player, new ClientboundRemoveEntitiesPacket(entity.getId())); + } + + @Override + public void showBlockAction(Player player, Location location, int action, int state) { + BlockPos position = CraftLocation.toBlockPosition(location); + Block block = ((CraftWorld) location.getWorld()).getHandle().getBlockState(position).getBlock(); + send(player, new ClientboundBlockEventPacket(position, block, action, state)); + } + + @Override + public void showTabListHeaderFooter(Player player, String header, String footer) { + Component cHeader = Handler.componentToNMS(FormattedTextHelper.parse(header, ChatColor.WHITE)); + Component cFooter = Handler.componentToNMS(FormattedTextHelper.parse(footer, ChatColor.WHITE)); + send(player, new ClientboundTabListPacket(cHeader, cFooter)); + } + + @Override + public void showTitle(Player player, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { + send(player, new ClientboundBundlePacket(List.of( + new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks), + new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE))), + new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE))) + ))); + } + + @Override + public void showMobHealth(Player player, LivingEntity mob, double health, double maxHealth) { + AttributeInstance attr = new AttributeInstance(Attributes.MAX_HEALTH, (a) -> {}); + attr.setBaseValue(maxHealth); + send(player, new ClientboundUpdateAttributesPacket(mob.getEntityId(), List.of(attr))); + send(player, new ClientboundSetEntityDataPacket(mob.getEntityId(), List.of(createEntityData(net.minecraft.world.entity.LivingEntity.DATA_HEALTH_ID, (float) health)))); + } + + @Override + public void showSignEditor(Player player, Location location) { // TODO: MC 1.18: once 1.18 is removed, remove 'location' arg + NetworkInterceptHelper.enable(); + Sign sign = null; + BlockPos toOpen = null; + // It actually allows 8 blocks of distance, but we limit to 7 because the client doesn't properly round down + for (int i = 0; i < 8; i++) { + Location toCheck = player.getLocation(); + toCheck.setY(toCheck.getY() - i); + if (toCheck.getBlock().getState() instanceof Sign foundSign) { + sign = foundSign; + } + else { + sign = null; + toOpen = CraftLocation.toBlockPosition(toCheck); + break; + } + } + if (sign != null) { + toOpen = CraftLocation.toBlockPosition(sign.getLocation()); + SignSide front = sign.getSide(Side.FRONT); + for (int line = 0; line < 4; line++) { + front.setLine(line, ""); + } + player.sendBlockUpdate(sign.getLocation(), sign); + } + else { + player.sendBlockChange(new LocationTag(player.getWorld(), toOpen.getX(), toOpen.getY(), toOpen.getZ()), Material.OAK_WALL_SIGN.createBlockData()); + } + DenizenNetworkManagerImpl.getNetworkManager(player).packetListener.fakeSignExpected = toOpen; + send(player, new ClientboundOpenSignEditorPacket(toOpen, true)); + } + + @Override + public void forceSpectate(Player player, Entity entity) { + send(player, new ClientboundSetCameraPacket(((CraftEntity) entity).getHandle())); + } + + public static void forceRespawnPlayerEntity(Entity entity, Player viewer) { + ChunkMap tracker = ((ServerLevel) ((CraftEntity) entity).getHandle().level()).getChunkSource().chunkMap; + ChunkMap.TrackedEntity entityTracker = tracker.entityMap.get(entity.getEntityId()); + if (entityTracker != null) { + try { + ServerEntity entry = (ServerEntity) ENTITY_TRACKER_ENTRY_GETTER.get(entityTracker); + if (entry != null) { + entry.removePairing(((CraftPlayer) viewer).getHandle()); + entry.addPairing(((CraftPlayer) viewer).getHandle()); + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + } + + @Override + public void sendRename(Player player, Entity entity, String name, boolean listMode) { + try { + if (entity.getType() == EntityType.PLAYER) { + if (listMode) { + send(player, new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, ((CraftPlayer) player).getHandle())); + } + else { + // For player entities, force a respawn packet and let the dynamic intercept correct the details + forceRespawnPlayerEntity(entity, player); + } + return; + } + List> list = List.of( + createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE)))), + createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true) + ); + send(player, new ClientboundSetEntityDataPacket(entity.getEntityId(), list)); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public static HashMap> noCollideTeamMap = new HashMap<>(); + + @Override + public void generateNoCollideTeam(Player player, UUID noCollide) { + removeNoCollideTeam(player, noCollide); + PlayerTeam team = new PlayerTeam(SidebarImpl.dummyScoreboard, Utilities.generateRandomColors(8)); + team.getPlayers().add(noCollide.toString()); + team.setCollisionRule(Team.CollisionRule.NEVER); + HashMap map = noCollideTeamMap.computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()); + map.put(noCollide, team); + send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); + } + + @Override + public void removeNoCollideTeam(Player player, UUID noCollide) { + if (noCollide == null || !player.isOnline()) { + noCollideTeamMap.remove(player.getUniqueId()); + return; + } + HashMap map = noCollideTeamMap.get(player.getUniqueId()); + if (map == null) { + return; + } + PlayerTeam team = map.remove(noCollide); + if (team != null) { + send(player, ClientboundSetPlayerTeamPacket.createRemovePacket(team)); + } + if (map.isEmpty()) { + noCollideTeamMap.remove(player.getUniqueId()); + } + } + + @Override + public void sendEntityMetadataFlagsUpdate(Player player, Entity entity) { + byte flags = ((CraftEntity) entity).getHandle().getEntityData().get(ENTITY_DATA_ACCESSOR_FLAGS); + send(player, new ClientboundSetEntityDataPacket(entity.getEntityId(), List.of(createEntityData(ENTITY_DATA_ACCESSOR_FLAGS, flags)))); + } + + @Override + public void sendEntityEffect(Player player, Entity entity, EntityEffect effect) { + send(player, new ClientboundEntityEventPacket(((CraftEntity) entity).getHandle(), effect.getData())); + } + + @Override + public int getPacketStats(Player player, boolean sent) { + DenizenNetworkManagerImpl netMan = DenizenNetworkManagerImpl.getNetworkManager(player); + return sent ? netMan.packetsSent : netMan.packetsReceived; + } + + @Override + public void setMapData(MapCanvas canvas, byte[] bytes, int x, int y, MapImage image) { + if (x > 127 || y > 127) { + return; + } + int width = Math.min(image.width, 128 - x), + height = Math.min(image.height, 128 - y); + if (x + width <= 0 || y + height <= 0) { + return; + } + try { + boolean anyChanged = false; + byte[] buffer = (byte[]) CANVAS_GET_BUFFER.invoke(canvas); + for (int x2 = x < 0 ? -x : 0; x2 < width; ++x2) { + for (int y2 = y < 0 ? -y : 0; y2 < height; ++y2) { + byte p = bytes[y2 * image.width + x2]; + if (p != MapPalette.TRANSPARENT) { + int index = (y2 + y) * 128 + (x2 + x); + if (buffer[index] != p) { + buffer[index] = p; + anyChanged = true; + } + } + } + } + if (anyChanged) { + // Flag the whole image as dirty + MapItemSavedData map = (MapItemSavedData) MAPVIEW_WORLDMAP.get(canvas.getMapView()); + map.setColorsDirty(Math.max(x, 0), Math.max(y, 0)); + map.setColorsDirty(width + x - 1, height + y - 1); + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void setNetworkManagerFor(Player player) { + DenizenNetworkManagerImpl.setNetworkManager(player); + } + + @Override + public void enableNetworkManager() { + DenizenNetworkManagerImpl.enableNetworkManager(); + } + + @Override + public void showDebugTestMarker(Player player, Location location, ColorTag color, String name, int time) { + BlockPos nmsPos = CraftLocation.toBlockPosition(location); + LocationTag displayPos = !name.isEmpty() ? LocationTag.valueOf(name, CoreUtilities.noDebugContext) : null; + send(player, new ClientboundGameTestHighlightPosPacket(nmsPos, displayPos != null ? CraftLocation.toBlockPosition(displayPos) : nmsPos)); + } + + @Override + public void clearDebugTestMarker(Player player) { + } + + @Override + public void sendBrand(Player player, String brand) { + BrandPayload payload = new BrandPayload(brand); + send(player, new ClientboundCustomPayloadPacket(payload)); + } + + @Override + public void sendCollectItemEntity(Player player, Entity taker, Entity item, int amount) { + send(player, new ClientboundTakeItemEntityPacket(item.getEntityId(), taker.getEntityId(), amount)); + } + + public Relative toNmsRelativeMovement(TeleportCommand.Relative relative) { + // TODO: 1.21.3: There seem to be more relative movement types now + return switch (relative) { + case X -> Relative.X; + case Y -> Relative.Y; + case Z -> Relative.Z; + case YAW -> Relative.Y_ROT; + case PITCH -> Relative.X_ROT; + }; + } + + @Override + public void sendRelativePositionPacket(Player player, double x, double y, double z, float yaw, float pitch, List relativeAxis) { + Set relativeMovements; + if (relativeAxis == null) { + relativeMovements = Relative.ALL; + } + else { + relativeMovements = EnumSet.noneOf(Relative.class); + for (TeleportCommand.Relative relative : relativeAxis) { + relativeMovements.add(toNmsRelativeMovement(relative)); + } + } + ClientboundPlayerPositionPacket packet = new ClientboundPlayerPositionPacket(0, new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yaw, pitch), relativeMovements); + sendAsyncSafe(player, packet); + } + + @Override + public void sendRelativeLookPacket(Player player, float yaw, float pitch) { + sendRelativePositionPacket(player, 0, 0, 0, yaw, pitch, null); + } + + @Override + public void sendEntityDataPacket(List players, Entity entity, List data) { + ClientboundSetEntityDataPacket setEntityDataPacket = new ClientboundSetEntityDataPacket(entity.getEntityId(), (List>) (Object) data); + Iterator playerIterator = players.iterator(); + while (playerIterator.hasNext()) { + Player player = playerIterator.next(); + if (!DenizenNetworkManagerImpl.getConnection(player).isConnected()) { + playerIterator.remove(); + continue; + } + sendAsyncSafe(player, setEntityDataPacket); + } + } + + public static void send(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().connection.send(packet); + } + + public static void broadcast(Packet packet) { + ((CraftServer) Bukkit.getServer()).getHandle().broadcastAll(packet); + } + + public static void sendAsyncSafe(Player player, Packet packet) { + DenizenNetworkManagerImpl.getConnection(player).channel.writeAndFlush(packet); + } + + public static SynchedEntityData.DataValue createEntityData(EntityDataAccessor accessor, T value) { + return new SynchedEntityData.DataValue<>(accessor.id(), accessor.serializer(), value); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java new file mode 100644 index 0000000000..6f73e27c02 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java @@ -0,0 +1,509 @@ +package com.denizenscript.denizen.nms.v1_21.helpers; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.abstracts.ImprovedOfflinePlayer; +import com.denizenscript.denizen.nms.enums.CustomEntityType; +import com.denizenscript.denizen.nms.interfaces.PlayerHelper; +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v1_21.impl.ImprovedOfflinePlayerImpl; +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.EntityItemProjectileImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.AbstractListenerPlayInImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.EntityTag; +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.entity.DenizenEntityType; +import com.denizenscript.denizen.utilities.entity.FakeEntity; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.mojang.authlib.GameProfile; +import it.unimi.dsi.fastutil.ints.IntList; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; +import net.minecraft.network.protocol.game.*; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +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.ServerGamePacketListenerImpl; +import net.minecraft.server.players.NameAndId; +import net.minecraft.server.players.PlayerList; +import net.minecraft.server.players.ServerOpList; +import net.minecraft.server.players.ServerOpListEntry; +import net.minecraft.stats.ServerRecipeBook; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.TagNetworkSerialization; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Avatar; +import net.minecraft.world.entity.Leashable; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.item.ItemCooldowns; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.LevelData; +import net.minecraft.world.phys.AABB; +import org.bukkit.*; +import org.bukkit.boss.BossBar; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.boss.CraftBossBar; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +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.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Predicate; + +public class PlayerHelperImpl extends PlayerHelper { + + public static final Field ATTACK_COOLDOWN_TICKS = ReflectionHelper.getFields(LivingEntity.class).get(ReflectionMappingsInfo.LivingEntity_attackStrengthTicker, int.class); + + public static final Field FLY_TICKS = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_aboveGroundTickCount, int.class); + public static final Field VEHICLE_FLY_TICKS = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_aboveGroundVehicleTickCount, int.class); + public static final Field PASSENGERS_PACKET_PASSENGERS = ReflectionHelper.getFields(ClientboundSetPassengersPacket.class).get(ReflectionMappingsInfo.ClientboundSetPassengersPacket_passengers, int[].class); + public static final MethodHandle PLAYER_RESPAWNCONFIG_SETTER = ReflectionHelper.getFinalSetter(ServerPlayer.class, ReflectionMappingsInfo.ServerPlayer_respawnConfig, ServerPlayer.RespawnConfig.class); + public static final MethodHandle SERVER_RECIPE_BOOK_ADD_HIGHLIGHT = ReflectionHelper.getMethodHandle(ServerRecipeBook.class, ReflectionMappingsInfo.ServerRecipeBook_addHighlight_method, ResourceKey.class); + + @Override + public void stopSound(Player player, NamespacedKey sound, SoundCategory category) { + ((CraftPlayer) player).getHandle().connection.send(new ClientboundStopSoundPacket(sound == null ? null : CraftNamespacedKey.toMinecraft(sound), null)); + } + + @Override + public void deTrackEntity(Player player, Entity entity) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ChunkMap.TrackedEntity tracker = nmsPlayer.level().getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); + if (tracker == null) { + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Failed to de-track entity " + entity.getEntityId() + " for " + player.getName() + ": tracker null"); + } + return; + } + sendEntityDestroy(player, entity); + tracker.removePlayer(nmsPlayer); + } + + public record TrackerData(PlayerTag player, ServerEntity tracker) {} + + @Override + public void addFakePassenger(List players, Entity vehicle, FakeEntity fakePassenger) { + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(((CraftEntity) vehicle).getHandle()); + int[] newPassengers = Arrays.copyOf(packet.getPassengers(), packet.getPassengers().length + 1); + newPassengers[packet.getPassengers().length] = fakePassenger.id; + try { + PASSENGERS_PACKET_PASSENGERS.set(packet, newPassengers); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + for (PlayerTag player : players) { + PacketHelperImpl.send(player.getPlayerEntity(), packet); + } + } + + public record FakeEntitySynchronizer(ServerGamePacketListenerImpl target) implements ServerEntity.Synchronizer { + + @Override + public void sendToTrackingPlayers(Packet packet) { + target.send(packet); + } + + @Override + public void sendToTrackingPlayersAndSelf(Packet packet) { + sendToTrackingPlayers(packet); + } + + @Override + public void sendToTrackingPlayersFiltered(Packet packet, Predicate predicate) { + if (predicate.test(target.getPlayer())) { + sendToTrackingPlayers(packet); + } + } + + @Override + public void sendToTrackingPlayersFilteredAndSelf(Packet packet, Predicate predicate) { + sendToTrackingPlayersFiltered(packet, predicate); + } + } + + @Override + public FakeEntity sendEntitySpawn(List players, DenizenEntityType entityType, LocationTag location, ArrayList mechanisms, int customId, UUID customUUID, boolean autoTrack) { + CraftWorld world = ((CraftWorld) location.getWorld()); + net.minecraft.world.entity.Entity nmsEntity; + if (entityType.isCustom()) { + if (entityType.customEntityType == CustomEntityType.ITEM_PROJECTILE) { + ItemStack itemStack = new ItemStack(Material.STONE); + for (Mechanism mechanism : mechanisms) { + if (mechanism.matches("item") && mechanism.requireObject(ItemTag.class)) { + itemStack = mechanism.valueAsType(ItemTag.class).getItemStack(); + } + } + nmsEntity = new EntityItemProjectileImpl(world.getHandle(), location, CraftItemStack.asNMSCopy(itemStack)); + } + else if (entityType.customEntityType == CustomEntityType.FAKE_PLAYER) { + String name = null; + String skin = null; + String blob = null; + for (Mechanism mechanism : new ArrayList<>(mechanisms)) { + if (mechanism.matches("name")) { + name = mechanism.getValue().asString(); + mechanisms.remove(mechanism); + } + else if (mechanism.matches("skin")) { + skin = mechanism.getValue().asString(); + mechanisms.remove(mechanism); + } + else if (mechanism.matches("skin_blob")) { + blob = mechanism.getValue().asString(); + mechanisms.remove(mechanism); + } + if (name != null && (skin != null || blob != null)) { + break; + } + } + nmsEntity = ((CraftFakePlayerImpl) NMSHandler.customEntityHelper.spawnFakePlayer(location, name, skin, blob, false)).getHandle(); + } + else { + throw new IllegalArgumentException("entityType"); + } + } + else { + org.bukkit.entity.Entity entity = world.createEntity(location, entityType.getBukkitEntityType().getEntityClass()); + nmsEntity = ((CraftEntity) entity).getHandle(); + } + if (customUUID != null) { + nmsEntity.setId(customId); + nmsEntity.setUUID(customUUID); + } + EntityTag entity = new EntityTag(nmsEntity.getBukkitEntity()); + entity.isFake = true; + entity.isFakeValid = true; + for (Mechanism mechanism : mechanisms) { + entity.safeAdjustDuplicate(mechanism); + } + nmsEntity.unsetRemoved(); + FakeEntity fake = new FakeEntity(players, location, entity.getBukkitEntity().getEntityId()); + fake.entity = new EntityTag(entity.getBukkitEntity()); + fake.entity.isFake = true; + fake.entity.isFakeValid = true; + List trackers = new ArrayList<>(); + fake.triggerSpawnPacket = (player) -> { + ServerPlayer nmsPlayer = ((CraftPlayer) player.getPlayerEntity()).getHandle(); + ServerGamePacketListenerImpl conn = nmsPlayer.connection; + final ServerEntity tracker = new ServerEntity(world.getHandle(), nmsEntity, 1, true, new FakeEntitySynchronizer(conn), Set.of(conn)); + tracker.addPairing(nmsPlayer); + final TrackerData data = new TrackerData(player, tracker); + trackers.add(data); + if (autoTrack) { + new BukkitRunnable() { + boolean wasOnline = true; + @Override + public void run() { + if (!fake.entity.isFakeValid) { + cancel(); + return; + } + if (player.isOnline()) { + if (!wasOnline) { + tracker.addPairing(((CraftPlayer) player.getPlayerEntity()).getHandle()); + wasOnline = true; + } + tracker.sendChanges(); + } + else if (wasOnline) { + wasOnline = false; + } + } + }.runTaskTimer(Denizen.getInstance(), 1, 1); + } + }; + for (PlayerTag player : players) { + fake.triggerSpawnPacket.accept(player); + } + fake.triggerUpdatePacket = () -> { + for (TrackerData tracker : trackers) { + if (tracker.player.isOnline()) { + tracker.tracker.sendChanges(); + } + } + }; + fake.triggerDestroyPacket = () -> { + for (TrackerData tracker : trackers) { + if (tracker.player.isOnline()) { + tracker.tracker.removePairing(((CraftPlayer) tracker.player.getPlayerEntity()).getHandle()); + } + } + trackers.clear(); + }; + return fake; + } + + @Override + public void sendEntityDestroy(Player player, Entity entity) { + ((CraftPlayer) player).getHandle().connection.send(new ClientboundRemoveEntitiesPacket(entity.getEntityId())); + } + + @Override + public int getFlyKickCooldown(Player player) { + ServerGamePacketListenerImpl conn = ((CraftPlayer) player).getHandle().connection; + if (conn instanceof AbstractListenerPlayInImpl denizenListener) { + conn = denizenListener.oldListener; + } + try { + return Math.max(80 - Math.max(FLY_TICKS.getInt(conn), VEHICLE_FLY_TICKS.getInt(conn)), 0); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + return 80; + } + + @Override + public void setFlyKickCooldown(Player player, int ticks) { + ticks = 80 - ticks; + ServerGamePacketListenerImpl conn = ((CraftPlayer) player).getHandle().connection; + if (conn instanceof AbstractListenerPlayInImpl denizenListener) { + conn = denizenListener.oldListener; + } + try { + FLY_TICKS.setInt(conn, ticks); + VEHICLE_FLY_TICKS.setInt(conn, ticks); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + } + + @Override + public int ticksPassedDuringCooldown(Player player) { + try { + return ATTACK_COOLDOWN_TICKS.getInt(((CraftPlayer) player).getHandle()); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + return -1; + } + + @Override + public float getMaxAttackCooldownTicks(Player player) { + return ((CraftPlayer) player).getHandle().getCurrentItemAttackStrengthDelay() + 3; + } + + @Override + public void setAttackCooldown(Player player, int ticks) { + try { + ATTACK_COOLDOWN_TICKS.setInt(((CraftPlayer) player).getHandle(), ticks); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + + } + + @Override + public boolean hasChunkLoaded(Player player, Chunk chunk) { + return ((CraftWorld) chunk.getWorld()).getHandle().getChunkSource().chunkMap + .getPlayers(new ChunkPos(chunk.getX(), chunk.getZ()), false).stream() + .anyMatch(entityPlayer -> entityPlayer.getUUID().equals(player.getUniqueId())); + } + + @Override + public void setTemporaryOp(Player player, boolean op) { + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + NameAndId nameAndId = new NameAndId(((CraftPlayer) player).getProfile()); + ServerOpList opList = server.getPlayerList().getOps(); + if (op) { + opList.add(new ServerOpListEntry(nameAndId, server.operatorUserPermissions(), opList.canBypassPlayerLimit(nameAndId))); + } + else { + opList.remove(nameAndId); + } + player.recalculatePermissions(); + } + + @Override + public void showEndCredits(Player player) { + ((CraftPlayer) player).getHandle().wonGame = true; + ((CraftPlayer) player).getHandle().connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1f)); + } + + @Override + public ImprovedOfflinePlayer getOfflineData(UUID uuid) { + return new ImprovedOfflinePlayerImpl(uuid); + } + + @Override + public void resendRecipeDetails(Player player) { + RecipeManager recipeManager = ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager(); + ClientboundUpdateRecipesPacket updatePacket = new ClientboundUpdateRecipesPacket(recipeManager.getSynchronizedItemProperties(), recipeManager.getSynchronizedStonecutterRecipes()); + ((CraftPlayer) player).getHandle().connection.send(updatePacket); + } + + @Override + public void resendDiscoveredRecipes(Player player) { + ServerRecipeBook recipeBook = ((CraftPlayer) player).getHandle().getRecipeBook(); + recipeBook.sendInitialRecipeBook(((CraftPlayer) player).getHandle()); + } + + @Override + public void quietlyAddRecipe(Player player, NamespacedKey key) { + ServerRecipeBook recipeBook = ((CraftPlayer) player).getHandle().getRecipeBook(); + RecipeHolder recipe = ItemHelperImpl.getNMSRecipe(key); + if (recipe == null) { + Debug.echoError("Cannot add recipe '" + key + "': it does not exist."); + return; + } + recipeBook.add(recipe.id()); + try { + SERVER_RECIPE_BOOK_ADD_HIGHLIGHT.invoke(recipeBook, recipe.id()); + } + catch (Throwable e) { + Debug.echoError(e); + } + } + + @Override + public byte getSkinLayers(Player player) { + return ((CraftPlayer) player).getHandle().getEntityData().get(Avatar.DATA_PLAYER_MODE_CUSTOMISATION); + } + + @Override + public void setSkinLayers(Player player, byte flags) { + ((CraftPlayer) player).getHandle().getEntityData().set(Avatar.DATA_PLAYER_MODE_CUSTOMISATION, flags); + } + + @Override + public void setBossBarTitle(BossBar bar, String title) { + ((CraftBossBar) bar).getHandle().name = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + ((CraftBossBar) bar).getHandle().broadcast(ClientboundBossEventPacket::createUpdateNamePacket); + } + + @Override + public boolean getSpawnForced(Player player) { + return ((CraftPlayer) player).getHandle().getRespawnConfig().forced(); + } + + @Override + public void setSpawnForced(Player player, boolean forced) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + try { + ServerPlayer.RespawnConfig config = nmsPlayer.getRespawnConfig(); + config = new ServerPlayer.RespawnConfig(config.respawnData(), forced); + PLAYER_RESPAWNCONFIG_SETTER.invoke(nmsPlayer, config); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public Location getBedSpawnLocation(Player player) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ServerPlayer.RespawnConfig nmsRespawnConfig = nmsPlayer.getRespawnConfig(); + if (nmsRespawnConfig == null) { + return null; + } + LevelData.RespawnData nmsRespawnData = nmsRespawnConfig.respawnData(); + Level nmsWorld = MinecraftServer.getServer().getLevel(nmsRespawnData.dimension()); + return nmsWorld != null ? new Location(nmsWorld.getWorld(), nmsRespawnData.pos().getX(), nmsRespawnData.pos().getY(), nmsRespawnData.pos().getZ(), nmsRespawnData.yaw(), nmsRespawnData.pitch()) : null; + } + + @Override + public long getLastActionTime(Player player) { + return ((CraftPlayer) player).getHandle().getLastActionTime(); + } + + @Override + public void sendPlayerInfoAddPacket(Player player, EnumSet editModes, String name, String display, UUID id, String texture, String signature, int latency, GameMode gameMode, boolean listed) { + EnumSet actions = EnumSet.noneOf(ClientboundPlayerInfoUpdatePacket.Action.class); + for (ProfileEditMode editMode : editModes) { + actions.add(switch (editMode) { + case ADD -> ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER; + case UPDATE_DISPLAY -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME; + case UPDATE_LATENCY -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY; + case UPDATE_GAME_MODE -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE; + case UPDATE_LISTED -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED; + }); + } + GameProfile profile = ProfileEditorImpl.createGameProfile(id, name, texture, signature); + // TODO: 1.21.3: Player list order and hat visibility support + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(display, ChatColor.WHITE)), true, player.getPlayerListOrder(), null); + PacketHelperImpl.send(player, ProfileEditorImpl.createInfoPacket(actions, List.of(entry))); + } + + @Override + public void sendPlayerInfoRemovePacket(Player player, UUID id) { + PacketHelperImpl.send(player, new ClientboundPlayerInfoRemovePacket(List.of(id))); + } + + @Override + public void sendClimbableMaterials(Player player, List materials) { + Map>, TagNetworkSerialization.NetworkPayload> packetInput = TagNetworkSerialization.serializeTagsToNetwork(((CraftServer) Bukkit.getServer()).getServer().registries()); + Map tags = ReflectionHelper.getFieldValue(TagNetworkSerialization.NetworkPayload.class, ReflectionMappingsInfo.TagNetworkSerializationNetworkPayload_tags, packetInput.get(BuiltInRegistries.BLOCK.key())); + IntList climbableBlocks = tags.get(BlockTags.CLIMBABLE.location()); + climbableBlocks.clear(); + for (Material material : materials) { + climbableBlocks.add(BuiltInRegistries.BLOCK.getId(CraftMagicNumbers.getBlock(material))); + } + PacketHelperImpl.send(player, new ClientboundUpdateTagsPacket(packetInput)); + } + + @Override + public void refreshPlayer(Player player) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ServerLevel nmsWorld = nmsPlayer.level(); + nmsPlayer.connection.send(new ClientboundRespawnPacket(nmsPlayer.createCommonSpawnInfo(nmsWorld), ClientboundRespawnPacket.KEEP_ALL_DATA)); + nmsPlayer.connection.internalTeleport(PositionMoveRotation.of(nmsPlayer), Set.of()); + if (nmsPlayer.isPassenger()) { + nmsPlayer.connection.send(new ClientboundSetPassengersPacket(nmsPlayer.getVehicle())); + } + if (nmsPlayer.isVehicle()) { + nmsPlayer.connection.send(new ClientboundSetPassengersPacket(nmsPlayer)); + } + AABB boundingBox = AABB.ofSize(nmsPlayer.getBoundingBox().getCenter(), 32, 32, 32); + for (net.minecraft.world.entity.Entity nmsEntity : nmsWorld.getEntitiesOfClass(net.minecraft.world.entity.Entity.class, boundingBox, nmsEntity -> nmsEntity instanceof Leashable nmsLeashable && nmsPlayer.equals(nmsLeashable.getLeashHolder()))) { + nmsPlayer.connection.send(new ClientboundSetEntityLinkPacket(nmsEntity, nmsPlayer)); + } + if (!nmsPlayer.getCooldowns().cooldowns.isEmpty()) { + int tickCount = nmsPlayer.getCooldowns().tickCount; + for (Map.Entry entry : nmsPlayer.getCooldowns().cooldowns.entrySet()) { + nmsPlayer.connection.send(new ClientboundCooldownPacket(entry.getKey(), entry.getValue().endTime - tickCount)); + } + } + nmsPlayer.connection.send(new ClientboundSetExperiencePacket(nmsPlayer.experienceProgress, nmsPlayer.totalExperience, nmsPlayer.experienceLevel)); + for (MobEffectInstance nmsEffect : nmsPlayer.getActiveEffects()) { + nmsPlayer.connection.send(new ClientboundUpdateMobEffectPacket(nmsPlayer.getId(), nmsEffect, false)); + } + nmsPlayer.onUpdateAbilities(); + PlayerList nmsPlayerList = MinecraftServer.getServer().getPlayerList(); + nmsPlayerList.sendPlayerPermissionLevel(nmsPlayer); + nmsPlayerList.sendLevelInfo(nmsPlayer, nmsWorld); + nmsPlayerList.sendAllPlayerInfo(nmsPlayer); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java new file mode 100644 index 0000000000..5f70b7347e --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java @@ -0,0 +1,111 @@ +package com.denizenscript.denizen.nms.v1_21.helpers; + +import com.denizenscript.denizen.nms.interfaces.WorldHelper; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v1_21.impl.BiomeNMSImpl; +import com.denizenscript.denizen.objects.BiomeTag; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.mojang.datafixers.util.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.players.SleepStatus; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; + +public class WorldHelperImpl implements WorldHelper { + + @Override + public boolean isStatic(World world) { + return ((CraftWorld) world).getHandle().isClientSide(); + } + + @Override + public void setStatic(World world, boolean isStatic) { + ServerLevel worldServer = ((CraftWorld) world).getHandle(); + ReflectionHelper.setFieldValue(net.minecraft.world.level.Level.class, ReflectionMappingsInfo.Level_isClientSide, worldServer, isStatic); + } + + @Override + public float getLocalDifficulty(Location location) { + BlockPos pos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + DifficultyInstance scaler = ((CraftWorld) location.getWorld()).getHandle().getCurrentDifficultyAt(pos); + return scaler.getEffectiveDifficulty(); + } + + @Override + public Location getNearestBiomeLocation(Location start, BiomeTag biome) { + Pair> result = ((CraftWorld) start.getWorld()).getHandle() + .findClosestBiome3d(b -> b.is(((BiomeNMSImpl) biome.getBiome()).biomeHolder.unwrapKey().get()), new BlockPos(start.getBlockX(), start.getBlockY(), start.getBlockZ()), 6400, 32, 64); + if (result == null || result.getFirst() == null) { + return null; + } + return new Location(start.getWorld(), result.getFirst().getX(), result.getFirst().getY(), result.getFirst().getZ()); + } + + @Override + public boolean areEnoughSleeping(World world, int percentage) { + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, ReflectionMappingsInfo.ServerLevel_sleepStatus, ((CraftWorld) world).getHandle()); + return status.areEnoughSleeping(percentage); + } + + @Override + public boolean areEnoughDeepSleeping(World world, int percentage) { + ServerLevel level = ((CraftWorld) world).getHandle(); + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, ReflectionMappingsInfo.ServerLevel_sleepStatus, level); + return status.areEnoughDeepSleeping(percentage, level.players()); + } + + @Override + public int getSkyDarken(World world) { + return ((CraftWorld) world).getHandle().getSkyDarken(); + } + + @Override + public boolean isDay(World world) { + return ((CraftWorld) world).getHandle().isBrightOutside(); + } + + @Override + public boolean isNight(World world) { + return ((CraftWorld) world).getHandle().isDarkOutside(); + } + + @Override + public void setDayTime(World world, long time) { + ((CraftWorld) world).getHandle().setDayTime(time); + } + + @Override + public void setGameTime(World world, long time) { + ((PrimaryLevelData) ((CraftWorld) world).getHandle().levelData).setGameTime(time); + } + + // net.minecraft.server.level.ServerLevel#wakeUpAllPlayers() + @Override + public void wakeUpAllPlayers(World world) { + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, ReflectionMappingsInfo.ServerLevel_sleepStatus, nmsWorld); + status.removeAllSleepers(); + nmsWorld.getPlayers(LivingEntity::isSleeping).forEach((player) -> player.stopSleepInBed(false, false)); + } + + // net.minecraft.server.level.ServerLevel#resetWeatherCycle() + @Override + public void clearWeather(World world) { + PrimaryLevelData data = ((CraftWorld) world).getHandle().serverLevelData; + data.setRaining(false); + if (!data.isRaining()) { + data.setRainTime(0); + } + data.setThundering(false); + if (!data.isThundering()) { + data.setThunderTime(0); + } + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java new file mode 100644 index 0000000000..d360c4318a --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java @@ -0,0 +1,242 @@ +package com.denizenscript.denizen.nms.v1_21.impl; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.abstracts.BiomeNMS; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.RegistrationInfo; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.random.Weighted; +import net.minecraft.util.random.WeightedList; +import net.minecraft.world.attribute.EnvironmentAttribute; +import net.minecraft.world.attribute.EnvironmentAttributeMap; +import net.minecraft.world.attribute.EnvironmentAttributes; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSpecialEffects; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntityType; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; +import org.bukkit.entity.EntityType; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class BiomeNMSImpl extends BiomeNMS { + + public static final MethodHandle BIOME_CLIMATESETTINGS_CONSTRUCTOR = ReflectionHelper.getConstructor(Biome.ClimateSettings.class, boolean.class, float.class, Biome.TemperatureModifier.class, float.class); + public static final MethodHandle MAPPED_REGISTRY_REGISTRATION_INFOS = ReflectionHelper.getFields(MappedRegistry.class).getGetter(ReflectionMappingsInfo.MappedRegistry_registrationInfos); + public static final MethodHandle BIOME_ATTRIBUTES_SETTER = ReflectionHelper.getFields(Biome.class).getSetter(ReflectionMappingsInfo.Biome_attributes); + + public Holder.Reference biomeHolder; + public ServerLevel world; + + public BiomeNMSImpl(ServerLevel world, NamespacedKey key) { + super(world.getWorld(), key); + this.world = world; + this.biomeHolder = getBiomeRegistry().get(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(key))).orElse(null); + } + + private MappedRegistry getBiomeRegistry() { + return (MappedRegistry) world.registryAccess().lookupOrThrow(Registries.BIOME); + } + + @Override + public DownfallType getDownfallTypeAt(Location location) { + Biome.Precipitation precipitation = biomeHolder.value().getPrecipitationAt(CraftLocation.toBlockPosition(location), world.getSeaLevel()); + return switch (precipitation) { + case RAIN -> DownfallType.RAIN; + case SNOW -> DownfallType.SNOW; + case NONE -> DownfallType.NONE; + }; + } + + @Override + public float getHumidity() { + return biomeHolder.value().climateSettings.downfall(); + } + + @Override + public float getBaseTemperature() { + return biomeHolder.value().getBaseTemperature(); + } + + @Override + public float getTemperatureAt(Location location) { + return biomeHolder.value().getTemperature(CraftLocation.toBlockPosition(location), world.getSeaLevel()); + } + + @Override + public boolean hasDownfall() { + return biomeHolder.value().hasPrecipitation(); + } + + @Override + public List getAmbientEntities() { + return getSpawnableEntities(MobCategory.AMBIENT); + } + + @Override + public List getCreatureEntities() { + return getSpawnableEntities(MobCategory.CREATURE); + } + + @Override + public List getMonsterEntities() { + return getSpawnableEntities(MobCategory.MONSTER); + } + + @Override + public List getWaterEntities() { + return getSpawnableEntities(MobCategory.WATER_CREATURE); + } + + @Override + public int getFoliageColor() { + // Check if the biome already has a default color + if (biomeHolder.value().getFoliageColor() != 0) { + return biomeHolder.value().getFoliageColor(); + } + // Based on net.minecraft.world.level.biome.Biome#getFoliageColorFromTexture() + float temperature = clampColor(getBaseTemperature()); + float humidity = clampColor(getHumidity()); + // Based on net.minecraft.world.level.FoliageColor#get() + humidity *= temperature; + int humidityValue = (int)((1.0f - humidity) * 255.0f); + int temperatureValue = (int)((1.0f - temperature) * 255.0f); + int index = temperatureValue << 8 | humidityValue; + return index >= 65536 ? 4764952 : getColor(index / 256, index % 256).asRGB(); + } + + public void setClimate(boolean hasPrecipitation, float temperature, Biome.TemperatureModifier temperatureModifier, float downfall) { + try { + Object newClimate = BIOME_CLIMATESETTINGS_CONSTRUCTOR.invoke(hasPrecipitation, temperature, temperatureModifier, downfall); + ReflectionHelper.setFieldValue(Biome.class, ReflectionMappingsInfo.Biome_climateSettings, biomeHolder.value(), newClimate); + setNetworkedRegistrationInfo(); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void setHumidity(float humidity) { + setClimate(hasDownfall(), getBaseTemperature(), getTemperatureModifier(), humidity); + } + + @Override + public void setBaseTemperature(float baseTemperature) { + setClimate(hasDownfall(), baseTemperature, getTemperatureModifier(), getHumidity()); + } + + @Override + public void setHasDownfall(boolean hasDownfall) { + setClimate(hasDownfall, getBaseTemperature(), getTemperatureModifier(), getHumidity()); + } + + @Override + public void setFoliageColor(int color) { + BiomeSpecialEffects nmsCurrEffects = biomeHolder.value().getSpecialEffects(); + BiomeSpecialEffects nmsNewEffects = new BiomeSpecialEffects( + nmsCurrEffects.waterColor(), Optional.of(color), nmsCurrEffects.dryFoliageColorOverride(), nmsCurrEffects.grassColorOverride(), nmsCurrEffects.grassColorModifier() + ); + ReflectionHelper.setFieldValue(Biome.class, ReflectionMappingsInfo.Biome_specialEffects, biomeHolder.value(), nmsNewEffects); + setNetworkedRegistrationInfo(); + } + + @Override + public int getFogColor() { + return getEnvironmentAttribute(EnvironmentAttributes.FOG_COLOR); + } + + @Override + public void setFogColor(int color) { + setEnvironmentAttribute(EnvironmentAttributes.FOG_COLOR, color); + } + + @Override + public int getWaterFogColor() { + return getEnvironmentAttribute(EnvironmentAttributes.WATER_FOG_COLOR); + } + + @Override + public void setWaterFogColor(int color) { + setEnvironmentAttribute(EnvironmentAttributes.WATER_FOG_COLOR, color); + } + + public T getEnvironmentAttribute(EnvironmentAttribute attribute) { + return biomeHolder.value().getAttributes().applyModifier(attribute, attribute.defaultValue()); + } + + public void setEnvironmentAttribute(EnvironmentAttribute attribute, T value) { + Biome nmsBiome = biomeHolder.value(); + EnvironmentAttributeMap newAttributeMap = EnvironmentAttributeMap.builder().putAll(nmsBiome.getAttributes()).set(attribute, value).build(); + try { + BIOME_ATTRIBUTES_SETTER.invokeExact(nmsBiome, newAttributeMap); + } + catch (Throwable e) { + Debug.echoError(e); + } + setNetworkedRegistrationInfo(); + } + + private List getSpawnableEntities(MobCategory creatureType) { + MobSpawnSettings mobs = biomeHolder.value().getMobSettings(); + WeightedList typeSettingList = mobs.getMobs(creatureType); + List entityTypes = new ArrayList<>(); + if (typeSettingList == null) { + return entityTypes; + } + for (Weighted meta : typeSettingList.unwrap()) { + entityTypes.add(CraftEntityType.minecraftToBukkit(meta.value().type())); + } + return entityTypes; + } + + @Override + public void setTo(Block block) { + if (((CraftWorld) block.getWorld()).getHandle() != this.world) { + NMSHandler.instance.getBiomeNMS(block.getWorld(), getKey()).setTo(block); + return; + } + // Based on CraftWorld source + BlockPos pos = new BlockPos(block.getX(), 0, block.getZ()); + if (world.hasChunkAt(pos)) { + LevelChunk chunk = world.getChunkAt(pos); + if (chunk != null) { + chunk.setBiome(block.getX() >> 2, block.getY() >> 2, block.getZ() >> 2, biomeHolder); + chunk.markUnsaved(); + } + } + } + + public Biome.TemperatureModifier getTemperatureModifier() { + return biomeHolder.value().climateSettings.temperatureModifier(); + } + + private void setNetworkedRegistrationInfo() { + try { + Map, RegistrationInfo> registrationInfos = (Map, RegistrationInfo>) MAPPED_REGISTRY_REGISTRATION_INFOS.invokeExact(getBiomeRegistry()); + registrationInfos.put(biomeHolder.key(), RegistrationInfo.BUILT_IN); + } + catch (Throwable e) { + Debug.echoError("Failed to set biome registration info, changes may not be synced correctly."); + Debug.echoError(e); + } + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java new file mode 100644 index 0000000000..7a33a97f69 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java @@ -0,0 +1,171 @@ +package com.denizenscript.denizen.nms.v1_21.impl; + +import com.denizenscript.denizen.nms.abstracts.ImprovedOfflinePlayer; +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v1_21.helpers.NBTAdapter; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.mojang.authlib.GameProfile; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.nbt.NbtIo; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ParticleStatus; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.ItemStackWithSlot; +import net.minecraft.world.entity.EntityEquipment; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.ai.attributes.AttributeInstance; +import net.minecraft.world.entity.ai.attributes.AttributeMap; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.ai.attributes.DefaultAttributes; +import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.level.storage.ValueOutput; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventoryPlayer; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.UUID; +import java.util.function.Consumer; + +public class ImprovedOfflinePlayerImpl extends ImprovedOfflinePlayer { + + public ImprovedOfflinePlayerImpl(UUID playeruuid) { + super(playeruuid); + } + + public static class OfflinePlayerInventory extends net.minecraft.world.entity.player.Inventory { + + public OfflinePlayerInventory(net.minecraft.world.entity.player.Player entityhuman) { + super(entityhuman, new EntityEquipment()); // TODO: 1.21.5: is the new Equipment right here? + } + + @Override + public InventoryHolder getOwner() { + return null; + } + } + + public static class OfflineCraftInventoryPlayer extends CraftInventoryPlayer { + + public OfflineCraftInventoryPlayer(net.minecraft.world.entity.player.Inventory inventory) { + super(inventory); + } + + @Override + public HumanEntity getHolder() { + return null; + } + } + + public static ServerPlayer fakeNmsPlayer; + + public static ServerPlayer getFakeNmsPlayer() { + if (fakeNmsPlayer == null) { + MinecraftServer server = ((CraftServer)Bukkit.getServer()).getServer(); + World world = Bukkit.getWorlds().getFirst(); + GameProfile fakeProfile = new GameProfile(new UUID(0, 0xABC123), "fakeplayer"); + ClientInformation fakeClientInfo = new ClientInformation("en", 0, ChatVisiblity.HIDDEN, false, 0, HumanoidArm.LEFT, true, false, ParticleStatus.MINIMAL); + fakeNmsPlayer = new ServerPlayer(server, ((CraftWorld) world).getHandle(), fakeProfile, fakeClientInfo); + } + return fakeNmsPlayer; + } + + public void editData(Consumer editor) { + this.compound = NBTAdapter.toAPI(Handler.useValueOutput(NBTAdapter.toNMS(this.compound), editor)); + markModified(); + } + + @Override + public org.bukkit.inventory.PlayerInventory getInventory() { + if (inventory == null) { + net.minecraft.world.entity.player.Inventory newInv = new OfflinePlayerInventory(getFakeNmsPlayer()); + Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> newInv.load(valueInput.listOrEmpty("Inventory", ItemStackWithSlot.CODEC))); + inventory = new OfflineCraftInventoryPlayer(newInv); + } + return inventory; + } + + @Override + public void setInventory(org.bukkit.inventory.PlayerInventory inventory) { + CraftInventoryPlayer inv = (CraftInventoryPlayer) inventory; + editData(valueOutput -> inv.getInventory().save(valueOutput.list("Inventory", ItemStackWithSlot.CODEC))); + } + + @Override + public Inventory getEnderChest() { + if (enderchest == null) { + PlayerEnderChestContainer nmsEnderChest = new PlayerEnderChestContainer(getFakeNmsPlayer()); + Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> nmsEnderChest.fromSlots(valueInput.listOrEmpty("EnderItems", ItemStackWithSlot.CODEC))); + enderchest = new CraftInventory(nmsEnderChest); + } + return enderchest; + } + + @Override + public void setEnderChest(Inventory inventory) { + editData(valueOutput -> ((PlayerEnderChestContainer) ((CraftInventory) inventory).getInventory()).storeAsSlots(valueOutput.list("EnderItems", ItemStackWithSlot.CODEC))); + } + + @Override + public double getMaxHealth() { + AttributeInstance maxHealth = getAttributes().getInstance(Attributes.MAX_HEALTH); + return maxHealth == null ? Attributes.MAX_HEALTH.value().getDefaultValue() : maxHealth.getValue(); + } + + @Override + public void setMaxHealth(double input) { + AttributeMap attributes = getAttributes(); + AttributeInstance maxHealth = attributes.getInstance(Attributes.MAX_HEALTH); + maxHealth.setBaseValue(input); + setAttributes(attributes); + } + + private AttributeMap getAttributes() { + AttributeMap amb = new AttributeMap(DefaultAttributes.getSupplier(net.minecraft.world.entity.EntityType.PLAYER)); + Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> valueInput.read("attributes", AttributeInstance.Packed.LIST_CODEC).ifPresent(amb::apply)); + return amb; + } + + public void setAttributes(AttributeMap attributes) { + editData(valueOutput -> valueOutput.store("attributes", AttributeInstance.Packed.LIST_CODEC, attributes.pack())); + } + + @Override + protected boolean loadPlayerData(UUID uuid) { + try { + this.player = uuid; + for (org.bukkit.World w : Bukkit.getWorlds()) { + this.file = new File(w.getWorldFolder(), "playerdata" + File.separator + this.player + ".dat"); + if (this.file.exists()) { + this.compound = NBTAdapter.toAPI(NbtIo.readCompressed(new FileInputStream(this.file), NbtAccounter.unlimitedHeap())); + return true; + } + } + } + catch (Exception e) { + Debug.echoError(e); + } + return false; + } + + @Override + public void saveInternal(CompoundBinaryTag compound) { + try { + NbtIo.writeCompressed(NBTAdapter.toNMS(compound), new FileOutputStream(this.file)); + } + catch (Exception e) { + Debug.echoError(e); + } + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java new file mode 100644 index 0000000000..196c039c05 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java @@ -0,0 +1,169 @@ +package com.denizenscript.denizen.nms.v1_21.impl; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.abstracts.ProfileEditor; +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.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.collect.ImmutableMultimap; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.datafixers.util.Either; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerRespawnEvent; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.*; + +public class ProfileEditorImpl extends ProfileEditor { + + @Override + protected void updatePlayer(final Player player, final boolean isSkinChanging) { + final ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + final UUID uuid = player.getUniqueId(); + ClientboundPlayerInfoRemovePacket removePlayerInfoPacket = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + ClientboundPlayerInfoUpdatePacket addPlayerInfoPacket = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(nmsPlayer)); + for (Player otherPlayer : Bukkit.getServer().getOnlinePlayers()) { + PacketHelperImpl.send(otherPlayer, removePlayerInfoPacket); + PacketHelperImpl.send(otherPlayer, addPlayerInfoPacket); + } + for (Player otherPlayer : NMSHandler.entityHelper.getPlayersThatSee(player)) { + if (!otherPlayer.getUniqueId().equals(uuid)) { + PacketHelperImpl.forceRespawnPlayerEntity(player, otherPlayer); + } + } + if (isSkinChanging) { + ((CraftServer) Bukkit.getServer()).getHandle().respawn(nmsPlayer, true, Entity.RemovalReason.CHANGED_DIMENSION, PlayerRespawnEvent.RespawnReason.PLUGIN); + } + else { + NMSHandler.playerHelper.refreshPlayer(player); + } + player.updateInventory(); + } + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundPlayerInfoUpdatePacket.class, ProfileEditorImpl::processPlayerInfoUpdatePacket); + } + + public static ClientboundPlayerInfoUpdatePacket processPlayerInfoUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundPlayerInfoUpdatePacket playerInfoUpdatePacket) { + if (ProfileEditor.mirrorUUIDs.isEmpty() && !RenameCommand.hasAnyDynamicRenames() && fakeProfiles.isEmpty()) { + return playerInfoUpdatePacket; + } + EnumSet actions = playerInfoUpdatePacket.actions(); + if (!actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER) && !actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) { + return playerInfoUpdatePacket; + } + boolean any = false; + for (ClientboundPlayerInfoUpdatePacket.Entry entry : playerInfoUpdatePacket.entries()) { + if (shouldChange(entry)) { + any = true; + break; + } + } + if (!any) { + return playerInfoUpdatePacket; + } + GameProfile ownProfile = networkManager.player.getGameProfile(); + List modifiedEntries = new ArrayList<>(playerInfoUpdatePacket.entries().size()); + for (ClientboundPlayerInfoUpdatePacket.Entry entry : playerInfoUpdatePacket.entries()) { + if (!shouldChange(entry)) { + modifiedEntries.add(entry); + continue; + } + String rename = RenameCommand.getCustomNameFor(entry.profileId(), networkManager.player.getBukkitEntity(), false); + GameProfile baseProfile = fakeProfiles.containsKey(entry.profileId()) ? getGameProfile(fakeProfiles.get(entry.profileId())) : entry.profile(); + PropertyMap modifiedProperties; + if (ProfileEditor.mirrorUUIDs.contains(entry.profileId())) { + modifiedProperties = ownProfile.properties(); + } + else { + // On Paper 1.19+, we use Paper's PlayerProfile API instead of this system + modifiedProperties = Denizen.supportsPaper ? entry.profile().properties() : baseProfile.properties(); + } + GameProfile modifiedProfile = new GameProfile(baseProfile.id(), rename != null ? (rename.length() > 16 ? rename.substring(0, 16) : rename) : baseProfile.name(), modifiedProperties); + String listRename = RenameCommand.getCustomNameFor(entry.profileId(), networkManager.player.getBukkitEntity(), true); + Component displayName = listRename != null ? Handler.componentToNMS(FormattedTextHelper.parse(listRename, ChatColor.WHITE)) : entry.displayName(); + ClientboundPlayerInfoUpdatePacket.Entry modifiedEntry = new ClientboundPlayerInfoUpdatePacket.Entry(entry.profileId(), modifiedProfile, entry.listed(), entry.latency(), entry.gameMode(), displayName, entry.showHat(), entry.listOrder(), entry.chatSession()); + modifiedEntries.add(modifiedEntry); + } + return createInfoPacket(actions, modifiedEntries); + } + + public static boolean shouldChange(ClientboundPlayerInfoUpdatePacket.Entry entry) { + return ProfileEditor.mirrorUUIDs.contains(entry.profileId()) || RenameCommand.customNames.containsKey(entry.profileId()) || fakeProfiles.containsKey(entry.profileId()); + } + + public static final Field ClientboundPlayerInfoUpdatePacket_entries = ReflectionHelper.getFields(ClientboundPlayerInfoUpdatePacket.class).getFirstOfType(List.class); + + public static ClientboundPlayerInfoUpdatePacket createInfoPacket(EnumSet actions, List entries) { + ClientboundPlayerInfoUpdatePacket playerInfoUpdatePacket = new ClientboundPlayerInfoUpdatePacket(actions, List.of()); + try { + ClientboundPlayerInfoUpdatePacket_entries.set(playerInfoUpdatePacket, entries); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return playerInfoUpdatePacket; + } + + public static GameProfile createGameProfile(UUID uuid, String name, String texture, String signature) { + return new GameProfile( + uuid != null ? uuid : NIL_UUID, name != null ? name : EMPTY_NAME, + texture != null ? new PropertyMap(ImmutableMultimap.of("textures", new Property("textures", texture, signature))) : PropertyMap.EMPTY + ); + } + + public static GameProfile getGameProfileNoProperties(PlayerProfile playerProfile) { + return createGameProfile(playerProfile.getUniqueId(), playerProfile.getName(), null, null); + } + + public static GameProfile getGameProfile(PlayerProfile playerProfile) { + return createGameProfile(playerProfile.getUniqueId(), playerProfile.getName(), playerProfile.getTexture(), playerProfile.getTextureSignature()); + } + + public static final MethodHandle RESOLVABLEPROFILE_UNPACK = ReflectionHelper.getMethodHandle(ResolvableProfile.class, ReflectionMappingsInfo.ResolvableProfile_unpack_method); + public static final MethodHandle RESOLVABLEPROFILE_PARTIAL_ID = ReflectionHelper + .getFields(ReflectionHelper.getClassOrThrow("net.minecraft.world.item.component.ResolvableProfile$Partial")) + .getGetter(ReflectionMappingsInfo.ResolvableProfilePartial_id, Optional.class); + + public static UUID getUUID(ResolvableProfile resolvableProfile) { + try { + Either unpacked = (Either) RESOLVABLEPROFILE_UNPACK.invokeExact(resolvableProfile); + return unpacked.map(GameProfile::id, + partial -> { + try { + Optional uuid = (Optional) RESOLVABLEPROFILE_PARTIAL_ID.invoke(partial); + return uuid.orElse(null); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + } + ); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/SidebarImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/SidebarImpl.java new file mode 100644 index 0000000000..e765aa1487 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/SidebarImpl.java @@ -0,0 +1,103 @@ +package com.denizenscript.denizen.nms.v1_21.impl; + +import com.denizenscript.denizen.nms.abstracts.Sidebar; +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v1_21.helpers.PacketHelperImpl; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.numbers.StyledFormat; +import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; +import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket; +import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket; +import net.minecraft.network.protocol.game.ClientboundSetScorePacket; +import net.minecraft.world.scores.DisplaySlot; +import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.PlayerTeam; +import net.minecraft.world.scores.Scoreboard; +import net.minecraft.world.scores.criteria.ObjectiveCriteria; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class SidebarImpl extends Sidebar { + + // TODO: 1.20.3: the scoreboard system saw significant changes, there is likely a better way to do this now + + public static Scoreboard dummyScoreboard = new Scoreboard(); + public static ObjectiveCriteria dummyCriteria; + + static { + try { + Constructor constructor = ObjectiveCriteria.class.getDeclaredConstructor(String.class); + constructor.setAccessible(true); + dummyCriteria = constructor.newInstance("dummy"); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public Objective obj1; + public Objective obj2; + + public SidebarImpl(Player player) { + super(player); + Component chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + this.obj1 = new Objective(dummyScoreboard, "dummy_1", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER, false, StyledFormat.SIDEBAR_DEFAULT); + this.obj2 = new Objective(dummyScoreboard, "dummy_2", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER, false, StyledFormat.SIDEBAR_DEFAULT); + } + + @Override + protected void setDisplayName(String title) { + if (this.obj1 != null) { + Component chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + this.obj1.setDisplayName(chatComponentTitle); + this.obj2.setDisplayName(chatComponentTitle); + } + } + + public List generatedTeams = new ArrayList<>(); + + @Override + public void sendUpdate() { + List oldTeams = generatedTeams; + generatedTeams = new ArrayList<>(); + PacketHelperImpl.send(player, new ClientboundSetObjectivePacket(this.obj1, 0)); + String[] ids = getIds(); + for (int i = 0; i < this.lines.length; i++) { + String line = this.lines[i]; + if (line == null) { + break; + } + String lineId = ids[i]; + PlayerTeam team = new PlayerTeam(dummyScoreboard, lineId); + team.getPlayers().add(lineId); + team.setPlayerPrefix(Handler.componentToNMS(FormattedTextHelper.parse(line, ChatColor.WHITE))); + generatedTeams.add(team); + PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); + PacketHelperImpl.send(player, new ClientboundSetScorePacket(lineId, obj1.getName(), this.scores[i], Optional.empty(), Optional.of(StyledFormat.SIDEBAR_DEFAULT))); + } + PacketHelperImpl.send(player, new ClientboundSetDisplayObjectivePacket(DisplaySlot.SIDEBAR, this.obj1)); + PacketHelperImpl.send(player, new ClientboundSetObjectivePacket(this.obj2, 1)); + Objective temp = this.obj2; + this.obj2 = this.obj1; + this.obj1 = temp; + for (PlayerTeam team : oldTeams) { + PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createRemovePacket(team)); + } + } + + @Override + public void remove() { + for (PlayerTeam team : generatedTeams) { + PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createRemovePacket(team)); + } + generatedTeams.clear(); + PacketHelperImpl.send(player, new ClientboundSetObjectivePacket(this.obj2, 1)); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java new file mode 100644 index 0000000000..78c81da8e2 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java @@ -0,0 +1,264 @@ +package com.denizenscript.denizen.nms.v1_21.impl.blocks; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.abstracts.BlockLight; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.lighting.LayerLightEventListener; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R7.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlock; +import org.bukkit.util.Vector; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.List; + +public class BlockLightImpl extends BlockLight { + + public static final Class LIGHTENGINETHREADED_TASKTYPE = Arrays.stream(ThreadedLevelLightEngine.class.getDeclaredClasses()).filter(c -> c.isEnum()).findFirst().get(); // TaskType + public static final Object LIGHTENGINETHREADED_TASKTYPE_PRE; + + static { + Object preObj = null; + try { + preObj = ReflectionHelper.getFields(LIGHTENGINETHREADED_TASKTYPE).get(ReflectionMappingsInfo.ThreadedLevelLightEngineTaskType_PRE_UPDATE).get(null); + } + catch (Throwable ex) { + ex.printStackTrace(); + } + LIGHTENGINETHREADED_TASKTYPE_PRE = preObj; + } + + public static final MethodHandle LIGHTENGINETHREADED_QUEUERUNNABLE = ReflectionHelper.getMethodHandle(ThreadedLevelLightEngine.class, ReflectionMappingsInfo.ThreadedLevelLightEngine_addTask_method, + int.class, int.class, LIGHTENGINETHREADED_TASKTYPE, Runnable.class); + + public static void enqueueRunnable(LevelChunk chunk, Runnable runnable) { + LevelLightEngine lightEngine = chunk.getLevel().getChunkSource().getLightEngine(); + if (lightEngine instanceof ThreadedLevelLightEngine) { + ChunkPos coord = chunk.getPos(); + try { + LIGHTENGINETHREADED_QUEUERUNNABLE.invoke(lightEngine, coord.x, coord.z, LIGHTENGINETHREADED_TASKTYPE_PRE, runnable); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + else { + runnable.run(); + } + } + + private BlockLightImpl(Location location, long ticks) { + super(location, ticks); + } + + public static BlockLight createLight(Location location, int lightLevel, long ticks) { + location = location.getBlock().getLocation(); + BlockLight blockLight; + if (lightsByLocation.containsKey(location)) { + blockLight = lightsByLocation.get(location); + if (blockLight.removeTask != null) { + blockLight.removeTask.cancel(); + blockLight.removeTask = null; + } + if (blockLight.updateTask != null) { + blockLight.updateTask.cancel(); + blockLight.updateTask = null; + } + blockLight.removeLater(ticks); + } + else { + blockLight = new BlockLightImpl(location, ticks); + lightsByLocation.put(location, blockLight); + if (!lightsByChunk.containsKey(blockLight.chunkCoord)) { + lightsByChunk.put(blockLight.chunkCoord, new ArrayList<>()); + } + lightsByChunk.get(blockLight.chunkCoord).add(blockLight); + } + blockLight.intendedLevel = lightLevel; + blockLight.update(lightLevel, true); + return blockLight; + } + + public static void checkIfLightsBrokenByPacket(ClientboundBlockUpdatePacket packet, Level world) { + try { + BlockPos pos = packet.getPos(); + int chunkX = pos.getX() >> 4; + int chunkZ = pos.getZ() >> 4; + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> { + LevelChunk chunk = world.getChunk(chunkX, chunkZ); + boolean any = false; + for (Vector vec : RELATIVE_CHUNKS) { + ChunkAccess other = world.getChunk(chunkX + vec.getBlockX(), chunkZ + vec.getBlockZ(), ChunkStatus.FULL, false); + if (other instanceof LevelChunk) { + List lights = lightsByChunk.get(new ChunkCoordinate(new CraftChunk((LevelChunk) other))); + if (lights != null) { + any = true; + for (BlockLight light : lights) { + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> light.update(light.intendedLevel, false), 1); + } + } + } + } + if (any) { + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> sendNearbyChunkUpdates(chunk), 3); + } + }, 1); + } + catch (Exception ex) { + Debug.echoError(ex); + } + } + + public static void checkIfLightsBrokenByPacket(ClientboundLightUpdatePacket packet, Level world) { + if (doNotCheck) { + return; + } + try { + int cX = packet.getX(); + int cZ = packet.getZ(); + BitSet bitMask = packet.getLightData().getBlockYMask(); + List blockData = packet.getLightData().getBlockUpdates(); + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> { + ChunkAccess chk = world.getChunk(cX, cZ, ChunkStatus.FULL, false); + if (!(chk instanceof LevelChunk)) { + return; + } + List lights = lightsByChunk.get(new ChunkCoordinate(new CraftChunk((LevelChunk) chk))); + if (lights == null) { + return; + } + boolean any = false; + for (BlockLight light : lights) { + if (((BlockLightImpl) light).checkIfChangedBy(bitMask, blockData)) { + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> light.update(light.intendedLevel, false), 1); + any = true; + } + } + if (any) { + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> sendNearbyChunkUpdates((LevelChunk) chk), 3); + } + }, 1); + } + catch (Exception ex) { + Debug.echoError(ex); + } + } + + public static boolean doNotCheck = false; + + public boolean checkIfChangedBy(BitSet bitmask, List data) { + Location blockLoc = block.getLocation(); + int layer = (blockLoc.getBlockY() >> 4) + 1; + if (!bitmask.get(layer)) { + return false; + } + int found = 0; + for (int i = 0; i < 16; i++) { + if (bitmask.get(i)) { + if (i == layer) { + byte[] blocks = data.get(found); + DataLayer arr = new DataLayer(blocks); + int x = blockLoc.getBlockX() - (chunkCoord.x << 4); + int y = blockLoc.getBlockY() % 16; + int z = blockLoc.getBlockZ() - (chunkCoord.z << 4); + int level = arr.get(x, y, z); + return intendedLevel != level; + } + found++; + } + } + return false; + } + + public static void runResetFor(final LevelChunk chunk, final BlockPos pos) { + Runnable runnable = () -> { + LevelLightEngine lightEngine = chunk.getLevel().getChunkSource().getLightEngine(); + LayerLightEventListener engineBlock = lightEngine.getLayerListener(LightLayer.BLOCK); + engineBlock.checkBlock(pos); + }; + enqueueRunnable(chunk, runnable); + } + + public static void runSetFor(final LevelChunk chunk, final BlockPos pos, final int level) { + Runnable runnable = () -> { + LevelLightEngine lightEngine = chunk.getLevel().getChunkSource().getLightEngine(); + LayerLightEventListener engineBlock = lightEngine.getLayerListener(LightLayer.BLOCK); + // engineBlock.onBlockEmissionIncrease(pos, level); // TODO: 1.20: ? + }; + enqueueRunnable(chunk, runnable); + } + + @Override + public void reset(boolean updateChunk) { + runResetFor((LevelChunk) ((CraftChunk) getChunk()).getHandle(ChunkStatus.FULL), ((CraftBlock) block).getPosition()); + if (updateChunk) { + // This runnable cast is necessary despite what your IDE may claim + updateTask = Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), (Runnable) this::sendNearbyChunkUpdates, 1); + } + } + + @Override + public void update(int lightLevel, boolean updateChunk) { + runResetFor((LevelChunk) ((CraftChunk) getChunk()).getHandle(ChunkStatus.FULL), ((CraftBlock) block).getPosition()); + updateTask = Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), () -> { + updateTask = null; + runSetFor((LevelChunk) ((CraftChunk) chunk).getHandle(ChunkStatus.FULL), ((CraftBlock) block).getPosition(), lightLevel); + if (updateChunk) { + // This runnable cast is necessary despite what your IDE may claim + updateTask = Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), (Runnable) this::sendNearbyChunkUpdates, 1); + } + }, 1); + } + + public static final Vector[] RELATIVE_CHUNKS = new Vector[] { + new Vector(0, 0, 0), + new Vector(-1, 0, 0), new Vector(1, 0, 0), new Vector(0, 0, -1), new Vector(0, 0, 1), + new Vector(-1, 0, -1), new Vector(-1, 0, 1), new Vector(1, 0, -1), new Vector(1, 0, 1) + }; + + public void sendNearbyChunkUpdates() { + sendNearbyChunkUpdates((LevelChunk) ((CraftChunk) getChunk()).getHandle(ChunkStatus.FULL)); + } + + public static void sendNearbyChunkUpdates(LevelChunk chunk) { + ChunkPos pos = chunk.getPos(); + for (Vector vec : RELATIVE_CHUNKS) { + ChunkAccess other = chunk.getLevel().getChunk(pos.x + vec.getBlockX(), pos.z + vec.getBlockZ(), ChunkStatus.FULL, false); + if (other instanceof LevelChunk) { + sendSingleChunkUpdate((LevelChunk) other); + } + } + } + + public static void sendSingleChunkUpdate(LevelChunk chunk) { + // TODO: 1.20: ? + /* + doNotCheck = true; + LevelLightEngine lightEngine = chunk.getLevel().getChunkSource().getLightEngine(); + ChunkPos pos = chunk.getPos(); + //ClientboundLightUpdatePacket packet = new ClientboundLightUpdatePacket(pos, lightEngine, null, null, true); // TODO: 1.16: should 'trust edges' be true here? + ((ServerChunkCache) chunk.getLevel().getChunkSource()).chunkMap.getPlayers(pos, false).forEach((player) -> { + player.connection.send(packet); + }); + doNotCheck = false;*/ + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakeArrowImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakeArrowImpl.java new file mode 100644 index 0000000000..4b45bfded0 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakeArrowImpl.java @@ -0,0 +1,26 @@ +package com.denizenscript.denizen.nms.v1_21.impl.entities; + +import com.denizenscript.denizen.nms.interfaces.FakeArrow; +import net.minecraft.world.entity.projectile.arrow.AbstractArrow; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftAbstractArrow; + +public class CraftFakeArrowImpl extends CraftAbstractArrow implements FakeArrow { + + public CraftFakeArrowImpl(CraftServer craftServer, AbstractArrow entityArrow) { + super(craftServer, entityArrow); + } + + @Override + public void remove() { + if (getPassenger() != null) { + return; + } + super.remove(); + } + + @Override + public String getEntityTypeName() { + return "FAKE_ARROW"; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakePlayerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakePlayerImpl.java new file mode 100644 index 0000000000..92a5ac8942 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakePlayerImpl.java @@ -0,0 +1,66 @@ +package com.denizenscript.denizen.nms.v1_21.impl.entities; + +import com.denizenscript.denizen.nms.interfaces.FakePlayer; +import com.denizenscript.denizen.nms.NMSHandler; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; + +import java.util.List; +import java.util.Set; + +public class CraftFakePlayerImpl extends CraftPlayer implements FakePlayer { + + private final CraftServer server; + public String fullName; + + public CraftFakePlayerImpl(CraftServer server, EntityFakePlayerImpl entity) { + super(server, entity); + this.server = server; + setMetadata("NPC", new FixedMetadataValue(NMSHandler.getJavaPlugin(), true)); + } + + @Override + public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { + this.server.getEntityMetadata().setMetadata(this, metadataKey, newMetadataValue); + } + + @Override + public List getMetadata(String metadataKey) { + return this.server.getEntityMetadata().getMetadata(this, metadataKey); + } + + @Override + public boolean hasMetadata(String metadataKey) { + return this.server.getEntityMetadata().hasMetadata(this, metadataKey); + } + + @Override + public void removeMetadata(String metadataKey, Plugin owningPlugin) { + this.server.getEntityMetadata().removeMetadata(this, metadataKey, owningPlugin); + } + + @Override + public String getEntityTypeName() { + return "FAKE_PLAYER"; + } + + @Override + public String getFullName() { + return fullName; + } + + @Override + public Block getTargetBlock(Set transparent, int maxDistance) { + return null; + } + + @Override + public List getLastTwoTargetBlocks(Set transparent, int maxDistance) { + return null; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftItemProjectileImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftItemProjectileImpl.java new file mode 100644 index 0000000000..a2b8de7f84 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftItemProjectileImpl.java @@ -0,0 +1,117 @@ +package com.denizenscript.denizen.nms.v1_21.impl.entities; + +import com.denizenscript.denizen.nms.interfaces.ItemProjectile; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.ProjectileSource; + +import java.lang.invoke.MethodHandle; +import java.util.UUID; + +public class CraftItemProjectileImpl extends CraftEntity implements ItemProjectile { + + private boolean doesBounce; + + public CraftItemProjectileImpl(CraftServer server, EntityItemProjectileImpl entity) { + super(server, entity); + MethodHandle handle = ReflectionHelper.getFinalSetterForFirstOfType(CraftEntity.class, EntityType.class); + if (handle != null) { + try { + handle.invoke(this, EntityType.ITEM); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + } + + @Override + public EntityItemProjectileImpl getHandle() { + return (EntityItemProjectileImpl) super.getHandle(); + } + + @Override + public String getEntityTypeName() { + return getType().name(); + } + + @Override + public ItemStack getItemStack() { + return CraftItemStack.asBukkitCopy(getHandle().getItemStack()); + } + + @Override + public void setItemStack(ItemStack itemStack) { + getHandle().setItemStack(CraftItemStack.asNMSCopy(itemStack)); + } + + @Override + public int getPickupDelay() { + return 0; + } + + @Override + public void setPickupDelay(int i) { + // Do nothing + } + + @Override + public void setUnlimitedLifetime(boolean b) { + // Do nothing + } + + @Override + public boolean isUnlimitedLifetime() { + return false; + } + + @Override + public void setOwner(UUID uuid) { + // Do nothing + } + + @Override + public UUID getOwner() { + return null; + } + + @Override + public void setThrower(UUID uuid) { + // Do nothing + } + + @Override + public UUID getThrower() { + return null; + } + + @Override + public ProjectileSource getShooter() { + return getHandle().projectileSource; + } + + @Override + public void setShooter(ProjectileSource projectileSource) { + if (projectileSource instanceof CraftEntity) { + getHandle().setOwner(((CraftEntity) projectileSource).getHandle()); + } + else { + getHandle().projectileSource = projectileSource; + } + } + + @Override + public boolean doesBounce() { + return doesBounce; + } + + @Override + public void setBounce(boolean doesBounce) { + this.doesBounce = doesBounce; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakeArrowImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakeArrowImpl.java new file mode 100644 index 0000000000..bad4b878de --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakeArrowImpl.java @@ -0,0 +1,43 @@ +package com.denizenscript.denizen.nms.v1_21.impl.entities; + +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.world.entity.projectile.arrow.SpectralArrow; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.event.entity.CreatureSpawnEvent; + +public class EntityFakeArrowImpl extends SpectralArrow { + + public EntityFakeArrowImpl(CraftWorld craftWorld, Location location) { + super(net.minecraft.world.entity.EntityType.SPECTRAL_ARROW, craftWorld.getHandle()); + try { + Handler.ENTITY_BUKKITYENTITY.set(this, new CraftFakeArrowImpl((CraftServer) Bukkit.getServer(), this)); + } + catch (Exception ex) { + Debug.echoError(ex); + } + setPosRaw(location.getX(), location.getY(), location.getZ()); + setRot(location.getYaw(), location.getPitch()); + level().addFreshEntity(this, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + + @Override + public void tick() { + // Do nothing + } + + @Override + protected ItemStack getPickupItem() { + return new ItemStack(Items.ARROW); + } + + @Override + public CraftFakeArrowImpl getBukkitEntity() { + return (CraftFakeArrowImpl) super.getBukkitEntity(); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakePlayerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakePlayerImpl.java new file mode 100644 index 0000000000..9c64a6636b --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakePlayerImpl.java @@ -0,0 +1,43 @@ +package com.denizenscript.denizen.nms.v1_21.impl.entities; + +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v1_21.impl.network.fakes.FakeNetworkManagerImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.fakes.FakePlayerConnectionImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.mojang.authlib.GameProfile; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.world.entity.player.Player; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.event.entity.CreatureSpawnEvent; + +public class EntityFakePlayerImpl extends ServerPlayer { + + public EntityFakePlayerImpl(MinecraftServer minecraftserver, ServerLevel worldserver, GameProfile gameprofile, ClientInformation clientInfo, boolean doAdd) { + super(minecraftserver, worldserver, gameprofile, clientInfo); + try { + Handler.ENTITY_BUKKITYENTITY.set(this, new CraftFakePlayerImpl((CraftServer) Bukkit.getServer(), this)); + net.minecraft.network.Connection networkManager = new FakeNetworkManagerImpl(PacketFlow.CLIENTBOUND); + connection = new FakePlayerConnectionImpl(minecraftserver, networkManager, this, new CommonListenerCookie(gameprofile, 0, clientInfo, false)); + DenizenNetworkManagerImpl.Connection_packetListener.set(networkManager, connection); + } + catch (Exception ex) { + Debug.echoError(ex); + } + getEntityData().set(Player.DATA_PLAYER_MODE_CUSTOMISATION, (byte) 127); + if (doAdd) { + worldserver.addFreshEntity(this, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + } + + @Override + public CraftFakePlayerImpl getBukkitEntity() { + return (CraftFakePlayerImpl) super.getBukkitEntity(); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java new file mode 100644 index 0000000000..21373b58c0 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java @@ -0,0 +1,106 @@ +package com.denizenscript.denizen.nms.v1_21.impl.entities; + +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.base.Preconditions; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.projectile.ThrowableProjectile; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.BlockHitResult; +import org.bukkit.Location; + +import java.lang.invoke.MethodHandle; + +public class EntityItemProjectileImpl extends ThrowableProjectile { + + public static MethodHandle setBukkitEntityMethod = ReflectionHelper.getFinalSetter(Entity.class, "bukkitEntity"); + + public static final EntityDataAccessor ITEM; + + static { + EntityDataAccessor watcher = null; + try { + watcher = (EntityDataAccessor) ReflectionHelper.getFields(ItemEntity.class).get(ReflectionMappingsInfo.ItemEntity_DATA_ITEM).get(null); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + ITEM = watcher; + } + + public EntityItemProjectileImpl(Level world, Location location, ItemStack item) { + super((net.minecraft.world.entity.EntityType) net.minecraft.world.entity.EntityType.ITEM, world); + try { + setBukkitEntityMethod.invoke(this, new CraftItemProjectileImpl(((ServerLevel) world).getServer().server, this)); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + setPosRaw(location.getX(), location.getY(), location.getZ()); + setRot(location.getYaw(), location.getPitch()); + setItemStack(item); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(ITEM, ItemStack.EMPTY); + } + + public ItemStack getItemStack() { + return this.getEntityData().get(ITEM); + } + + public void setItemStack(ItemStack itemstack) { + Preconditions.checkArgument(!itemstack.isEmpty(), "Cannot drop air"); + this.getEntityData().set(ITEM, itemstack); + this.getEntityData().markDirty(ITEM); + } + + @Override + protected void onHitBlock(BlockHitResult movingobjectpositionblock) { + super.onHitBlock(movingobjectpositionblock); + remove(RemovalReason.KILLED); + } + + @Override + public void onSyncedDataUpdated(EntityDataAccessor datawatcherobject) { + super.onSyncedDataUpdated(datawatcherobject); + if (ITEM.equals(datawatcherobject)) { + this.getItemStack().setEntityRepresentation(this); + } + } + + @Override + public boolean save(ValueOutput nmsValueOutput) { + if (!this.getItemStack().isEmpty()) { + nmsValueOutput.store("Item", ItemStack.CODEC, this.getItemStack()); + } + super.save(nmsValueOutput); + return true; + } + + @Override + public void load(ValueInput nmsValueInput) { + ItemStack nmsItemStack = nmsValueInput.read("Item", ItemStack.CODEC).orElse(ItemStack.EMPTY); + if (nmsItemStack.isEmpty()) { + this.remove(RemovalReason.KILLED); + } + else { + this.setItemStack(nmsItemStack); + } + super.load(nmsValueInput); + } + + @Override + public CraftItemProjectileImpl getBukkitEntity() { + return (CraftItemProjectileImpl) super.getBukkitEntity(); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeChannelImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeChannelImpl.java new file mode 100644 index 0000000000..f3b1953ca3 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeChannelImpl.java @@ -0,0 +1,80 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.fakes; + +import io.netty.channel.*; + +import java.net.SocketAddress; + +public class FakeChannelImpl extends AbstractChannel { + + private final ChannelConfig config = new DefaultChannelConfig(this); + + protected FakeChannelImpl(Channel parent) { + super(parent); + } + + @Override + public ChannelConfig config() { + config.setAutoRead(true); + return config; + } + + @Override + protected AbstractUnsafe newUnsafe() { + return null; + } + + @Override + protected boolean isCompatible(EventLoop eventLoop) { + return false; + } + + @Override + protected SocketAddress localAddress0() { + return null; + } + + @Override + protected SocketAddress remoteAddress0() { + return null; + } + + @Override + protected void doBind(SocketAddress socketAddress) throws Exception { + + } + + @Override + protected void doDisconnect() throws Exception { + + } + + @Override + protected void doClose() throws Exception { + + } + + @Override + protected void doBeginRead() throws Exception { + + } + + @Override + protected void doWrite(ChannelOutboundBuffer channelOutboundBuffer) throws Exception { + + } + + @Override + public boolean isOpen() { + return false; + } + + @Override + public boolean isActive() { + return false; + } + + @Override + public ChannelMetadata metadata() { + return new ChannelMetadata(true); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeNetworkManagerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeNetworkManagerImpl.java new file mode 100644 index 0000000000..ca0c9e0f7f --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeNetworkManagerImpl.java @@ -0,0 +1,16 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.fakes; + +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.PacketFlow; + +import java.net.SocketAddress; + +public class FakeNetworkManagerImpl extends Connection { + + public FakeNetworkManagerImpl(PacketFlow enumprotocoldirection) { + super(enumprotocoldirection); + channel = new FakeChannelImpl(null); + address = new SocketAddress() { + }; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakePlayerConnectionImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakePlayerConnectionImpl.java new file mode 100644 index 0000000000..4c4d11ac3c --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakePlayerConnectionImpl.java @@ -0,0 +1,20 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.fakes; + +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; + +public class FakePlayerConnectionImpl extends ServerGamePacketListenerImpl { + + public FakePlayerConnectionImpl(MinecraftServer minecraftserver, Connection networkmanager, ServerPlayer entityplayer, CommonListenerCookie cookie) { + super(minecraftserver, networkmanager, entityplayer, cookie); + } + + @Override + public void send(Packet packet) { + // Do nothing + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java new file mode 100644 index 0000000000..d67b131ff5 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java @@ -0,0 +1,671 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; + +import com.denizenscript.denizen.events.player.PlayerSendPacketScriptEvent; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.mojang.authlib.GameProfile; +import io.netty.channel.ChannelFutureListener; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; +import net.minecraft.network.ConnectionProtocol; +import net.minecraft.network.DisconnectionDetails; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.PlayerChatMessage; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.*; +import net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.ping.ServerboundPingRequestPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerCommonPacketListenerImpl; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.Relative; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.event.player.PlayerTeleportEvent; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.net.SocketAddress; +import java.util.Set; + +public class AbstractListenerPlayInImpl extends ServerGamePacketListenerImpl { + + public static final Field ServerGamePacketListenerImpl_chunkSender = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_chunkSender); + + public static final MethodHandle SERVER_COMMON_PACKET_LISTENER_IMPL_CREATE_COOKIE = ReflectionHelper.getMethodHandle(ServerCommonPacketListenerImpl.class, ReflectionMappingsInfo.ServerCommonPacketListenerImpl_createCookie_method, ClientInformation.class); + + public static CommonListenerCookie createCookie(ServerPlayer nmsPlayer) { + try { + return (CommonListenerCookie) SERVER_COMMON_PACKET_LISTENER_IMPL_CREATE_COOKIE.invoke(nmsPlayer.connection, nmsPlayer.clientInformation()); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public final ServerGamePacketListenerImpl oldListener; + public final DenizenNetworkManagerImpl denizenNetworkManager; + + public AbstractListenerPlayInImpl(DenizenNetworkManagerImpl networkManager, ServerPlayer entityPlayer, ServerGamePacketListenerImpl oldListener) { + super(MinecraftServer.getServer(), networkManager, entityPlayer, createCookie(entityPlayer)); + this.oldListener = oldListener; + this.denizenNetworkManager = networkManager; + try { + ServerGamePacketListenerImpl_chunkSender.set(this, oldListener.chunkSender); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + } + + @Override + public void disconnect(Component ichatbasecomponent) { + oldListener.disconnect(ichatbasecomponent); + } + + @Override + public void disconnect(DisconnectionDetails disconnectiondetails) { + oldListener.disconnect(disconnectiondetails); + } + + @Override + public void kickPlayer(Component reason) { + oldListener.kickPlayer(reason); + } + + @Override + public void teleport(double d0, double d1, double d2, float f, float f1) { + oldListener.teleport(d0, d1, d2, f, f1); + } + + @Override + public boolean teleport(double d0, double d1, double d2, float f, float f1, PlayerTeleportEvent.TeleportCause cause) { + return oldListener.teleport(d0, d1, d2, f, f1, cause); + } + + @Override + public void teleport(PositionMoveRotation positionmoverotation, Set set) { + oldListener.teleport(positionmoverotation, set); + } + + @Override + public boolean teleport(PositionMoveRotation positionmoverotation, Set set, PlayerTeleportEvent.TeleportCause cause) { + return oldListener.teleport(positionmoverotation, set, cause); + } + + @Override + public void teleport(Location dest) { + oldListener.teleport(dest); + } + + @Override + public void internalTeleport(PositionMoveRotation positionmoverotation, Set set) { + oldListener.internalTeleport(positionmoverotation, set); + } + + @Override + public CraftPlayer getCraftPlayer() { + return oldListener.getCraftPlayer(); + } + + @Override + public void tick() { + oldListener.tick(); + } + + @Override + public void resetPosition() { + oldListener.resetPosition(); + } + + @Override + public boolean isAcceptingMessages() { + return oldListener.isAcceptingMessages(); + } + + @Override + public boolean shouldHandleMessage(Packet packet) { + return oldListener.shouldHandleMessage(packet); + } + + @Override + public void fillCrashReport(CrashReport var0) { + oldListener.fillCrashReport(var0); + } + + @Override + public void fillListenerSpecificCrashDetails(CrashReport var0, CrashReportCategory var1) { + oldListener.fillListenerSpecificCrashDetails(var0, var1); + } + + @Override + public GameProfile getOwner() { + return oldListener.getOwner(); + } + + @Override + public int latency() { + return oldListener.latency(); + } + + @Override + public void onDisconnect(DisconnectionDetails disconnectionDetails) { + oldListener.onDisconnect(disconnectionDetails); + } + + @Override + public void ackBlockChangesUpTo(int i) { + oldListener.ackBlockChangesUpTo(i); + } + + @Override + public void send(Packet packet) { + oldListener.send(packet); + } + + @Override + public void send(Packet packet, ChannelFutureListener channelfuturelistener) { + oldListener.send(packet, channelfuturelistener); + } + + public static Field AWAITING_POS_FIELD = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_awaitingPositionFromClient, Vec3.class); + public static Field AWAITING_TELEPORT_FIELD = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_awaitingTeleport, int.class); + + public void debugPacketOutput(Packet packet) { + try { + if (packet instanceof ServerboundMovePlayerPacket) { + ServerboundMovePlayerPacket movePacket = (ServerboundMovePlayerPacket) packet; + DenizenNetworkManagerImpl.doPacketOutput("Packet ServerboundMovePlayerPacket sent from " + player.getScoreboardName() + " with XYZ=" + + movePacket.x + ", " + movePacket.y + ", " + movePacket.z + ", yRot=" + movePacket.yRot + ", xRot=" + movePacket.xRot + + ", onGround=" + movePacket.isOnGround() + ", hasPos=" + movePacket.hasPos + ", hasRot=" + movePacket.hasRot); + } + else if (packet instanceof ServerboundAcceptTeleportationPacket) { + Vec3 awaitPos = (Vec3) AWAITING_POS_FIELD.get(oldListener); + int awaitTeleportId = AWAITING_TELEPORT_FIELD.getInt(oldListener); + ServerboundAcceptTeleportationPacket acceptPacket = (ServerboundAcceptTeleportationPacket) packet; + DenizenNetworkManagerImpl.doPacketOutput("Packet ServerboundAcceptTeleportationPacket sent from " + player.getScoreboardName() + + " with ID=" + acceptPacket.getId() + ", awaitingTeleport=" + awaitTeleportId + ", awaitPos=" + awaitPos); + } + else { + DenizenNetworkManagerImpl.doPacketOutput("Packet: " + packet.getClass().getCanonicalName() + " sent from " + player.getScoreboardName()); + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public boolean handlePacketIn(Packet packet) { + denizenNetworkManager.packetsReceived++; + if (NMSHandler.debugPackets) { + debugPacketOutput(packet); + } + if (PlayerSendPacketScriptEvent.instance.eventData.isEnabled) { + if (PlayerSendPacketScriptEvent.fireFor(player.getBukkitEntity(), packet)) { + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Denied packet-in " + packet.getClass().getCanonicalName() + " from " + player.getScoreboardName() + " due to event"); + } + return true; + } + } + return false; + } + + @Override + public void handleChatAck(ServerboundChatAckPacket serverboundchatackpacket) { + oldListener.handleChatAck(serverboundchatackpacket); + } + + @Override + public void handlePlayerInput(ServerboundPlayerInputPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlayerInput(packet); + } + + @Override + public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleMoveVehicle(packet); + } + + @Override + public void handleAcceptTeleportPacket(ServerboundAcceptTeleportationPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleAcceptTeleportPacket(packet); + } + + @Override + public void handleRecipeBookSeenRecipePacket(ServerboundRecipeBookSeenRecipePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleRecipeBookSeenRecipePacket(packet); + } + + @Override + public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleRecipeBookChangeSettingsPacket(packet); + } + + @Override + public void handleSeenAdvancements(ServerboundSeenAdvancementsPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSeenAdvancements(packet); + } + + @Override + public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleCustomCommandSuggestions(packet); + } + + @Override + public void handleSetCommandBlock(ServerboundSetCommandBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetCommandBlock(packet); + } + + @Override + public void handleSetCommandMinecart(ServerboundSetCommandMinecartPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetCommandMinecart(packet); + } + + @Override + public void handleAcceptPlayerLoad(ServerboundPlayerLoadedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleAcceptPlayerLoad(packet); + } + + @Override + public void handlePickItemFromBlock(ServerboundPickItemFromBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePickItemFromBlock(packet); + } + + @Override + public void handlePickItemFromEntity(ServerboundPickItemFromEntityPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePickItemFromEntity(packet); + } + + @Override + public void handleRenameItem(ServerboundRenameItemPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleRenameItem(packet); + } + + @Override + public void handleSetBeaconPacket(ServerboundSetBeaconPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetBeaconPacket(packet); + } + + @Override + public void handleSetStructureBlock(ServerboundSetStructureBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetStructureBlock(packet); + } + + @Override + public void handleSetTestBlock(ServerboundSetTestBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetTestBlock(packet); + } + + @Override + public void handleTestInstanceBlockAction(ServerboundTestInstanceBlockActionPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleTestInstanceBlockAction(packet); + } + + @Override + public void handleSetJigsawBlock(ServerboundSetJigsawBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetJigsawBlock(packet); + } + + @Override + public void handleJigsawGenerate(ServerboundJigsawGeneratePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleJigsawGenerate(packet); + } + + @Override + public void handleSelectTrade(ServerboundSelectTradePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSelectTrade(packet); + } + + @Override + public void handleEditBook(ServerboundEditBookPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleEditBook(packet); + } + + @Override + public void handleMovePlayer(ServerboundMovePlayerPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleMovePlayer(packet); + } + + @Override + public void handlePlayerAction(ServerboundPlayerActionPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlayerAction(packet); + } + + @Override + public void handleUseItemOn(ServerboundUseItemOnPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleUseItemOn(packet); + } + + @Override + public void handleUseItem(ServerboundUseItemPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleUseItem(packet); + } + + @Override + public void handleTeleportToEntityPacket(ServerboundTeleportToEntityPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleTeleportToEntityPacket(packet); + } + + @Override + public void handleResourcePackResponse(ServerboundResourcePackPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleResourcePackResponse(packet); + } + + @Override + public void suspendFlushing() { + oldListener.suspendFlushing(); + } + + @Override + public void resumeFlushing() { + oldListener.resumeFlushing(); + } + + @Override + public void handlePaddleBoat(ServerboundPaddleBoatPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePaddleBoat(packet); + } + + @Override + public void handlePong(ServerboundPongPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePong(packet); + } + + @Override + public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetCarriedItem(packet); + } + + @Override + public void handleChat(ServerboundChatPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChat(packet); + } + + @Override + public void handleChatCommand(ServerboundChatCommandPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChatCommand(packet); + } + + @Override + public void chat(String s, PlayerChatMessage original, boolean async) { + oldListener.chat(s, original, async); + } + + @Override + public ConnectionProtocol protocol() { + return oldListener == null ? ConnectionProtocol.PLAY : oldListener.protocol(); + } + + @Override + public void handleAnimate(ServerboundSwingPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleAnimate(packet); + } + + @Override + public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlayerCommand(packet); + } + + @Override + public void sendPlayerChatMessage(PlayerChatMessage playerchatmessage, ChatType.Bound chatmessagetype_a) { + oldListener.sendPlayerChatMessage(playerchatmessage, chatmessagetype_a); + } + + @Override + public void sendDisguisedChatMessage(Component ichatbasecomponent, ChatType.Bound chatmessagetype_a) { + oldListener.sendDisguisedChatMessage(ichatbasecomponent, chatmessagetype_a); + } + + @Override + public SocketAddress getRemoteAddress() { + return oldListener.getRemoteAddress(); + } + + @Override + public SocketAddress getRawAddress() { + return oldListener.getRawAddress(); + } + + @Override + public void switchToConfig() { + oldListener.switchToConfig(); + } + + @Override + public void handleInteract(ServerboundInteractPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleInteract(packet); + } + + @Override + public void handleClientCommand(ServerboundClientCommandPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleClientCommand(packet); + } + + @Override + public void handleContainerClose(ServerboundContainerClosePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleContainerClose(packet); + } + + @Override + public void handleContainerClick(ServerboundContainerClickPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleContainerClick(packet); + } + + @Override + public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlaceRecipe(packet); + } + + @Override + public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleContainerButtonClick(packet); + } + + @Override + public void handleSetCreativeModeSlot(ServerboundSetCreativeModeSlotPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetCreativeModeSlot(packet); + } + + @Override + public void handleSignUpdate(ServerboundSignUpdatePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSignUpdate(packet); + } + + @Override + public void handleKeepAlive(ServerboundKeepAlivePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleKeepAlive(packet); + } + + @Override + public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlayerAbilities(packet); + } + + @Override + public void handleClientInformation(ServerboundClientInformationPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleClientInformation(packet); + } + + @Override + public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleCustomPayload(packet); + } + + @Override + public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChangeDifficulty(packet); + } + + @Override + public void handleLockDifficulty(ServerboundLockDifficultyPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleLockDifficulty(packet); + } + + @Override + public void handleChatSessionUpdate(ServerboundChatSessionUpdatePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChatSessionUpdate(packet); + } + + @Override + public void handleConfigurationAcknowledged(ServerboundConfigurationAcknowledgedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleConfigurationAcknowledged(packet); + } + + @Override + public void handleChunkBatchReceived(ServerboundChunkBatchReceivedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChunkBatchReceived(packet); + } + + @Override + public void handleBlockEntityTagQuery(ServerboundBlockEntityTagQueryPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleBlockEntityTagQuery(packet); + } + + @Override + public void handleBundleItemSelectedPacket(ServerboundSelectBundleItemPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleBundleItemSelectedPacket(packet); + } + + @Override + public void handleClientTickEnd(ServerboundClientTickEndPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleClientTickEnd(packet); + } + + @Override + public boolean hasInfiniteMaterials() { + return oldListener.hasInfiniteMaterials(); + } + + @Override + public void handleContainerSlotStateChanged(ServerboundContainerSlotStateChangedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleContainerSlotStateChanged(packet); + } + + @Override + public void handleDebugSubscriptionRequest(ServerboundDebugSubscriptionRequestPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleDebugSubscriptionRequest(packet); + } + + @Override + public void handleEntityTagQuery(ServerboundEntityTagQueryPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleEntityTagQuery(packet); + } + + @Override + public void handlePingRequest(ServerboundPingRequestPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePingRequest(packet); + } + + @Override + public void handleSignedChatCommand(ServerboundChatCommandSignedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSignedChatCommand(packet); + } + + @Override + public void handleChangeGameMode(ServerboundChangeGameModePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChangeGameMode(packet); + } + + @Override + public void handleCustomClickAction(ServerboundCustomClickActionPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleCustomClickAction(packet); + } + + @Override + public void handleCookieResponse(ServerboundCookieResponsePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleCookieResponse(packet); + } + + @Override + public ServerPlayer getPlayer() { + return oldListener.getPlayer(); + } + + @Override + public PacketFlow flow() { + return oldListener == null ? PacketFlow.SERVERBOUND : oldListener.flow(); + } + + @Override + public void onPacketError(Packet var0, Exception var1) throws ReportedException { + oldListener.onPacketError(var0, var1); + } + + @Override + public DisconnectionDetails createDisconnectionInfo(Component var0, Throwable var1) { + return oldListener.createDisconnectionInfo(var0, var1); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java new file mode 100644 index 0000000000..d725381ce0 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -0,0 +1,580 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; + +import com.denizenscript.denizen.events.player.PlayerReceivesPacketScriptEvent; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v1_21.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet.*; +import com.denizenscript.denizen.utilities.Settings; +import com.denizenscript.denizen.utilities.packets.NetworkInterceptCodeGen; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import net.minecraft.network.*; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.login.ClientLoginPacketListener; +import net.minecraft.network.protocol.status.ClientStatusPacketListener; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerCommonPacketListenerImpl; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.util.debugchart.LocalSampleLogger; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import javax.crypto.Cipher; +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public class DenizenNetworkManagerImpl extends Connection { + + public static > T copyPacket(T original, StreamCodec packetCodec) { + try { + RegistryFriendlyByteBuf copier = new RegistryFriendlyByteBuf(Unpooled.buffer(), CraftRegistry.getMinecraftRegistry()); + packetCodec.encode(copier, original); + return packetCodec.decode(copier); + } + catch (Throwable ex) { + Debug.echoError(ex); + return null; + } + } + + @FunctionalInterface + public interface PacketHandler> { + Packet handlePacket(DenizenNetworkManagerImpl networkManager, T packet) throws Exception; + } + + public static final Map>, List>> packetHandlers = new HashMap<>(); + + public static > void registerPacketHandler(Class packetClass, PacketHandler handler) { + packetHandlers.computeIfAbsent(packetClass, k -> new ArrayList<>()).add(handler); + } + + public static > void registerPacketHandler(Class packetClass, BiConsumer handler) { + registerPacketHandler(packetClass, (networkManager, packet) -> { + handler.accept(networkManager, packet); + return packet; + }); + } + + public final Connection oldManager; + public final DenizenPacketListenerImpl packetListener; + public final ServerPlayer player; + public int packetsSent, packetsReceived; + + public DenizenNetworkManagerImpl(ServerPlayer entityPlayer, Connection oldManager) { + super(getProtocolDirection(oldManager)); + this.oldManager = oldManager; + this.channel = oldManager.channel; + this.player = entityPlayer; + packetListener = (DenizenPacketListenerImpl) NetworkInterceptCodeGen.generateAppropriateInterceptor(this, entityPlayer, DenizenPacketListenerImpl.class, AbstractListenerPlayInImpl.class, ServerGamePacketListenerImpl.class); + if (!(oldManager.getPacketListener() instanceof ServerConfigurationPacketListener)) { + setListener(packetListener); + } + } + + public void setListener(PacketListener listener) { + try { + Connection_packetListener.set(oldManager, listener); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + throw new RuntimeException("Failed to set packet listener due to reflection error", e); + } + } + + public static Connection getConnection(ServerPlayer player) { + try { + return (Connection) ServerGamePacketListener_ConnectionField.get(player.connection); + } + catch (Throwable ex) { + Debug.echoError(ex); + throw new RuntimeException("Failed to get connection from player due to reflection error", ex); + } + } + + public static Connection getConnection(Player player) { + return getConnection(((CraftPlayer) player).getHandle()); + } + + public static DenizenNetworkManagerImpl getNetworkManager(ServerPlayer player) { + return (DenizenNetworkManagerImpl) getConnection(player); + } + + public static DenizenNetworkManagerImpl getNetworkManager(Player player) { + return getNetworkManager(((CraftPlayer) player).getHandle()); + } + + public static void setNetworkManager(Player player) { + ServerPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + ServerGamePacketListenerImpl playerConnection = entityPlayer.connection; + setNetworkManager(playerConnection, new DenizenNetworkManagerImpl(entityPlayer, getConnection(entityPlayer))); + } + + public static void enableNetworkManager() { + for (World w : Bukkit.getWorlds()) { + for (ChunkMap.TrackedEntity tracker : ((CraftWorld) w).getHandle().getChunkSource().chunkMap.entityMap.values()) { + ArrayList connections = new ArrayList<>(tracker.seenBy); + tracker.seenBy.clear(); + for (ServerPlayerConnection connection : connections) { + tracker.seenBy.add(connection.getPlayer().connection); + } + } + } + } + + @Override + public int hashCode() { + return oldManager.hashCode(); + } + + @Override + public boolean equals(Object c2) { + return oldManager.equals(c2); + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + oldManager.channelRegistered(ctx); + } + + @Override + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { + oldManager.channelUnregistered(ctx); + } + + @Override + public void channelActive(ChannelHandlerContext channelhandlercontext) throws Exception { + oldManager.channelActive(channelhandlercontext); + } + + @Override + public void channelInactive(ChannelHandlerContext channelhandlercontext) { + oldManager.channelInactive(channelhandlercontext); + } + + @Override + public boolean isSharable() { + return oldManager.isSharable(); + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + oldManager.handlerAdded(ctx); + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + oldManager.handlerRemoved(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) { + oldManager.exceptionCaught(channelhandlercontext, throwable); + } + + @Override + public void setupInboundProtocol(ProtocolInfo protocolinfo, T t0) { + oldManager.setupInboundProtocol(protocolinfo, t0); + } + + @Override + public void setupOutboundProtocol(ProtocolInfo protocolinfo) { + oldManager.setupOutboundProtocol(protocolinfo); + } + + @Override + protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet packet) { + if (oldManager.channel.isOpen()) { + try { + packet.handle(this.packetListener); + } + catch (Exception e) { + // Do nothing + } + } + } + + @Override + public void setListenerForServerboundHandshake(PacketListener packetlistener) { + oldManager.setListenerForServerboundHandshake(packetlistener); + } + + @Override + public void initiateServerboundStatusConnection(String s, int i, ClientStatusPacketListener packetstatusoutlistener) { + oldManager.initiateServerboundStatusConnection(s, i, packetstatusoutlistener); + } + + @Override + public void initiateServerboundPlayConnection(String s, int i, ClientLoginPacketListener packetloginoutlistener) { + oldManager.initiateServerboundPlayConnection(s, i, packetloginoutlistener); + } + + @Override + public void initiateServerboundPlayConnection(String s, int i, ProtocolInfo protocolinfo, ProtocolInfo protocolinfo1, C c0, boolean flag) { + oldManager.initiateServerboundPlayConnection(s, i, protocolinfo, protocolinfo1, c0, flag); + } + + @Override + public void send(Packet packet) { + send(packet, null); + } + + public static void doPacketOutput(String text) { + if (!NMSHandler.debugPackets) { + return; + } + if (NMSHandler.debugPacketFilter == null || NMSHandler.debugPacketFilter.trim().isEmpty() + || CoreUtilities.toLowerCase(text).contains(NMSHandler.debugPacketFilter)) { + Debug.log(text); + } + } + + public void debugOutputPacket(Packet packet) { + if (packet instanceof ClientboundSetEntityDataPacket) { + StringBuilder output = new StringBuilder(128); + output.append("Packet: ClientboundSetEntityDataPacket sent to ").append(player.getScoreboardName()).append(" for entity ID: ").append(((ClientboundSetEntityDataPacket) packet).id()).append(": "); + List> list = ((ClientboundSetEntityDataPacket) packet).packedItems(); + if (list == null) { + output.append("None"); + } + else { + for (SynchedEntityData.DataValue data : list) { + output.append('[').append(data.id()).append(": ").append(data.value()).append("], "); + } + } + doPacketOutput(output.toString()); + } + else if (packet instanceof ClientboundSetEntityMotionPacket) { + ClientboundSetEntityMotionPacket velPacket = (ClientboundSetEntityMotionPacket) packet; + doPacketOutput("Packet: ClientboundSetEntityMotionPacket sent to " + player.getScoreboardName() + " for entity ID: " + velPacket.getId() + ": " + velPacket.getMovement()); + } + else if (packet instanceof ClientboundAddEntityPacket) { + ClientboundAddEntityPacket addEntityPacket = (ClientboundAddEntityPacket) packet; + doPacketOutput("Packet: ClientboundAddEntityPacket sent to " + player.getScoreboardName() + " for entity ID: " + addEntityPacket.getId() + ": " + "uuid: " + addEntityPacket.getUUID() + + ", type: " + addEntityPacket.getType() + ", at: " + addEntityPacket.getX() + "," + addEntityPacket.getY() + "," + addEntityPacket.getZ() + ", data: " + addEntityPacket.getData()); + } + else if (packet instanceof ClientboundMapItemDataPacket) { + ClientboundMapItemDataPacket mapPacket = (ClientboundMapItemDataPacket) packet; + doPacketOutput("Packet: ClientboundMapItemDataPacket sent to " + player.getScoreboardName() + " for map ID: " + mapPacket.mapId() + ", scale: " + mapPacket.scale() + ", locked: " + mapPacket.locked()); + } + else if (packet instanceof ClientboundRemoveEntitiesPacket) { + ClientboundRemoveEntitiesPacket removePacket = (ClientboundRemoveEntitiesPacket) packet; + doPacketOutput("Packet: ClientboundRemoveEntitiesPacket sent to " + player.getScoreboardName() + " for entities: " + removePacket.getEntityIds().stream().map(Object::toString).collect(Collectors.joining(", "))); + } + else if (packet instanceof ClientboundPlayerInfoUpdatePacket) { + ClientboundPlayerInfoUpdatePacket playerInfoPacket = (ClientboundPlayerInfoUpdatePacket) packet; + doPacketOutput("Packet: ClientboundPlayerInfoPacket sent to " + player.getScoreboardName() + " of types " + playerInfoPacket.actions() + " for player profiles: " + + playerInfoPacket.entries().stream().map(p -> "mode=" + p.gameMode() + "/latency=" + p.latency() + "/display=" + p.displayName() + "/name=" + p.profile().name() + "/id=" + p.profile().id() + "/" + + p.profile().properties().asMap().entrySet().stream().map(e -> e.getKey() + "=" + e.getValue().stream().map(v -> v.value() + ";" + v.signature()).collect(Collectors.joining(";;;"))).collect(Collectors.joining("/"))).collect(Collectors.joining(", "))); + } + else { + doPacketOutput("Packet: " + packet.getClass().getCanonicalName() + " sent to " + player.getScoreboardName()); + } + } + + @Override + public void send(Packet packet, ChannelFutureListener channelFutureListener) { + send(packet, channelFutureListener, true); + } + + @Override + public void send(Packet packet, @Nullable ChannelFutureListener channelFutureListener, boolean flush) { + if (!Bukkit.isPrimaryThread()) { + if (Settings.cache_warnOnAsyncPackets + && !(packet instanceof ClientboundSystemChatPacket) && !(packet instanceof ClientboundPlayerChatPacket) // Vanilla supports an async chat system, though it's normally disabled, some plugins use this as justification for sending messages async + && !(packet instanceof ClientboundCommandSuggestionsPacket)) { // Async tab complete is wholly unsupported in Spigot (and will cause an exception), however Paper explicitly adds async support (for unclear reasons), so let it through too + Debug.echoError("Warning: packet sent off main thread! This is completely unsupported behavior! Denizen network interceptor ignoring packet to avoid crash. Packet class: " + + packet.getClass().getCanonicalName() + " sent to " + player.getScoreboardName() + " identify the sender of the packet from the stack trace:"); + try { + throw new RuntimeException("Trace"); + } + catch (Exception ex) { + Debug.echoError(ex); + } + } + oldManager.send(packet, channelFutureListener, flush); + return; + } + if (NMSHandler.debugPackets) { + debugOutputPacket(packet); + } + packetsSent++; + if (packet instanceof ClientboundBundlePacket bundlePacket) { + List> processedPackets = new ArrayList<>(); + boolean anyChange = false; + for (Packet _subPacket : bundlePacket.subPackets()) { + // Bundle packets with non-game packets shouldn't ever be sent while the Denizen interceptor is active + Packet subPacket = (Packet) _subPacket; + Packet processed = processPacketHandlersFor(subPacket); + anyChange = anyChange || processed != subPacket; + if (processed != null) { + processedPackets.add(processed); + } + } + if (processedPackets.isEmpty()) { + return; + } + if (anyChange) { + packet = new ClientboundBundlePacket(processedPackets); + } + } + else { + Packet processed = processPacketHandlersFor((Packet) packet); + if (processed == null) { + return; + } + packet = processed; + } + oldManager.send(packet, channelFutureListener, flush); + } + + @Override + public void runOnceConnected(Consumer consumer) { + oldManager.runOnceConnected(consumer); + } + + @Override + public void flushChannel() { + oldManager.flushChannel(); + } + + public Packet processPacketHandlersFor(Packet packet) { + if (packet == null) { + return null; + } + List> packetHandlers = DenizenNetworkManagerImpl.packetHandlers.get(packet.getClass()); + if (packetHandlers != null) { + for (PacketHandler _packetHandler : packetHandlers) { + PacketHandler> packetHandler = (PacketHandler>) _packetHandler; + Packet processed; + try { + processed = packetHandler.handlePacket(this, packet); + } + catch (Exception ex) { + Debug.echoError("Packet handler for " + packet.getClass().getCanonicalName() + " threw an exception:"); + Debug.echoError(ex); + continue; + } + if (processed == null) { + if (NMSHandler.debugPackets) { + doPacketOutput("DENIED PACKET - " + packet.getClass().getCanonicalName() + " DENIED FROM SEND TO " + player.getScoreboardName()); + } + return null; + } + packet = processed; + } + } + if (PlayerReceivesPacketScriptEvent.instance.eventData.isEnabled & PlayerReceivesPacketScriptEvent.fireFor(player.getBukkitEntity(), packet)) { + if (NMSHandler.debugPackets) { + doPacketOutput("DENIED PACKET - " + packet.getClass().getCanonicalName() + " DENIED FROM SEND TO " + player.getScoreboardName() + " due to event"); + } + return null; + } + return packet; + } + + static { + ActionBarEventPacketHandlers.registerHandlers(); + AttachPacketHandlers.registerHandlers(); + BlockLightPacketHandlers.registerHandlers(); + DenizenPacketHandlerPacketHandlers.registerHandlers(); + EntityMetadataPacketHandlers.registerHandlers(); + DisguisePacketHandlers.registerHandlers(); + FakeBlocksPacketHandlers.registerHandlers(); + FakeEquipmentPacketHandlers.registerHandlers(); + FakePlayerPacketHandlers.registerHandlers(); + HiddenEntitiesPacketHandlers.registerHandlers(); + HideParticlesPacketHandlers.registerHandlers(); + PlayerHearsSoundEventPacketHandlers.registerHandlers(); + ProfileEditorImpl.registerHandlers(); + TablistUpdateEventPacketHandlers.registerHandlers(); + } + + @Override + public void tick() { + oldManager.tick(); + } + + @Override + public SocketAddress getRemoteAddress() { + return oldManager.getRemoteAddress(); + } + + @Override + public String getLoggableAddress(boolean flag) { + return oldManager.getLoggableAddress(flag); + } + + @Override + public void disconnect(Component ichatbasecomponent) { + if (!player.getBukkitEntity().isOnline()) { // Workaround Paper duplicate quit event issue + return; + } + oldManager.disconnect(ichatbasecomponent); + } + + @Override + public void disconnect(DisconnectionDetails disconnectiondetails) { + oldManager.disconnect(disconnectiondetails); + } + + @Override + public boolean isMemoryConnection() { + return oldManager != null && oldManager.isMemoryConnection(); + } + + @Override + public PacketFlow getReceiving() { + return oldManager.getReceiving(); + } + + @Override + public PacketFlow getSending() { + return oldManager.getSending(); + } + + @Override + public void configurePacketHandler(ChannelPipeline channelpipeline) { + oldManager.configurePacketHandler(channelpipeline); + } + + @Override + public void setEncryptionKey(Cipher cipher, Cipher cipher1) { + oldManager.setEncryptionKey(cipher, cipher1); + } + + @Override + public boolean isEncrypted() { + return oldManager.isEncrypted(); + } + + @Override + public boolean isConnected() { + return oldManager.isConnected(); + } + + @Override + public boolean isConnecting() { + return oldManager.isConnecting(); + } + + @Override + public PacketListener getPacketListener() { + return oldManager.getPacketListener(); + } + + @Override + public DisconnectionDetails getDisconnectionDetails() { + return oldManager.getDisconnectionDetails(); + } + + @Override + public void setReadOnly() { + oldManager.setReadOnly(); + } + + @Override + public void setupCompression(int i, boolean b) { + oldManager.setupCompression(i, b); + } + + @Override + public void handleDisconnection() { + oldManager.handleDisconnection(); + } + + @Override + public float getAverageReceivedPackets() { + return oldManager.getAverageReceivedPackets(); + } + + @Override + public float getAverageSentPackets() { + return oldManager.getAverageSentPackets(); + } + + @Override + public void setBandwidthLogger(LocalSampleLogger localsamplelogger) { + oldManager.setBandwidthLogger(localsamplelogger); + } + + ////////////////////////////////// + //// Reflection Methods/Fields + /////////// + + private static final Field protocolDirectionField = ReflectionHelper.getFields(Connection.class).get(ReflectionMappingsInfo.Connection_receiving, PacketFlow.class); + public static final Field Connection_packetListener = ReflectionHelper.getFields(Connection.class).get(ReflectionMappingsInfo.Connection_packetListener, PacketListener.class); + private static final Field ServerGamePacketListener_ConnectionField = ReflectionHelper.getFields(ServerCommonPacketListenerImpl.class).get(ReflectionMappingsInfo.ServerCommonPacketListenerImpl_connection); + private static final MethodHandle ServerGamePacketListener_ConnectionSetter = ReflectionHelper.getFinalSetter(ServerCommonPacketListenerImpl.class, ReflectionMappingsInfo.ServerCommonPacketListenerImpl_connection); + + private static PacketFlow getProtocolDirection(Connection networkManager) { + PacketFlow direction = null; + try { + direction = (PacketFlow) protocolDirectionField.get(networkManager); + } + catch (Exception e) { + Debug.echoError(e); + } + return direction; + } + + private static void setNetworkManager(ServerGamePacketListenerImpl playerConnection, Connection networkManager) { + try { + ServerGamePacketListener_ConnectionSetter.invoke(playerConnection, networkManager); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public boolean acceptInboundMessage(Object msg) throws Exception { + return oldManager.acceptInboundMessage(msg); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + oldManager.channelRead(ctx, msg); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + oldManager.channelReadComplete(ctx); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + oldManager.userEventTriggered(ctx, evt); + } + + @Override + public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { + oldManager.channelWritabilityChanged(ctx); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenPacketListenerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenPacketListenerImpl.java new file mode 100644 index 0000000000..ed03d1ee48 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenPacketListenerImpl.java @@ -0,0 +1,121 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; + +import com.denizenscript.denizen.events.player.PlayerChangesSignScriptEvent; +import com.denizenscript.denizen.events.player.PlayerSteersEntityScriptEvent; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v1_21.impl.network.packets.PacketInResourcePackStatusImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.packets.PacketInSteerVehicleImpl; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.objects.MaterialTag; +import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; +import com.denizenscript.denizen.utilities.packets.DenizenPacketHandler; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.ServerboundResourcePackPacket; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlock; +import org.bukkit.event.block.SignChangeEvent; + +public class DenizenPacketListenerImpl extends AbstractListenerPlayInImpl { + + public BlockPos fakeSignExpected; + + public DenizenPacketListenerImpl(DenizenNetworkManagerImpl networkManager, ServerPlayer entityPlayer) { + super(networkManager, entityPlayer, entityPlayer.connection); + } + + @Override + public void handlePlayerInput(final ServerboundPlayerInputPacket packet) { + if (!PlayerSteersEntityScriptEvent.instance.eventData.isEnabled) { + super.handlePlayerInput(packet); + return; + } + DenizenPacketHandler.instance.receivePacket(player.getBukkitEntity(), new PacketInSteerVehicleImpl(packet), () -> super.handlePlayerInput(packet)); + } + + @Override + public void handleResourcePackResponse(ServerboundResourcePackPacket packet) { + DenizenPacketHandler.instance.receivePacket(player.getBukkitEntity(), new PacketInResourcePackStatusImpl(packet)); + super.handleResourcePackResponse(packet); + } + + @Override + public void handleUseItem(ServerboundUseItemPacket packet) { + DenizenPacketHandler.instance.receivePlacePacket(player.getBukkitEntity()); + super.handleUseItem(packet); + } + + @Override + public void handlePlayerAction(ServerboundPlayerActionPacket packet) { + DenizenPacketHandler.instance.receiveDigPacket(player.getBukkitEntity()); + super.handlePlayerAction(packet); + } + + @Override + public void handleAnimate(ServerboundSwingPacket packet) { + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(player.getUUID(), getCraftPlayer()); + if (override != null && (override.hand != null || override.offhand != null)) { + player.getBukkitEntity().updateInventory(); + } + super.handleAnimate(packet); + } + + @Override + public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(player.getUUID(), getCraftPlayer()); + if (override != null && override.hand != null) { + Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), player.getBukkitEntity()::updateInventory, 2); + } + super.handleSetCarriedItem(packet); + } + + @Override + public void handleContainerClick(ServerboundContainerClickPacket packet) { + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(player.getUUID(), getCraftPlayer()); + if (override != null && packet.containerId() == 0) { + Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), player.getBukkitEntity()::updateInventory, 1); + } + super.handleContainerClick(packet); + } + + @Override + public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { + if (NMSHandler.debugPackets) { + Debug.log("Custom packet payload: " + packet.payload().type().id().toString() + " sent from " + player.getScoreboardName()); + } + super.handleCustomPayload(packet); + } + + @Override + public void handleSignUpdate(ServerboundSignUpdatePacket packet) { + if (fakeSignExpected != null && packet.getPos().equals(fakeSignExpected)) { + LocationTag loc = new LocationTag(player.getBukkitEntity().getWorld(), fakeSignExpected.getX(), fakeSignExpected.getY(), fakeSignExpected.getZ()); + this.connection.send(new ClientboundBlockUpdatePacket(player.level(), fakeSignExpected)); + PlayerChangesSignScriptEvent evt = (PlayerChangesSignScriptEvent) PlayerChangesSignScriptEvent.instance.clone(); + evt.material = new MaterialTag(org.bukkit.Material.OAK_WALL_SIGN); + evt.location = new LocationTag(player.getBukkitEntity().getLocation()); + evt.event = new SignChangeEvent(CraftBlock.at(player.level(), fakeSignExpected), player.getBukkitEntity(), packet.getLines()); + fakeSignExpected = null; + evt.fire(evt.event); + } + super.handleSignUpdate(packet); + } + + @Override + public void handleMovePlayer(ServerboundMovePlayerPacket packet) { + if (DenizenPacketHandler.forceNoclip.contains(player.getUUID())) { + player.noPhysics = true; + } + super.handleMovePlayer(packet); + } + + // For compatibility with other plugins using Reflection weirdly... + @Override + public void send(Packet packet) { + super.send(packet); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java new file mode 100644 index 0000000000..13ca382b8b --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java @@ -0,0 +1,168 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.blocks.FakeBlock; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import io.netty.buffer.Unpooled; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.Strategy; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockStates; +import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FakeBlockHelper { + + public static Field CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getFirstOfType(List.class); + public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); + public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); + public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; + public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); + public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); + public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); + public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 2).findFirst().get(); + + public static BlockState getNMSState(FakeBlock block) { + return ((CraftBlockData) block.material.getModernData()).getState(); + } + + public static boolean anyBlocksInSection(List blocks, int y) { + int minY = y << 4; + int maxY = (y << 4) + 16; + for (FakeBlock block : blocks) { + int blockY = block.location.getBlockY(); + if (blockY >= minY && blockY < maxY) { + return true; + } + } + return false; + } + + public static Field PAPER_CHUNK_READY; + public static boolean tryPaperPatch = true; + + public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket newPacket, ClientboundLevelChunkWithLightPacket oldPacket) { + if (!Denizen.supportsPaper || !tryPaperPatch) { + return; + } + try { + if (PAPER_CHUNK_READY == null) { + PAPER_CHUNK_READY = ReflectionHelper.getFields(ClientboundLevelChunkWithLightPacket.class).get("ready"); + } + } + catch (Throwable ex) { + tryPaperPatch = false; + Debug.echoError("Paper packet patch failed:"); + Debug.echoError(ex); + return; + } + try { + PAPER_CHUNK_READY.setBoolean(newPacket, true); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalPacket, int chunkX, int chunkZ, List blocks) { + try { + ClientboundLevelChunkWithLightPacket duplicateCorePacket = DenizenNetworkManagerImpl.copyPacket(originalPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(duplicateCorePacket, originalPacket); + RegistryFriendlyByteBuf copier = new RegistryFriendlyByteBuf(Unpooled.buffer(), CraftRegistry.getMinecraftRegistry()); + originalPacket.getChunkData().write(copier); + ClientboundLevelChunkPacketData packet = new ClientboundLevelChunkPacketData(copier, chunkX, chunkZ); + FriendlyByteBuf serial = originalPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf outputSerial = new FriendlyByteBuf(Unpooled.buffer(serial.readableBytes())); + List blockEntities = new ArrayList((List) CHUNKDATA_BLOCK_ENTITIES.get(originalPacket.getChunkData())); + CHUNKDATA_BLOCK_ENTITIES.set(packet, blockEntities); + for (int i = 0; i < blockEntities.size(); i++) { + Object blockEnt = blockEntities.get(i); + int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); + int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int x = (chunkX << 4) + ((xz >> 4) & 15); + int z = (chunkZ << 4) + (xz & 15); + for (FakeBlock block : blocks) { + LocationTag loc = block.location; + if (loc.getBlockX() == x && loc.getBlockY() == y && loc.getBlockZ() == z && block.material != null) { + BlockEntity newBlockEnt = CraftBlockStates.createNewTileEntity(block.material.getMaterial()); + Object newData = CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR.invoke(xz, y, newBlockEnt.getType(), newBlockEnt.getUpdateTag(CraftRegistry.getMinecraftRegistry())); + blockEntities.set(i, newData); + break; + } + } + } + int worldMinY = world.getMinHeight(); + int worldMaxY = world.getMaxHeight(); + int minChunkY = worldMinY >> 4; + int maxChunkY = worldMaxY >> 4; + Registry biomeRegistry = ((CraftWorld) world).getHandle().registryAccess().lookupOrThrow(Registries.BIOME); + for (int y = minChunkY; y < maxChunkY; y++) { + int blockCount = serial.readShort(); + // reflected constructors as workaround for spigot remapper bug - Mojang "IdMap" became Spigot "IRegistry" but should be "Registry" + PalettedContainer states = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); + states.read(serial); + PalettedContainer biomes = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry)); + biomes.read(serial); + if (anyBlocksInSection(blocks, y)) { + int minY = y << 4; + int maxY = (y << 4) + 16; + for (FakeBlock block : blocks) { + int blockY = block.location.getBlockY(); + if (blockY >= minY && blockY < maxY && block.material != null) { + int blockX = block.location.getBlockX(); + int blockZ = block.location.getBlockZ(); + blockX -= (blockX >> 4) * 16; + blockY -= (blockY >> 4) * 16; + blockZ -= (blockZ >> 4) * 16; + BlockState oldState = states.get(blockX, blockY, blockZ); + BlockState newState = getNMSState(block); + if (oldState.isAir() && !newState.isAir()) { + blockCount++; + } + else if (newState.isAir() && !oldState.isAir()) { + blockCount--; + } + states.set(blockX, blockY, blockZ, newState); + } + } + } + outputSerial.writeShort(blockCount); + states.write(outputSerial); + biomes.write(outputSerial); + } + byte[] outputBytes = outputSerial.array(); + CHUNKDATA_BUFFER_SETTER.invoke(packet, outputBytes); + CHUNKPACKET_CHUNKDATA_SETTER.invoke(duplicateCorePacket, packet); + return duplicateCorePacket; + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return null; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/ActionBarEventPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/ActionBarEventPacketHandlers.java new file mode 100644 index 0000000000..62ad8bd09b --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/ActionBarEventPacketHandlers.java @@ -0,0 +1,39 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.events.player.PlayerReceivesActionbarScriptEvent; +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.objects.core.ElementTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftChatMessage; + +public class ActionBarEventPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetActionBarTextPacket.class, ActionBarEventPacketHandlers::processActionbarPacket); + } + + public static ClientboundSetActionBarTextPacket processActionbarPacket(DenizenNetworkManagerImpl networkManager, ClientboundSetActionBarTextPacket actionbarPacket) { + PlayerReceivesActionbarScriptEvent event = PlayerReceivesActionbarScriptEvent.instance; + if (!event.loaded) { + return actionbarPacket; + } + event.reset(); + Component actionbarText = actionbarPacket.text(); + event.message = new ElementTag(FormattedTextHelper.stringify(Handler.componentToSpigot(actionbarText)), true); + event.rawJson = new ElementTag(CraftChatMessage.toJSON(actionbarText), true); + event.system = new ElementTag(false); + event.player = PlayerTag.mirrorBukkitPlayer(networkManager.player.getBukkitEntity()); + event = (PlayerReceivesActionbarScriptEvent) event.triggerNow(); + if (event.cancelled) { + return null; + } + if (event.modified) { + return new ClientboundSetActionBarTextPacket(Handler.componentToNMS(event.altMessageDetermination)); + } + return actionbarPacket; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java new file mode 100644 index 0000000000..7219ee9108 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java @@ -0,0 +1,310 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; +import com.denizenscript.denizencore.utilities.CoreConfiguration; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.phys.Vec3; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftVector; +import org.bukkit.util.Vector; + +import java.lang.reflect.Field; +import java.util.Set; + +public class AttachPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundMoveEntityPacket.class, AttachPacketHandlers::processAttachToForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundRotateHeadPacket.class, AttachPacketHandlers::processAttachToForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEntityMotionPacket.class, AttachPacketHandlers::processAttachToForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundTeleportEntityPacket.class, AttachPacketHandlers::processAttachToForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundRemoveEntitiesPacket.class, AttachPacketHandlers::processAttachToForPacket); + } + + public static Field POS_X_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_xa, short.class); + public static Field POS_Y_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_ya, short.class); + public static Field POS_Z_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_za, short.class); + public static Field YAW_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_yRot, byte.class); + public static Field PITCH_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_xRot, byte.class); + public static Field ENTITY_ID_PACKVELENT = ReflectionHelper.getFields(ClientboundSetEntityMotionPacket.class).get(ReflectionMappingsInfo.ClientboundSetEntityMotionPacket_id, int.class); + + public static Vector VECTOR_ZERO = new Vector(0, 0, 0); + + public static void tryProcessMovePacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundMoveEntityPacket packet, Entity e) throws IllegalAccessException { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + ClientboundMoveEntityPacket pNew; + int newId = att.attached.getBukkitEntity().getEntityId(); + if (packet instanceof ClientboundMoveEntityPacket.Pos) { + pNew = new ClientboundMoveEntityPacket.Pos(newId, packet.getXa(), packet.getYa(), packet.getZa(), packet.isOnGround()); + } + else if (packet instanceof ClientboundMoveEntityPacket.Rot) { + pNew = new ClientboundMoveEntityPacket.Rot(newId, Mth.packDegrees(packet.getYRot()), Mth.packDegrees(packet.getXRot()), packet.isOnGround()); + } + else if (packet instanceof ClientboundMoveEntityPacket.PosRot) { + pNew = new ClientboundMoveEntityPacket.PosRot(newId, packet.getXa(), packet.getYa(), packet.getZa(), Mth.packDegrees(packet.getYRot()), Mth.packDegrees(packet.getXRot()), packet.isOnGround()); + } + else { + if (CoreConfiguration.debugVerbose) { + Debug.echoError("Impossible move-entity packet class: " + packet.getClass().getCanonicalName()); + } + return; + } + if (att.positionalOffset != null) { + boolean isRotate = packet instanceof ClientboundMoveEntityPacket.PosRot || packet instanceof ClientboundMoveEntityPacket.Rot; + float yaw, pitch; + if (att.noRotate) { + Entity attachedEntity = ((CraftEntity) att.attached.getBukkitEntity()).getHandle(); + yaw = attachedEntity.getYRot(); + pitch = attachedEntity.getXRot(); + } + else if (isRotate) { + yaw = packet.getYRot(); + pitch = packet.getXRot(); + } + else { + yaw = e.getYRot(); + pitch = e.getXRot(); + } + if (att.noPitch) { + pitch = ((CraftEntity) att.attached.getBukkitEntity()).getHandle().getXRot(); + } + float newYaw = yaw; + if (isRotate) { + newYaw = EntityAttachmentHelper.normalizeAngle(newYaw + att.positionalOffset.getYaw()); + pitch = EntityAttachmentHelper.normalizeAngle(pitch + att.positionalOffset.getPitch()); + } + Vector goalPosition = att.fixedForOffset(new Vector(e.getX(), e.getY(), e.getZ()), e.getYRot(), e.getXRot()); + Vector oldPos = att.visiblePositions.get(networkManager.player.getUUID()); + boolean forceTele = false; + if (oldPos == null) { + oldPos = att.attached.getLocation().toVector(); + forceTele = true; + } + Vector moveNeeded = goalPosition.clone().subtract(oldPos); + att.visiblePositions.put(networkManager.player.getUUID(), goalPosition.clone()); + int offX = (int) (moveNeeded.getX() * (32 * 128)); + int offY = (int) (moveNeeded.getY() * (32 * 128)); + int offZ = (int) (moveNeeded.getZ() * (32 * 128)); + if ((isRotate && att.offsetRelative) || forceTele || offX < Short.MIN_VALUE || offX > Short.MAX_VALUE + || offY < Short.MIN_VALUE || offY > Short.MAX_VALUE + || offZ < Short.MIN_VALUE || offZ > Short.MAX_VALUE) { + ClientboundTeleportEntityPacket newTeleportPacket = new ClientboundTeleportEntityPacket( + att.attached.getBukkitEntity().getEntityId(), + new PositionMoveRotation(CraftVector.toNMS(goalPosition), Vec3.ZERO, newYaw, pitch), + Set.of(), + e.onGround() + ); + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Move-Tele Packet: " + newTeleportPacket.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName() + " with original yaw " + yaw + " adapted to " + newYaw); + } + networkManager.oldManager.send(newTeleportPacket); + } + else { + POS_X_PACKENT.setShort(pNew, (short) Mth.clamp(offX, Short.MIN_VALUE, Short.MAX_VALUE)); + POS_Y_PACKENT.setShort(pNew, (short) Mth.clamp(offY, Short.MIN_VALUE, Short.MAX_VALUE)); + POS_Z_PACKENT.setShort(pNew, (short) Mth.clamp(offZ, Short.MIN_VALUE, Short.MAX_VALUE)); + if (isRotate) { + YAW_PACKENT.setByte(pNew, EntityAttachmentHelper.compressAngle(yaw)); + PITCH_PACKENT.setByte(pNew, EntityAttachmentHelper.compressAngle(pitch)); + } + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Move Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName() + " with original yaw " + yaw + " adapted to " + newYaw); + } + networkManager.oldManager.send(pNew); + } + } + else { + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Replica-Move Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName()); + } + networkManager.oldManager.send(pNew); + } + } + } + } + if (e.passengers != null && !e.passengers.isEmpty()) { + for (Entity ent : e.passengers) { + tryProcessMovePacketForAttach(networkManager, packet, ent); + } + } + } + + public static void tryProcessRotateHeadPacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundRotateHeadPacket packet, Entity e) throws IllegalAccessException { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + float yaw = packet.getYHeadRot(); + Entity attachedEntity = ((CraftEntity) att.attached.getBukkitEntity()).getHandle(); + if (att.positionalOffset != null) { + if (att.noRotate) { + yaw = attachedEntity.getYRot(); + } + yaw = EntityAttachmentHelper.normalizeAngle(yaw + att.positionalOffset.getYaw()); + } + ClientboundRotateHeadPacket pNew = new ClientboundRotateHeadPacket(attachedEntity, EntityAttachmentHelper.compressAngle(yaw)); + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Head Rotation Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName()); + } + networkManager.oldManager.send(pNew); + } + } + } + if (e.passengers != null && !e.passengers.isEmpty()) { + for (Entity ent : e.passengers) { + tryProcessRotateHeadPacketForAttach(networkManager, packet, ent); + } + } + } + + public static void tryProcessVelocityPacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundSetEntityMotionPacket packet, Entity e) throws IllegalAccessException { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + ClientboundSetEntityMotionPacket pNew = DenizenNetworkManagerImpl.copyPacket(packet, ClientboundSetEntityMotionPacket.STREAM_CODEC); + ENTITY_ID_PACKVELENT.setInt(pNew, att.attached.getBukkitEntity().getEntityId()); + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Velocity Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName()); + } + networkManager.oldManager.send(pNew); + } + } + } + if (e.passengers != null && !e.passengers.isEmpty()) { + for (Entity ent : e.passengers) { + tryProcessVelocityPacketForAttach(networkManager, packet, ent); + } + } + } + + public static void tryProcessTeleportPacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundTeleportEntityPacket packet, Entity e, Vector relative) throws IllegalAccessException { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + ClientboundTeleportEntityPacket pNew; + Vector resultPos = CraftVector.toBukkit(packet.change().position()).add(relative); + if (att.positionalOffset != null) { + resultPos = att.fixedForOffset(resultPos, e.getYRot(), e.getXRot()); + float yaw, pitch; + if (att.noRotate) { + Entity attachedEntity = ((CraftEntity) att.attached.getBukkitEntity()).getHandle(); + yaw = attachedEntity.getYRot(); + pitch = attachedEntity.getXRot(); + } + else { + yaw = packet.change().yRot(); + pitch = packet.change().xRot(); + } + if (att.noPitch) { + pitch = ((CraftEntity) att.attached.getBukkitEntity()).getHandle().getXRot(); + } + float newYaw = EntityAttachmentHelper.normalizeAngle(yaw + att.positionalOffset.getYaw()); + pitch = EntityAttachmentHelper.normalizeAngle(pitch + att.positionalOffset.getPitch()); + pNew = new ClientboundTeleportEntityPacket( + att.attached.getBukkitEntity().getEntityId(), + new PositionMoveRotation(CraftVector.toNMS(resultPos), packet.change().deltaMovement(), newYaw, pitch), + packet.relatives(), + packet.onGround() + ); + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Teleport Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + + " sent to " + networkManager.player.getScoreboardName() + " with raw yaw " + yaw + " adapted to " + newYaw); + } + } + else { + pNew = new ClientboundTeleportEntityPacket(att.attached.getBukkitEntity().getEntityId(), packet.change(), packet.relatives(), packet.onGround()); + } + att.visiblePositions.put(networkManager.player.getUUID(), resultPos.clone()); + networkManager.oldManager.send(pNew); + } + } + } + if (e.passengers != null && !e.passengers.isEmpty()) { + for (Entity ent : e.passengers) { + tryProcessTeleportPacketForAttach(networkManager, packet, ent, new Vector(ent.getX() - e.getX(), ent.getY() - e.getY(), ent.getZ() - e.getZ())); + } + } + } + + public static Packet processAttachToForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (EntityAttachmentHelper.toEntityToData.isEmpty()) { + return packet; + } + try { + if (packet instanceof ClientboundMoveEntityPacket moveEntityPacket) { + Entity e = moveEntityPacket.getEntity(networkManager.player.level()); + if (e == null) { + return packet; + } + if (!e.isPassenger()) { + tryProcessMovePacketForAttach(networkManager, moveEntityPacket, e); + } + return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; + } + else if (packet instanceof ClientboundRotateHeadPacket rotateHeadPacket) { + Entity e = rotateHeadPacket.getEntity(networkManager.player.level()); + if (e == null) { + return packet; + } + tryProcessRotateHeadPacketForAttach(networkManager, rotateHeadPacket, e); + return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; + } + else if (packet instanceof ClientboundSetEntityMotionPacket setEntityMotionPacket) { + int ider = setEntityMotionPacket.getId(); + Entity e = networkManager.player.level().getEntity(ider); + if (e == null) { + return packet; + } + tryProcessVelocityPacketForAttach(networkManager, setEntityMotionPacket, e); + return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; + } + else if (packet instanceof ClientboundTeleportEntityPacket teleportEntityPacket) { + int ider = teleportEntityPacket.id(); + Entity e = networkManager.player.level().getEntity(ider); + if (e == null) { + return packet; + } + tryProcessTeleportPacketForAttach(networkManager, teleportEntityPacket, e, VECTOR_ZERO); + return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; + } + else if (packet instanceof ClientboundRemoveEntitiesPacket removeEntitiesPacket) { + for (int id : removeEntitiesPacket.getEntityIds()) { + Entity e = networkManager.player.level().getEntity(id); + if (e != null) { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + att.visiblePositions.remove(networkManager.player.getUUID()); + } + } + } + } + } + } + } + catch (Exception ex) { + Debug.echoError(ex); + } + return packet; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/BlockLightPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/BlockLightPacketHandlers.java new file mode 100644 index 0000000000..2e53cedab2 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/BlockLightPacketHandlers.java @@ -0,0 +1,27 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.abstracts.BlockLight; +import com.denizenscript.denizen.nms.v1_21.impl.blocks.BlockLightImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; + +public class BlockLightPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLightUpdatePacket.class, BlockLightPacketHandlers::processLightUpdatePacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, BlockLightPacketHandlers::processBlockUpdatePacket); + } + + public static void processLightUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundLightUpdatePacket lightUpdatePacket) { + if (!BlockLight.lightsByChunk.isEmpty()) { + BlockLightImpl.checkIfLightsBrokenByPacket(lightUpdatePacket, networkManager.player.level()); + } + } + + public static void processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { + if (!BlockLight.lightsByChunk.isEmpty()) { + BlockLightImpl.checkIfLightsBrokenByPacket(blockUpdatePacket, networkManager.player.level()); + } + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java new file mode 100644 index 0000000000..cd8abd286c --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java @@ -0,0 +1,47 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.events.player.PlayerReceivesMessageScriptEvent; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.packets.PacketOutChatImpl; +import com.denizenscript.denizen.utilities.packets.DenizenPacketHandler; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; + +public class DenizenPacketHandlerPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSystemChatPacket.class, DenizenPacketHandlerPacketHandlers::processPacketHandlerForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundPlayerChatPacket.class, DenizenPacketHandlerPacketHandlers::processPacketHandlerForPacket); + } + + public static Packet processPacketHandlerForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (DenizenPacketHandler.instance.shouldInterceptChatPacket()) { + PacketOutChatImpl packetHelper = null; + boolean isActionbar = false; + if (packet instanceof ClientboundSystemChatPacket chatPacket) { + isActionbar = chatPacket.overlay(); + packetHelper = new PacketOutChatImpl(chatPacket); + if (packetHelper.rawJson == null) { // Makes no sense but this can be null in weird edge cases + return packet; + } + } + else if (packet instanceof ClientboundPlayerChatPacket playerChatPacket) { + packetHelper = new PacketOutChatImpl(playerChatPacket); + } + if (packetHelper != null) { + PlayerReceivesMessageScriptEvent result = DenizenPacketHandler.instance.sendPacket(networkManager.player.getBukkitEntity(), packetHelper); + if (result != null) { + if (result.cancelled) { + return null; + } + if (result.modified) { + return new ClientboundSystemChatPacket(result.altMessageDetermination, isActionbar); + } + } + } + } + return packet; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DisguisePacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DisguisePacketHandlers.java new file mode 100644 index 0000000000..a15b517fb5 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DisguisePacketHandlers.java @@ -0,0 +1,160 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v1_21.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; +import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; +import com.denizenscript.denizen.utilities.entity.FakeEntity; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.level.Level; +import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.ToIntFunction; + +public class DisguisePacketHandlers { + + public static void registerHandlers() { + registerPacketHandler(ClientboundSetEntityDataPacket.class, ClientboundSetEntityDataPacket::id, DisguisePacketHandlers::processEntityDataPacket); + registerPacketHandler(ClientboundUpdateAttributesPacket.class, ClientboundUpdateAttributesPacket::getEntityId, DisguisePacketHandlers::processAttributesPacket); + registerPacketHandler(ClientboundAddEntityPacket.class, ClientboundAddEntityPacket::getId, DisguisePacketHandlers::sendDisguiseForPacket); + registerPacketHandler(ClientboundTeleportEntityPacket.class, ClientboundTeleportEntityPacket::id, DisguisePacketHandlers::processTeleportPacket); + registerPacketHandler(ClientboundMoveEntityPacket.Rot.class, ClientboundMoveEntityPacket::getEntity, DisguisePacketHandlers::processMoveEntityRotPacket); + registerPacketHandler(ClientboundMoveEntityPacket.PosRot.class, ClientboundMoveEntityPacket::getEntity, DisguisePacketHandlers::processMoveEntityPosRotPacket); + } + + private static boolean antiDuplicate = false; + + public static > void registerPacketHandler(Class packetType, ToIntFunction idGetter, DisguisePacketHandler handler) { + registerPacketHandler(packetType, (packet, level) -> level.getEntity(idGetter.applyAsInt(packet)), handler); + } + + public static > void registerPacketHandler(Class packetType, BiFunction entityGetter, DisguisePacketHandler handler) { + DenizenNetworkManagerImpl.registerPacketHandler(packetType, (networkManager, packet) -> { + if (DisguiseCommand.disguises.isEmpty() || antiDuplicate) { + return packet; + } + Entity entity = entityGetter.apply(packet, networkManager.player.level()); + if (entity == null) { + return packet; + } + Map playerMap = DisguiseCommand.disguises.get(entity.getUUID()); + if (playerMap == null) { + return packet; + } + DisguiseCommand.TrackedDisguise disguise = playerMap.get(networkManager.player.getUUID()); + if (disguise == null) { + disguise = playerMap.get(null); + } + if (disguise == null || !disguise.isActive) { + return packet; + } + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("DISGUISED packet " + packet.getClass().getName() + " for entity " + entity.getId() + " to player " + networkManager.player.getScoreboardName()); + } + try { + return handler.handle(networkManager, packet, disguise); + } + catch (Exception e) { + antiDuplicate = false; + throw e; // "pass it" to the generic exception handling + } + }); + } + + @FunctionalInterface + public interface DisguisePacketHandler> { + + T handle(DenizenNetworkManagerImpl networkManager, T packet, DisguiseCommand.TrackedDisguise disguise) throws Exception; + } + + public static ClientboundSetEntityDataPacket processEntityDataPacket(DenizenNetworkManagerImpl networkManager, ClientboundSetEntityDataPacket entityDataPacket, DisguiseCommand.TrackedDisguise disguise) { + if (entityDataPacket.id() == networkManager.player.getId()) { + if (!disguise.shouldFake) { + return entityDataPacket; + } + for (SynchedEntityData.DataValue dataValue : entityDataPacket.packedItems()) { + if (dataValue.id() == 0) { // Entity flags + List> newData = new ArrayList<>(entityDataPacket.packedItems()); + newData.remove(dataValue); + byte flags = (byte) dataValue.value(); + flags |= 0x20; // Invisible flag + newData.add(PacketHelperImpl.createEntityData(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS, flags)); + return new ClientboundSetEntityDataPacket(entityDataPacket.id(), newData); + } + } + } + else { + List> data = ((CraftEntity) disguise.toOthers.entity.entity).getHandle().getEntityData().getNonDefaultValues(); + return data != null ? new ClientboundSetEntityDataPacket(entityDataPacket.id(), data) : null; + } + return entityDataPacket; + } + + public static ClientboundUpdateAttributesPacket processAttributesPacket(DenizenNetworkManagerImpl networkManager, ClientboundUpdateAttributesPacket attributesPacket, DisguiseCommand.TrackedDisguise disguise) { + FakeEntity fake = attributesPacket.getEntityId() == networkManager.player.getId() ? disguise.fakeToSelf : disguise.toOthers; + return fake == null || fake.entity.entity instanceof LivingEntity ? attributesPacket : null; // Non-living entities don't have attributes + } + + public static ClientboundTeleportEntityPacket processTeleportPacket(DenizenNetworkManagerImpl networkManager, ClientboundTeleportEntityPacket teleportEntityPacket, DisguiseCommand.TrackedDisguise disguise) throws IllegalAccessException { + if (disguise.as.getBukkitEntityType() == EntityType.ENDER_DRAGON) { + PositionMoveRotation oldChange = teleportEntityPacket.change(); + return new ClientboundTeleportEntityPacket( + teleportEntityPacket.id(), + new PositionMoveRotation(oldChange.position(), oldChange.deltaMovement(), EntityAttachmentHelper.normalizeAngle(oldChange.yRot() + 180), oldChange.xRot()), + teleportEntityPacket.relatives(), + teleportEntityPacket.onGround() + ); + } + return sendDisguiseForPacket(networkManager, teleportEntityPacket, disguise); + } + + + public static ClientboundMoveEntityPacket.Rot processMoveEntityRotPacket(DenizenNetworkManagerImpl networkManager, ClientboundMoveEntityPacket.Rot rotPacket, DisguiseCommand.TrackedDisguise disguise) { + if (disguise.as.getBukkitEntityType() == EntityType.ENDER_DRAGON) { + return new ClientboundMoveEntityPacket.Rot( + disguise.entity.getBukkitEntity().getEntityId(), + EntityAttachmentHelper.compressAngle(rotPacket.getYRot() + 180), + Mth.packDegrees(rotPacket.getXRot()), + rotPacket.isOnGround() + ); + } + return sendDisguiseForPacket(networkManager, rotPacket, disguise); + } + + + public static ClientboundMoveEntityPacket.PosRot processMoveEntityPosRotPacket(DenizenNetworkManagerImpl networkManager, ClientboundMoveEntityPacket.PosRot posRotPacket, DisguiseCommand.TrackedDisguise disguise) { + if (disguise.as.getBukkitEntityType() == EntityType.ENDER_DRAGON) { + return new ClientboundMoveEntityPacket.PosRot( + disguise.entity.getBukkitEntity().getEntityId(), + posRotPacket.getXa(), + posRotPacket.getYa(), + posRotPacket.getZa(), + EntityAttachmentHelper.compressAngle(posRotPacket.getYRot() + 180), + Mth.packDegrees(posRotPacket.getXRot()), + posRotPacket.isOnGround() + ); + } + return sendDisguiseForPacket(networkManager, posRotPacket, disguise); + } + + public static > T sendDisguiseForPacket(DenizenNetworkManagerImpl networkManager, T packet, DisguiseCommand.TrackedDisguise disguise) { + antiDuplicate = true; + disguise.sendTo(List.of(new PlayerTag(networkManager.player.getUUID()))); + antiDuplicate = false; + return null; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/EntityMetadataPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/EntityMetadataPacketHandlers.java new file mode 100644 index 0000000000..ee538c2b83 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/EntityMetadataPacketHandlers.java @@ -0,0 +1,92 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v1_21.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.scripts.commands.entity.GlowCommand; +import com.denizenscript.denizen.scripts.commands.entity.InvisibleCommand; +import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; +import com.denizenscript.denizen.scripts.commands.entity.SneakCommand; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class EntityMetadataPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEntityDataPacket.class, EntityMetadataPacketHandlers::processMetadataChangesForPacket); + } + + public static ClientboundSetEntityDataPacket getModifiedMetadataFor(DenizenNetworkManagerImpl networkManager, ClientboundSetEntityDataPacket metadataPacket) { + if (!RenameCommand.hasAnyDynamicRenames() && SneakCommand.forceSetSneak.isEmpty() && InvisibleCommand.helper.noOverrides() && GlowCommand.helper.noOverrides()) { + return null; + } + try { + Entity entity = networkManager.player.level().getEntity(metadataPacket.id()); + if (entity == null) { + return null; // If it doesn't exist on-server, it's definitely not relevant, so move on + } + String nameToApply = RenameCommand.getCustomNameFor(entity.getUUID(), networkManager.player.getBukkitEntity(), false); + Boolean forceSneak = SneakCommand.shouldSneak(entity.getUUID(), networkManager.player.getUUID()); + Boolean isInvisible = InvisibleCommand.helper.getState(entity.getBukkitEntity(), networkManager.player.getUUID(), true); + Boolean isGlowing = GlowCommand.helper.getState(entity.getBukkitEntity(), networkManager.player.getUUID(), true); + boolean shouldModifyFlags = isInvisible != null || forceSneak != null || isGlowing != null; + if (nameToApply == null && !shouldModifyFlags) { + return null; + } + List> data = new ArrayList<>(metadataPacket.packedItems().size()); + Byte currentFlags = null; + for (SynchedEntityData.DataValue dataValue : metadataPacket.packedItems()) { + if (dataValue.id() == 0 && shouldModifyFlags) { // 0: Entity Flags + currentFlags = (Byte) dataValue.value(); + } + else if (nameToApply == null || (dataValue.id() != 2 && dataValue.id() != 3)) { // 2 and 3: Custom name and custom name visible + data.add(dataValue); + } + } + if (shouldModifyFlags) { + byte flags = currentFlags == null ? entity.getEntityData().get(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS) : currentFlags; + flags = applyEntityDataFlag(flags, forceSneak, 0x02); + flags = applyEntityDataFlag(flags, isInvisible, 0x20); + flags = applyEntityDataFlag(flags, isGlowing, 0x40); + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS, flags)); + } + if (nameToApply != null) { + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(nameToApply, ChatColor.WHITE))))); + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true)); + } + return new ClientboundSetEntityDataPacket(metadataPacket.id(), data); + } + catch (Throwable ex) { + Debug.echoError(ex); + return null; + } + } + + public static byte applyEntityDataFlag(byte currentFlags, Boolean value, int flag) { + if (value == null) { + return currentFlags; + } + return (byte) (value ? currentFlags | flag : currentFlags & ~flag); + } + + public static Packet processMetadataChangesForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (!(packet instanceof ClientboundSetEntityDataPacket entityDataPacket)) { + return packet; + } + ClientboundSetEntityDataPacket altPacket = getModifiedMetadataFor(networkManager, entityDataPacket); + if (altPacket == null) { + return packet; + } + return altPacket; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java new file mode 100644 index 0000000000..4938114cac --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -0,0 +1,112 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.FakeBlockHelper; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; +import com.denizenscript.denizen.utilities.blocks.FakeBlock; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.world.level.block.state.BlockState; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.List; + +public class FakeBlocksPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelChunkWithLightPacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSectionBlocksUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + } + + public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); + public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); + public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); + + public static Packet processShowFakeForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (FakeBlock.blocks.isEmpty()) { + return packet; + } + try { + if (packet instanceof ClientboundLevelChunkWithLightPacket) { + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return packet; + } + int chunkX = ((ClientboundLevelChunkWithLightPacket) packet).getX(); + int chunkZ = ((ClientboundLevelChunkWithLightPacket) packet).getZ(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); + List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); + if (blocks == null || blocks.isEmpty()) { + return packet; + } + ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks); + return newPacket; + } + else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return sectionBlocksUpdatePacket; + } + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionBlocksUpdatePacket); + ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); + if (!map.byChunk.containsKey(coordinateDenizen)) { + return sectionBlocksUpdatePacket; + } + ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionBlocksUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); + BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); + short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); + BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); + OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); + BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); + for (int i = 0; i < offsetArray.length; i++) { + short offset = offsetArray[i]; + BlockPos pos = coord.relativeToBlockPos(offset); + location.setX(pos.getX()); + location.setY(pos.getY()); + location.setZ(pos.getZ()); + FakeBlock block = map.byLocation.get(location); + if (block != null) { + dataArray[i] = FakeBlockHelper.getNMSState(block); + } + } + return newPacket; + } + else if (packet instanceof ClientboundBlockUpdatePacket) { + BlockPos pos = ((ClientboundBlockUpdatePacket) packet).getPos(); + LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); + if (block != null) { + ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(((ClientboundBlockUpdatePacket) packet).getPos(), FakeBlockHelper.getNMSState(block)); + return newPacket; + } + } + else if (packet instanceof ClientboundBlockChangedAckPacket) { + // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. + /* + ClientboundBlockChangedAckPacket origPack = (ClientboundBlockChangedAckPacket) packet; + BlockPos pos = origPack.pos(); + LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); + if (block != null) { + ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(origPack.pos(), FakeBlockHelper.getNMSState(block), origPack.action(), false); + oldManager.send(newPacket, genericfuturelistener); + return true; + }*/ + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return packet; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java new file mode 100644 index 0000000000..97d21d284a --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java @@ -0,0 +1,138 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; +import com.mojang.datafixers.util.Pair; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class FakeEquipmentPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEquipmentPacket.class, FakeEquipmentPacketHandlers::processSetEquipmentPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundEntityEventPacket.class, FakeEquipmentPacketHandlers::processEntityEventPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundContainerSetContentPacket.class, FakeEquipmentPacketHandlers::processContainerSetContentPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundContainerSetSlotPacket.class, FakeEquipmentPacketHandlers::processContainerSetSlotPacket); + } + + public static ClientboundSetEquipmentPacket processSetEquipmentPacket(DenizenNetworkManagerImpl networkManager, ClientboundSetEquipmentPacket setEquipmentPacket) { + if (FakeEquipCommand.overrides.isEmpty()) { + return setEquipmentPacket; + } + Entity entity = networkManager.player.level().getEntity(setEquipmentPacket.getEntity()); + if (entity == null) { + return setEquipmentPacket; + } + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(entity.getUUID(), networkManager.player.getBukkitEntity()); + if (override == null) { + return setEquipmentPacket; + } + List> equipment = new ArrayList<>(setEquipmentPacket.getSlots()); + for (int i = 0; i < equipment.size(); i++) { + Pair pair = equipment.get(i); + ItemStack use = switch (pair.getFirst()) { + case MAINHAND -> override.hand == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.hand.getItemStack()); + case OFFHAND -> override.offhand == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.offhand.getItemStack()); + case CHEST -> override.chest == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.chest.getItemStack()); + case HEAD -> override.head == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.head.getItemStack()); + case LEGS -> override.legs == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.legs.getItemStack()); + case FEET -> override.boots == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.boots.getItemStack()); + case BODY -> pair.getSecond(); // TODO: 1.20.6: is this actually used here? do we want to allow overriding it? + case SADDLE -> pair.getSecond(); // TODO: 1.21.5: same as above + }; + equipment.set(i, new Pair<>(pair.getFirst(), use)); + } + return new ClientboundSetEquipmentPacket(setEquipmentPacket.getEntity(), equipment); + } + + public static Packet processEntityEventPacket(DenizenNetworkManagerImpl networkManager, ClientboundEntityEventPacket entityEventPacket) { + if (FakeEquipCommand.overrides.isEmpty()) { + return entityEventPacket; + } + if (entityEventPacket.getEventId() != 55) { + return entityEventPacket; + } + if (!(entityEventPacket.getEntity(networkManager.player.level()) instanceof LivingEntity livingEntity)) { + return entityEventPacket; + } + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(livingEntity.getUUID(), networkManager.player.getBukkitEntity()); + if (override == null || (override.hand == null && override.offhand == null)) { + return entityEventPacket; + } + ItemStack hand = override.hand != null ? CraftItemStack.asNMSCopy(override.hand.getItemStack()) : livingEntity.getMainHandItem(); + ItemStack offhand = override.offhand != null ? CraftItemStack.asNMSCopy(override.offhand.getItemStack()) : livingEntity.getOffhandItem(); + return new ClientboundSetEquipmentPacket(livingEntity.getId(), List.of(new Pair<>(EquipmentSlot.MAINHAND, hand), new Pair<>(EquipmentSlot.OFFHAND, offhand))); + } + + public static ClientboundContainerSetContentPacket processContainerSetContentPacket(DenizenNetworkManagerImpl networkManager, ClientboundContainerSetContentPacket setContentPacket) { + if (FakeEquipCommand.overrides.isEmpty()) { + return setContentPacket; + } + if (setContentPacket.containerId() != 0) { + return setContentPacket; + } + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(networkManager.player.getUUID(), networkManager.player.getBukkitEntity()); + if (override == null) { + return setContentPacket; + } + List items = setContentPacket.items(); + if (override.head != null) { + items.set(5, CraftItemStack.asNMSCopy(override.head.getItemStack())); + } + if (override.chest != null) { + items.set(6, CraftItemStack.asNMSCopy(override.chest.getItemStack())); + } + if (override.legs != null) { + items.set(7, CraftItemStack.asNMSCopy(override.legs.getItemStack())); + } + if (override.boots != null) { + items.set(8, CraftItemStack.asNMSCopy(override.boots.getItemStack())); + } + if (override.offhand != null) { + items.set(45, CraftItemStack.asNMSCopy(override.offhand.getItemStack())); + } + if (override.hand != null) { + items.set(getMainHandSlot(networkManager.player), CraftItemStack.asNMSCopy(override.hand.getItemStack())); + } + return new ClientboundContainerSetContentPacket(setContentPacket.containerId(), setContentPacket.stateId(), items, setContentPacket.carriedItem()); + } + + public static ClientboundContainerSetSlotPacket processContainerSetSlotPacket(DenizenNetworkManagerImpl networkManager, ClientboundContainerSetSlotPacket setSlotPacket) { + if (FakeEquipCommand.overrides.isEmpty()) { + return setSlotPacket; + } + if (setSlotPacket.getContainerId() != 0) { + return setSlotPacket; + } + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(networkManager.player.getUUID(), networkManager.player.getBukkitEntity()); + if (override == null) { + return setSlotPacket; + } + ItemTag item = switch (setSlotPacket.getSlot()) { + case 5 -> override.head; + case 6 -> override.chest; + case 7 -> override.legs; + case 8 -> override.boots; + case 45 -> override.offhand; + default -> setSlotPacket.getSlot() == getMainHandSlot(networkManager.player) ? override.hand : null; + }; + if (item == null) { + return setSlotPacket; + } + return new ClientboundContainerSetSlotPacket(setSlotPacket.getContainerId(), setSlotPacket.getStateId(), setSlotPacket.getSlot(), CraftItemStack.asNMSCopy(item.getItemStack())); + } + + public static int getMainHandSlot(ServerPlayer player) { + return player.getInventory().getSelectedSlot() + 36; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakePlayerPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakePlayerPacketHandlers.java new file mode 100644 index 0000000000..dff04ee9a5 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakePlayerPacketHandlers.java @@ -0,0 +1,29 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +/* +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v1_20.impl.entities.EntityFakePlayerImpl; +import com.denizenscript.denizen.nms.v1_20.impl.network.handlers.DenizenNetworkManagerImpl; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import org.bukkit.Bukkit; + +import java.util.List; +*/ + +public class FakePlayerPacketHandlers { + + public static void registerHandlers() { + // TODO: 1.20.2: Replace this. + //DenizenNetworkManagerImpl.registerPacketHandler(ClientboundAddPlayerPacket.class, FakePlayerPacketHandlers::processAddPlayerPacket); + } + + /* + public static void processAddPlayerPacket(DenizenNetworkManagerImpl networkManager, ClientboundAddPlayerPacket addPlayerPacket) { + if (networkManager.player.level().getEntity(addPlayerPacket.getEntityId()) instanceof EntityFakePlayerImpl fakePlayer) { + networkManager.send(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, fakePlayer)); + Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), + () -> networkManager.send(new ClientboundPlayerInfoRemovePacket(List.of(fakePlayer.getUUID()))), 5); + } + }*/ +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java new file mode 100644 index 0000000000..cac24bc7d8 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java @@ -0,0 +1,69 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.utilities.entity.HideEntitiesHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; + +public class HiddenEntitiesPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundAddEntityPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + //DenizenNetworkManagerImpl.registerPacketHandler(ClientboundAddExperienceOrbPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundMoveEntityPacket.Rot.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundMoveEntityPacket.Pos.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundMoveEntityPacket.PosRot.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEntityDataPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEntityMotionPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundTeleportEntityPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + } + + public static boolean isHidden(ServerPlayer player, Entity entity) { + return entity != null && HideEntitiesHelper.playerShouldHide(player.getBukkitEntity().getUniqueId(), entity.getBukkitEntity()); + } + + public static Packet processHiddenEntitiesForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (!HideEntitiesHelper.hasAnyHides()) { + return packet; + } + try { + int ider = -1; + Entity e = null; + if (packet instanceof ClientboundAddEntityPacket) { + ider = ((ClientboundAddEntityPacket) packet).getId(); + } + //TODO: 1.21.5: check this packet list + /* + else if (packet instanceof ClientboundAddExperienceOrbPacket) { + ider = ((ClientboundAddExperienceOrbPacket) packet).getId(); + }*/ + else if (packet instanceof ClientboundMoveEntityPacket) { + e = ((ClientboundMoveEntityPacket) packet).getEntity(networkManager.player.level()); + } + else if (packet instanceof ClientboundSetEntityDataPacket) { + ider = ((ClientboundSetEntityDataPacket) packet).id(); + } + else if (packet instanceof ClientboundSetEntityMotionPacket) { + ider = ((ClientboundSetEntityMotionPacket) packet).getId(); + } + else if (packet instanceof ClientboundTeleportEntityPacket) { + ider = ((ClientboundTeleportEntityPacket) packet).id(); + } + if (e == null && ider != -1) { + e = networkManager.player.level().getEntity(ider); + } + if (e != null) { + if (isHidden(networkManager.player, e)) { + return null; + } + } + } + catch (Exception ex) { + Debug.echoError(ex); + } + return packet; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HideParticlesPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HideParticlesPacketHandlers.java new file mode 100644 index 0000000000..09328473fc --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HideParticlesPacketHandlers.java @@ -0,0 +1,31 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.utilities.packets.HideParticles; +import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; +import org.bukkit.Particle; +import org.bukkit.craftbukkit.v1_21_R7.CraftParticle; + +import java.util.Set; + +public class HideParticlesPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelParticlesPacket.class, HideParticlesPacketHandlers::processParticlesPacket); + } + + public static ClientboundLevelParticlesPacket processParticlesPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelParticlesPacket particlesPacket) { + if (HideParticles.hidden.isEmpty()) { + return particlesPacket; + } + Set hidden = HideParticles.hidden.get(networkManager.player.getUUID()); + if (hidden == null) { + return particlesPacket; + } + Particle bukkitParticle = CraftParticle.minecraftToBukkit(particlesPacket.getParticle().getType()); + if (hidden.contains(bukkitParticle)) { + return null; + } + return particlesPacket; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java new file mode 100644 index 0000000000..4dad338a67 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java @@ -0,0 +1,39 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.events.player.PlayerHearsSoundScriptEvent; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.world.entity.Entity; +import org.bukkit.Location; + +public class PlayerHearsSoundEventPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSoundPacket.class, PlayerHearsSoundEventPacketHandlers::processSoundPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSoundEntityPacket.class, PlayerHearsSoundEventPacketHandlers::processSoundPacket); + } + + public static Packet processSoundPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (!PlayerHearsSoundScriptEvent.instance.eventData.isEnabled) { + return packet; + } + if (packet instanceof ClientboundSoundPacket) { + ClientboundSoundPacket spacket = (ClientboundSoundPacket) packet; + return PlayerHearsSoundScriptEvent.instance.run(networkManager.player.getBukkitEntity(), spacket.getSound().value().location().getPath(), spacket.getSource().name(), + false, null, new Location(networkManager.player.getBukkitEntity().getWorld(), spacket.getX(), spacket.getY(), spacket.getZ()), spacket.getVolume(), spacket.getPitch()) ? null : packet; + } + else if (packet instanceof ClientboundSoundEntityPacket) { + ClientboundSoundEntityPacket spacket = (ClientboundSoundEntityPacket) packet; + Entity entity = networkManager.player.level().getEntity(spacket.getId()); + if (entity == null) { + return packet; + } + return PlayerHearsSoundScriptEvent.instance.run(networkManager.player.getBukkitEntity(), spacket.getSound().value().location().getPath(), spacket.getSource().name(), + false, entity.getBukkitEntity(), null, spacket.getVolume(), spacket.getPitch()) ? null : packet; + } + return packet; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java new file mode 100644 index 0000000000..21e5d5ba0c --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java @@ -0,0 +1,126 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; + +import com.denizenscript.denizen.events.player.PlayerReceivesTablistUpdateScriptEvent; +import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v1_21.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.base.Joiner; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.world.level.GameType; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +public class TablistUpdateEventPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundPlayerInfoUpdatePacket.class, TablistUpdateEventPacketHandlers::processTablistPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundPlayerInfoRemovePacket.class, TablistUpdateEventPacketHandlers::processTablistPacket); + } + + public static boolean tablistBreakOnlyOnce = false; + + // TODO: properly rebundle the packet instead of splitting it up + public static Packet processTablistPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (!PlayerReceivesTablistUpdateScriptEvent.instance.eventData.isEnabled) { + return packet; + } + if (packet instanceof ClientboundPlayerInfoUpdatePacket) { + ClientboundPlayerInfoUpdatePacket infoPacket = (ClientboundPlayerInfoUpdatePacket) packet; + String mode = ""; + for (ClientboundPlayerInfoUpdatePacket.Action action : infoPacket.actions()) { + switch (action) { + case ADD_PLAYER: + mode = "add"; + break; + case UPDATE_LATENCY: + mode = mode.isEmpty() ? "update_latency" : mode + "|update_latency"; + break; + case UPDATE_GAME_MODE: + mode = mode.isEmpty() ? "update_gamemode" : mode + "|update_gamemode"; + break; + case UPDATE_DISPLAY_NAME: + mode = mode.isEmpty() ? "update_display" : mode + "|update_display"; + break; + case UPDATE_LISTED: + mode = mode.isEmpty() ? "update_listed" : mode + "|update_listed"; + break; + case INITIALIZE_CHAT: + mode = mode.isEmpty() ? "initialize_chat" : mode + "|initialize_chat"; + default: + break; + } + } + if (mode.isEmpty()) { + if (!tablistBreakOnlyOnce) { + tablistBreakOnlyOnce = true; + Debug.echoError("Tablist packet processing failed: unknown action " + Joiner.on(", ").join(infoPacket.actions())); + } + return packet; + } + boolean isOverriding = false; + for (ClientboundPlayerInfoUpdatePacket.Entry update : infoPacket.entries()) { + GameProfile profile = update.profile(); + String texture = null, signature = null; + if (profile.properties().containsKey("textures")) { + Property property = profile.properties().get("textures").stream().findFirst().get(); + texture = property.value(); + signature = property.signature(); + } + String modeText = update.gameMode() == null ? null : update.gameMode().name(); + PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData(mode, profile.id(), update.listed(), profile.name(), + update.displayName() == null ? null : FormattedTextHelper.stringify(Handler.componentToSpigot(update.displayName())), modeText, texture, signature, update.latency()); + PlayerReceivesTablistUpdateScriptEvent.fire(networkManager.player.getBukkitEntity(), data); + if (data.modified) { + if (!isOverriding) { + isOverriding = true; + for (ClientboundPlayerInfoUpdatePacket.Entry priorUpdate : infoPacket.entries()) { + if (priorUpdate == update) { + break; + } + networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(priorUpdate))); + } + } + if (!data.cancelled) { + GameProfile newProfile = ProfileEditorImpl.createGameProfile(data.id, data.name, data.texture, data.signature); + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(newProfile.id(), newProfile, data.isListed, data.latency, data.gamemode == null ? null : GameType.byName(CoreUtilities.toLowerCase(data.gamemode)), + data.display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(data.display, ChatColor.WHITE)), update.showHat(), update.listOrder(), update.chatSession()); + networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(entry))); + } + } + else if (isOverriding) { + networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(update))); + } + } + return isOverriding ? null : packet; + } + else if (packet instanceof ClientboundPlayerInfoRemovePacket) { + ClientboundPlayerInfoRemovePacket removePacket = (ClientboundPlayerInfoRemovePacket) packet; + boolean modified = false; + List altIds = new ArrayList<>(((ClientboundPlayerInfoRemovePacket) packet).profileIds()); + for (UUID id : ((ClientboundPlayerInfoRemovePacket) packet).profileIds()) { + PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData("remove", id, false, null, null, null, null, null, 0); + PlayerReceivesTablistUpdateScriptEvent.fire(networkManager.player.getBukkitEntity(), data); + if (data.modified && data.cancelled) { + modified = true; + altIds.remove(id); + } + } + if (modified) { + return new ClientboundPlayerInfoRemovePacket(altIds); + } + } + return packet; + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInResourcePackStatusImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInResourcePackStatusImpl.java new file mode 100644 index 0000000000..9069658423 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInResourcePackStatusImpl.java @@ -0,0 +1,18 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.packets; + +import com.denizenscript.denizen.nms.interfaces.packets.PacketInResourcePackStatus; +import net.minecraft.network.protocol.common.ServerboundResourcePackPacket; + +public class PacketInResourcePackStatusImpl implements PacketInResourcePackStatus { + + private ServerboundResourcePackPacket internal; + + public PacketInResourcePackStatusImpl(ServerboundResourcePackPacket internal) { + this.internal = internal; + } + + @Override + public String getStatus() { + return internal.action().name(); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInSteerVehicleImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInSteerVehicleImpl.java new file mode 100644 index 0000000000..ce2c293c29 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInSteerVehicleImpl.java @@ -0,0 +1,33 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.packets; + +import com.denizenscript.denizen.nms.interfaces.packets.PacketInSteerVehicle; +import net.minecraft.network.protocol.game.ServerboundPlayerInputPacket; + +public class PacketInSteerVehicleImpl implements PacketInSteerVehicle { + + private ServerboundPlayerInputPacket internal; + + public PacketInSteerVehicleImpl(ServerboundPlayerInputPacket internal) { + this.internal = internal; + } + + @Override + public float getLeftwardInput() { + return internal.input().left() ? 1 : 0; + } + + @Override + public float getForwardInput() { + return internal.input().forward() ? 1 : 0; + } + + @Override + public boolean getJumpInput() { + return internal.input().jump(); + } + + @Override + public boolean getDismountInput() { + return internal.input().shift(); + } +} diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketOutChatImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketOutChatImpl.java new file mode 100644 index 0000000000..13d5d02757 --- /dev/null +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketOutChatImpl.java @@ -0,0 +1,50 @@ +package com.denizenscript.denizen.nms.v1_21.impl.network.packets; + +import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import net.md_5.bungee.chat.ComponentSerializer; +import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftChatMessage; + +public class PacketOutChatImpl extends PacketOutChat { + + public ClientboundPlayerChatPacket playerPacket; + public ClientboundSystemChatPacket systemPacket; + public String message; + public String rawJson; + public boolean isOverlayActionbar; + + public PacketOutChatImpl(ClientboundSystemChatPacket internal) { + systemPacket = internal; + rawJson = CraftChatMessage.toJSON(internal.content()); + message = FormattedTextHelper.stringify(FormattedTextHelper.parseJson(rawJson)); + isOverlayActionbar = internal.overlay(); + } + + public PacketOutChatImpl(ClientboundPlayerChatPacket internal) { + playerPacket = internal; + rawJson = ComponentSerializer.toString(internal.body().content()); + message = FormattedTextHelper.stringify(FormattedTextHelper.parseJson(rawJson)); + } + + @Override + public boolean isSystem() { + return systemPacket != null; + } + + @Override + public boolean isActionbar() { + return isOverlayActionbar; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public String getRawJson() { + return rawJson; + } +} From 2858f2f5ab51d6189d6f58b1a197a3f0f996ddf0 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 27 Mar 2026 01:54:44 +0000 Subject: [PATCH 080/169] `MaterialMode`: fix enum error on old versions --- .../denizen/objects/properties/material/MaterialMode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java index d9dcb0f0c9..3b7250537d 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java @@ -82,7 +82,7 @@ else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() i return new ElementTag(sculkShrieker.isShrieking() ? "SHRIEKING" : "NORMAL", true); } else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof CreakingHeart creakingHeart) { - return new ElementTag(creakingHeart.getCreakingHeartState()); + return new ElementTag(creakingHeart.getCreakingHeartState().name(), true); // TODO: once 1.21 is the minimum supported version, use the enum constructor } return null; } From 3bb9efde9b489843287e529ac3b6b6528ebb5cd0 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 25 Mar 2026 14:52:48 +0000 Subject: [PATCH 081/169] 26.1 part 2: bump versions --- README.md | 2 +- dist/pom.xml | 6 +++ plugin/pom.xml | 2 +- pom.xml | 1 + v26_1/pom.xml | 40 ++----------------- .../denizen/nms/v26_1/Handler.java | 2 +- 6 files changed, 13 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index adf885b898..5246dcd86e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, and 1.21.11! +**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, and 26.1! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html diff --git a/dist/pom.xml b/dist/pom.xml index 25100bb2e5..a379213c15 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -60,6 +60,12 @@ ${project.parent.version} compile + + com.denizenscript + denizen-v26_1 + ${project.parent.version} + compile + com.denizenscript denizen-paper diff --git a/plugin/pom.xml b/plugin/pom.xml index f1abe6f709..a6a069d70b 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -30,7 +30,7 @@ org.spigotmc spigot-api - 1.21.11-R0.2-SNAPSHOT + 26.1-R0.1-SNAPSHOT jar provided diff --git a/pom.xml b/pom.xml index a5c28e2ada..237da72570 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ plugin paper + v26_1 v1_21 v1_20 v1_19 diff --git a/v26_1/pom.xml b/v26_1/pom.xml index 1449c8e8a8..0b20031d3d 100644 --- a/v26_1/pom.xml +++ b/v26_1/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.denizenscript - denizen-v1_21 + denizen-v26_1 1.3.1-SNAPSHOT @@ -19,53 +19,19 @@ org.spigotmc spigot-api - 1.21.11-R0.2-SNAPSHOT + 26.1-R0.1-SNAPSHOT provided org.spigotmc spigot - 1.21.11-R0.2-SNAPSHOT - remapped-mojang + 26.1-R0.1-SNAPSHOT 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 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 index 01ffc5fac9..3e1fa23ae5 100644 --- 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 @@ -150,7 +150,7 @@ public void undisableAsyncCatcher() { @Override public boolean isExactServerVersionMatch() { - return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("1.21.11") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e3cd927e07e6ff434793a0474c51b2b9"); + return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("26.1") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e8ece90188c951d866bd2fffc52c803e"); } @Override From b336d975dd3bab803ee17e78e91db451c3dd97f4 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 25 Mar 2026 15:08:09 +0000 Subject: [PATCH 082/169] 26.1 part 3: handle import versions --- .../denizen/nms/v26_1/Handler.java | 38 +++++++++---------- .../nms/v26_1/ReflectionMappingsInfo.java | 2 +- .../v26_1/helpers/AdvancementHelperImpl.java | 12 +++--- .../v26_1/helpers/AnimationHelperImpl.java | 8 ++-- .../nms/v26_1/helpers/BlockHelperImpl.java | 30 +++++++-------- .../nms/v26_1/helpers/ChunkHelperImpl.java | 8 ++-- .../v26_1/helpers/CustomEntityHelperImpl.java | 16 ++++---- .../v26_1/helpers/EnchantmentHelperImpl.java | 2 +- .../v26_1/helpers/EntityDataNameMapper.java | 2 +- .../nms/v26_1/helpers/EntityHelperImpl.java | 24 ++++++------ .../nms/v26_1/helpers/FishingHelperImpl.java | 12 +++--- .../nms/v26_1/helpers/ItemHelperImpl.java | 28 +++++++------- .../denizen/nms/v26_1/helpers/NBTAdapter.java | 2 +- .../nms/v26_1/helpers/PacketHelperImpl.java | 26 ++++++------- .../nms/v26_1/helpers/PlayerHelperImpl.java | 34 ++++++++--------- .../nms/v26_1/helpers/WorldHelperImpl.java | 8 ++-- .../denizen/nms/v26_1/impl/BiomeNMSImpl.java | 12 +++--- .../v26_1/impl/ImprovedOfflinePlayerImpl.java | 14 +++---- .../nms/v26_1/impl/ProfileEditorImpl.java | 14 +++---- .../denizen/nms/v26_1/impl/SidebarImpl.java | 6 +-- .../nms/v26_1/impl/blocks/BlockLightImpl.java | 8 ++-- .../impl/entities/CraftFakeArrowImpl.java | 6 +-- .../impl/entities/CraftFakePlayerImpl.java | 6 +-- .../entities/CraftItemProjectileImpl.java | 8 ++-- .../impl/entities/EntityFakeArrowImpl.java | 8 ++-- .../impl/entities/EntityFakePlayerImpl.java | 12 +++--- .../entities/EntityItemProjectileImpl.java | 4 +- .../impl/network/fakes/FakeChannelImpl.java | 2 +- .../network/fakes/FakeNetworkManagerImpl.java | 2 +- .../fakes/FakePlayerConnectionImpl.java | 2 +- .../handlers/AbstractListenerPlayInImpl.java | 6 +-- .../handlers/DenizenNetworkManagerImpl.java | 14 +++---- .../handlers/DenizenPacketListenerImpl.java | 8 ++-- .../network/handlers/FakeBlockHelper.java | 12 +++--- .../packet/ActionBarEventPacketHandlers.java | 8 ++-- .../handlers/packet/AttachPacketHandlers.java | 10 ++--- .../packet/BlockLightPacketHandlers.java | 6 +-- .../DenizenPacketHandlerPacketHandlers.java | 6 +-- .../packet/DisguisePacketHandlers.java | 8 ++-- .../packet/EntityMetadataPacketHandlers.java | 8 ++-- .../packet/FakeBlocksPacketHandlers.java | 8 ++-- .../packet/FakeEquipmentPacketHandlers.java | 6 +-- .../packet/FakePlayerPacketHandlers.java | 2 +- .../packet/HiddenEntitiesPacketHandlers.java | 4 +- .../packet/HideParticlesPacketHandlers.java | 6 +-- .../PlayerHearsSoundEventPacketHandlers.java | 4 +- .../TablistUpdateEventPacketHandlers.java | 8 ++-- .../PacketInResourcePackStatusImpl.java | 2 +- .../packets/PacketInSteerVehicleImpl.java | 2 +- .../network/packets/PacketOutChatImpl.java | 4 +- 50 files changed, 244 insertions(+), 244 deletions(-) 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 index 3e1fa23ae5..3bc942fd6a 100644 --- 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 @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21; +package com.denizenscript.denizen.nms.v26_1; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.NMSHandler; @@ -7,11 +7,11 @@ 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.nms.v26_1.helpers.*; +import com.denizenscript.denizen.nms.v26_1.impl.BiomeNMSImpl; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.SidebarImpl; +import com.denizenscript.denizen.nms.v26_1.impl.blocks.BlockLightImpl; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; @@ -67,19 +67,19 @@ 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.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.boss.CraftBossBar; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryCustom; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.legacy.FieldRename; +import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; +import org.bukkit.craftbukkit.util.*; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; 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 index 360d260ee4..61727ee6aa 100644 --- 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 @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21; +package com.denizenscript.denizen.nms.v26_1; public class ReflectionMappingsInfo { 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 index 1c9d91c52c..4db89cee5f 100644 --- 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 @@ -1,7 +1,7 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.nms.interfaces.AdvancementHelper; -import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v26_1.Handler; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.google.common.collect.ImmutableMap; import net.md_5.bungee.api.ChatColor; @@ -14,10 +14,10 @@ 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.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import java.util.*; 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 index b000df11bc..2c12daf4ba 100644 --- 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 @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.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.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftHorse; +import org.bukkit.craftbukkit.entity.CraftPolarBear; import org.bukkit.entity.EntityType; import org.bukkit.entity.Horse; import org.bukkit.entity.IronGolem; 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 index 8a8b9188c9..e6287b6a9e 100644 --- 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 @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.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.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -34,17 +34,17 @@ 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 org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.block.CraftSkull; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftLocation; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; 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 index 4157cf2074..b203e0a2b5 100644 --- 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 @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.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.denizen.nms.v26_1.impl.BiomeNMSImpl; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -20,8 +20,8 @@ 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 org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; 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 index 0df283220e..9905e036ef 100644 --- 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 @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.interfaces.CustomEntityHelper; @@ -6,11 +6,11 @@ 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.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.CraftFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityFakeArrowImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityItemProjectileImpl; import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -20,8 +20,8 @@ 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.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.scoreboard.Scoreboard; 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 index ba72802159..8325b63cca 100644 --- 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 @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.nms.interfaces.EnchantmentHelper; 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 index 01b43c07ca..8ce7da8054 100644 --- 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 @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizencore.objects.ArgumentHelper; 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 index b57de3441d..b08f82d4c8 100644 --- 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 @@ -1,11 +1,11 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.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.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.properties.entity.EntityState; import com.denizenscript.denizen.utilities.Utilities; @@ -69,14 +69,14 @@ 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.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.*; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.entity.*; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.EquipmentSlot; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java index a6cd25a56c..a3ae8177bd 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java @@ -1,7 +1,7 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.nms.interfaces.FishingHelper; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.resources.ResourceKey; @@ -18,10 +18,10 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftFishHook; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftFishHook; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.FishHook; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java index 5ab295a2d6..c69b375fb3 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java @@ -1,11 +1,11 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.interfaces.ItemHelper; 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.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.properties.item.ItemComponentsPatch; import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; @@ -72,16 +72,16 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.block.data.BlockData; -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.entity.CraftEntityType; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R7.inventory.*; -import org.bukkit.craftbukkit.v1_21_R7.map.CraftMapView; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftMagicNumbers; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.*; +import org.bukkit.craftbukkit.map.CraftMapView; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.*; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/NBTAdapter.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/NBTAdapter.java index 427e1a62b3..9072903cba 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/NBTAdapter.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/NBTAdapter.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizencore.utilities.ReflectionHelper; import net.kyori.adventure.nbt.*; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java index de8b320707..773a78bff2 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java @@ -1,11 +1,11 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.interfaces.PacketHelper; -import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; -import com.denizenscript.denizen.nms.v1_21.impl.SidebarImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.SidebarImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; import com.denizenscript.denizen.utilities.FormattedTextHelper; @@ -49,14 +49,14 @@ import org.bukkit.block.Sign; import org.bukkit.block.sign.Side; import org.bukkit.block.sign.SignSide; -import org.bukkit.craftbukkit.v1_21_R7.CraftServer; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; -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.map.CraftMapCanvas; -import org.bukkit.craftbukkit.v1_21_R7.map.CraftMapView; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.map.CraftMapCanvas; +import org.bukkit.craftbukkit.map.CraftMapView; +import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java index 6f73e27c02..e1b527bddc 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java @@ -1,18 +1,18 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.ImprovedOfflinePlayer; import com.denizenscript.denizen.nms.enums.CustomEntityType; import com.denizenscript.denizen.nms.interfaces.PlayerHelper; -import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; -import com.denizenscript.denizen.nms.v1_21.impl.ImprovedOfflinePlayerImpl; -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.EntityItemProjectileImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.AbstractListenerPlayInImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.ImprovedOfflinePlayerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.CraftFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityItemProjectileImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.AbstractListenerPlayInImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; @@ -61,14 +61,14 @@ import net.minecraft.world.phys.AABB; import org.bukkit.*; import org.bukkit.boss.BossBar; -import org.bukkit.craftbukkit.v1_21_R7.CraftServer; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.boss.CraftBossBar; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; -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.CraftMagicNumbers; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.boss.CraftBossBar; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java index 5f70b7347e..fbdeb27e21 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.helpers; +package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.nms.interfaces.WorldHelper; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; -import com.denizenscript.denizen.nms.v1_21.impl.BiomeNMSImpl; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.BiomeNMSImpl; import com.denizenscript.denizen.objects.BiomeTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.mojang.datafixers.util.Pair; @@ -16,7 +16,7 @@ import net.minecraft.world.level.storage.PrimaryLevelData; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.CraftWorld; public class WorldHelperImpl implements WorldHelper { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java index d360c4318a..e8875f27fa 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl; +package com.denizenscript.denizen.nms.v26_1.impl; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.BiomeNMS; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.core.BlockPos; @@ -25,10 +25,10 @@ import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.block.Block; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntityType; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.util.CraftLocation; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.EntityType; import java.lang.invoke.MethodHandle; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java index 7a33a97f69..17596e6dc2 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl; +package com.denizenscript.denizen.nms.v26_1.impl; import com.denizenscript.denizen.nms.abstracts.ImprovedOfflinePlayer; -import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.nms.v1_21.helpers.NBTAdapter; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.helpers.NBTAdapter; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; import net.kyori.adventure.nbt.CompoundBinaryTag; @@ -24,10 +24,10 @@ import net.minecraft.world.level.storage.ValueOutput; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R7.CraftServer; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventory; -import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventoryPlayer; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java index 196c039c05..f6aa5807cd 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java @@ -1,13 +1,13 @@ -package com.denizenscript.denizen.nms.v1_21.impl; +package com.denizenscript.denizen.nms.v26_1.impl; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.ProfileEditor; 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.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -25,8 +25,8 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.item.component.ResolvableProfile; 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.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerRespawnEvent; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/SidebarImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/SidebarImpl.java index e765aa1487..0e08145f36 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/SidebarImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/SidebarImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl; +package com.denizenscript.denizen.nms.v26_1.impl; import com.denizenscript.denizen.nms.abstracts.Sidebar; -import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.nms.v1_21.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.md_5.bungee.api.ChatColor; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java index 78c81da8e2..f5d7c4f40a 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl.blocks; +package com.denizenscript.denizen.nms.v26_1.impl.blocks; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.BlockLight; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -21,8 +21,8 @@ import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R7.CraftChunk; -import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlock; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.util.Vector; import java.lang.invoke.MethodHandle; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakeArrowImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakeArrowImpl.java index 4b45bfded0..160f12a001 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakeArrowImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakeArrowImpl.java @@ -1,9 +1,9 @@ -package com.denizenscript.denizen.nms.v1_21.impl.entities; +package com.denizenscript.denizen.nms.v26_1.impl.entities; import com.denizenscript.denizen.nms.interfaces.FakeArrow; import net.minecraft.world.entity.projectile.arrow.AbstractArrow; -import org.bukkit.craftbukkit.v1_21_R7.CraftServer; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftAbstractArrow; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftAbstractArrow; public class CraftFakeArrowImpl extends CraftAbstractArrow implements FakeArrow { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakePlayerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakePlayerImpl.java index 92a5ac8942..79f8121011 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakePlayerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftFakePlayerImpl.java @@ -1,11 +1,11 @@ -package com.denizenscript.denizen.nms.v1_21.impl.entities; +package com.denizenscript.denizen.nms.v26_1.impl.entities; import com.denizenscript.denizen.nms.interfaces.FakePlayer; import com.denizenscript.denizen.nms.NMSHandler; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.craftbukkit.v1_21_R7.CraftServer; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftItemProjectileImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftItemProjectileImpl.java index a2b8de7f84..da41f2da0c 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftItemProjectileImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/CraftItemProjectileImpl.java @@ -1,11 +1,11 @@ -package com.denizenscript.denizen.nms.v1_21.impl.entities; +package com.denizenscript.denizen.nms.v26_1.impl.entities; import com.denizenscript.denizen.nms.interfaces.ItemProjectile; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import org.bukkit.craftbukkit.v1_21_R7.CraftServer; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakeArrowImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakeArrowImpl.java index bad4b878de..01b789f238 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakeArrowImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakeArrowImpl.java @@ -1,14 +1,14 @@ -package com.denizenscript.denizen.nms.v1_21.impl.entities; +package com.denizenscript.denizen.nms.v26_1.impl.entities; -import com.denizenscript.denizen.nms.v1_21.Handler; +import com.denizenscript.denizen.nms.v26_1.Handler; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.world.entity.projectile.arrow.SpectralArrow; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R7.CraftServer; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.event.entity.CreatureSpawnEvent; public class EntityFakeArrowImpl extends SpectralArrow { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakePlayerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakePlayerImpl.java index 9c64a6636b..d81df1ffa7 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakePlayerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityFakePlayerImpl.java @@ -1,9 +1,9 @@ -package com.denizenscript.denizen.nms.v1_21.impl.entities; +package com.denizenscript.denizen.nms.v26_1.impl.entities; -import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.nms.v1_21.impl.network.fakes.FakeNetworkManagerImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.fakes.FakePlayerConnectionImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.network.fakes.FakeNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.fakes.FakePlayerConnectionImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; import net.minecraft.network.protocol.PacketFlow; @@ -14,7 +14,7 @@ import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.world.entity.player.Player; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R7.CraftServer; +import org.bukkit.craftbukkit.CraftServer; import org.bukkit.event.entity.CreatureSpawnEvent; public class EntityFakePlayerImpl extends ServerPlayer { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java index 21373b58c0..3c5b3ea259 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java @@ -1,6 +1,6 @@ -package com.denizenscript.denizen.nms.v1_21.impl.entities; +package com.denizenscript.denizen.nms.v26_1.impl.entities; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.google.common.base.Preconditions; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeChannelImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeChannelImpl.java index f3b1953ca3..e265656f2e 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeChannelImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeChannelImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.fakes; +package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; import io.netty.channel.*; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeNetworkManagerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeNetworkManagerImpl.java index ca0c9e0f7f..a94b4367aa 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeNetworkManagerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakeNetworkManagerImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.fakes; +package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; import net.minecraft.network.Connection; import net.minecraft.network.protocol.PacketFlow; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakePlayerConnectionImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakePlayerConnectionImpl.java index 4c4d11ac3c..373e74ada5 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakePlayerConnectionImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/fakes/FakePlayerConnectionImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.fakes; +package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; import net.minecraft.network.Connection; import net.minecraft.network.protocol.Packet; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java index d67b131ff5..9432cae053 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; import com.denizenscript.denizen.events.player.PlayerSendPacketScriptEvent; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; @@ -31,7 +31,7 @@ import net.minecraft.world.entity.Relative; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.event.player.PlayerTeleportEvent; import java.lang.invoke.MethodHandle; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java index d725381ce0..6eb4dd9943 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; import com.denizenscript.denizen.events.player.PlayerReceivesPacketScriptEvent; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; -import com.denizenscript.denizen.nms.v1_21.impl.ProfileEditorImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet.*; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet.*; import com.denizenscript.denizen.utilities.Settings; import com.denizenscript.denizen.utilities.packets.NetworkInterceptCodeGen; import com.denizenscript.denizencore.utilities.CoreUtilities; @@ -32,9 +32,9 @@ import net.minecraft.util.debugchart.LocalSampleLogger; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import javax.annotation.Nullable; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenPacketListenerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenPacketListenerImpl.java index ed03d1ee48..224b0c76ba 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenPacketListenerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenPacketListenerImpl.java @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; import com.denizenscript.denizen.events.player.PlayerChangesSignScriptEvent; import com.denizenscript.denizen.events.player.PlayerSteersEntityScriptEvent; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v1_21.impl.network.packets.PacketInResourcePackStatusImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.packets.PacketInSteerVehicleImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketInResourcePackStatusImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketInSteerVehicleImpl; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; @@ -17,7 +17,7 @@ import net.minecraft.network.protocol.game.*; import net.minecraft.server.level.ServerPlayer; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.event.block.SignChangeEvent; public class DenizenPacketListenerImpl extends AbstractListenerPlayInImpl { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java index 13ca382b8b..ec922bd71e 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java @@ -1,7 +1,7 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; import com.denizenscript.denizen.Denizen; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -24,10 +24,10 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.Strategy; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockStates; -import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlockStates; +import org.bukkit.craftbukkit.block.data.CraftBlockData; import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/ActionBarEventPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/ActionBarEventPacketHandlers.java index 62ad8bd09b..c1f641f7b5 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/ActionBarEventPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/ActionBarEventPacketHandlers.java @@ -1,14 +1,14 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerReceivesActionbarScriptEvent; -import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.objects.core.ElementTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftChatMessage; public class ActionBarEventPacketHandlers { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java index 7219ee9108..69ad484907 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -13,8 +13,8 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PositionMoveRotation; import net.minecraft.world.phys.Vec3; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftVector; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftVector; import org.bukkit.util.Vector; import java.lang.reflect.Field; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/BlockLightPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/BlockLightPacketHandlers.java index 2e53cedab2..0a6f0257bc 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/BlockLightPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/BlockLightPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; import com.denizenscript.denizen.nms.abstracts.BlockLight; -import com.denizenscript.denizen.nms.v1_21.impl.blocks.BlockLightImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.blocks.BlockLightImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java index cd8abd286c..43f76611ee 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerReceivesMessageScriptEvent; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.packets.PacketOutChatImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketOutChatImpl; import com.denizenscript.denizen.utilities.packets.DenizenPacketHandler; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DisguisePacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DisguisePacketHandlers.java index a15b517fb5..12f13d8070 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DisguisePacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/DisguisePacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v1_21.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; @@ -14,7 +14,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PositionMoveRotation; import net.minecraft.world.level.Level; -import org.bukkit.craftbukkit.v1_21_R7.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/EntityMetadataPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/EntityMetadataPacketHandlers.java index ee538c2b83..f0b1cf4b7f 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/EntityMetadataPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/EntityMetadataPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.nms.v1_21.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.GlowCommand; import com.denizenscript.denizen.scripts.commands.entity.InvisibleCommand; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 4938114cac..17f6afd713 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.FakeBlockHelper; +import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.FakeBlockHelper; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java index 97d21d284a..9471624704 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java @@ -1,6 +1,6 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; import com.mojang.datafixers.util.Pair; @@ -11,7 +11,7 @@ import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; -import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import java.util.ArrayList; import java.util.List; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakePlayerPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakePlayerPacketHandlers.java index dff04ee9a5..ac5c76ae4f 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakePlayerPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakePlayerPacketHandlers.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; /* import com.denizenscript.denizen.nms.NMSHandler; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java index cac24bc7d8..86f1d921c5 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java @@ -1,6 +1,6 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.entity.HideEntitiesHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.network.protocol.Packet; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HideParticlesPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HideParticlesPacketHandlers.java index 09328473fc..70c64da27b 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HideParticlesPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HideParticlesPacketHandlers.java @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.packets.HideParticles; import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; import org.bukkit.Particle; -import org.bukkit.craftbukkit.v1_21_R7.CraftParticle; +import org.bukkit.craftbukkit.CraftParticle; import java.util.Set; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java index 4dad338a67..f26a97ad7e 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java @@ -1,7 +1,7 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerHearsSoundScriptEvent; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java index 21e5d5ba0c..cd436d5d26 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java @@ -1,9 +1,9 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerReceivesTablistUpdateScriptEvent; -import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.nms.v1_21.impl.ProfileEditorImpl; -import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.Debug; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInResourcePackStatusImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInResourcePackStatusImpl.java index 9069658423..64a80bad64 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInResourcePackStatusImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInResourcePackStatusImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.packets; +package com.denizenscript.denizen.nms.v26_1.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketInResourcePackStatus; import net.minecraft.network.protocol.common.ServerboundResourcePackPacket; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInSteerVehicleImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInSteerVehicleImpl.java index ce2c293c29..fb041134f3 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInSteerVehicleImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketInSteerVehicleImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.packets; +package com.denizenscript.denizen.nms.v26_1.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketInSteerVehicle; import net.minecraft.network.protocol.game.ServerboundPlayerInputPacket; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketOutChatImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketOutChatImpl.java index 13d5d02757..ed5445a201 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketOutChatImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/packets/PacketOutChatImpl.java @@ -1,11 +1,11 @@ -package com.denizenscript.denizen.nms.v1_21.impl.network.packets; +package com.denizenscript.denizen.nms.v26_1.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; import com.denizenscript.denizen.utilities.FormattedTextHelper; import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftChatMessage; public class PacketOutChatImpl extends PacketOutChat { From 909187e382890b0b73176a4ed422ed99aadfb817 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 27 Mar 2026 01:39:05 +0000 Subject: [PATCH 083/169] 26.1 part 4: handle obfuscation removal --- .../nms/v26_1/ReflectionMappingsInfo.java | 130 ------------------ .../nms/v26_1/helpers/BlockHelperImpl.java | 5 +- .../v26_1/helpers/EnchantmentHelperImpl.java | 4 +- .../nms/v26_1/helpers/EntityHelperImpl.java | 15 +- .../nms/v26_1/helpers/FishingHelperImpl.java | 7 +- .../nms/v26_1/helpers/ItemHelperImpl.java | 5 +- .../nms/v26_1/helpers/PacketHelperImpl.java | 13 +- .../nms/v26_1/helpers/PlayerHelperImpl.java | 15 +- .../nms/v26_1/helpers/WorldHelperImpl.java | 9 +- .../denizen/nms/v26_1/impl/BiomeNMSImpl.java | 9 +- .../nms/v26_1/impl/ProfileEditorImpl.java | 5 +- .../nms/v26_1/impl/blocks/BlockLightImpl.java | 5 +- .../entities/EntityItemProjectileImpl.java | 3 +- .../handlers/AbstractListenerPlayInImpl.java | 9 +- .../handlers/DenizenNetworkManagerImpl.java | 9 +- .../network/handlers/FakeBlockHelper.java | 5 +- .../handlers/packet/AttachPacketHandlers.java | 13 +- .../packet/FakeBlocksPacketHandlers.java | 7 +- 18 files changed, 61 insertions(+), 207 deletions(-) delete mode 100644 v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/ReflectionMappingsInfo.java 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 deleted file mode 100644 index 61727ee6aa..0000000000 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/ReflectionMappingsInfo.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.denizenscript.denizen.nms.v26_1; - -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/BlockHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/BlockHelperImpl.java index e6287b6a9e..3916ff35b8 100644 --- 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 @@ -3,7 +3,6 @@ import com.denizenscript.denizen.nms.interfaces.BlockHelper; import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizencore.objects.Mechanism; @@ -131,7 +130,7 @@ public boolean setBlockResistance(Material material, float resistance) { if (block == null) { return false; } - ReflectionHelper.setFieldValue(net.minecraft.world.level.block.state.BlockBehaviour.class, ReflectionMappingsInfo.BlockBehaviour_explosionResistance, block, resistance); + ReflectionHelper.setFieldValue(net.minecraft.world.level.block.state.BlockBehaviour.class, "explosionResistance", block, resistance); return true; } @@ -141,7 +140,7 @@ public float getBlockResistance(Material material) { if (block == null) { return 0; } - return ReflectionHelper.getFieldValue(net.minecraft.world.level.block.state.BlockBehaviour.class, ReflectionMappingsInfo.BlockBehaviour_explosionResistance, block); + return ReflectionHelper.getFieldValue(net.minecraft.world.level.block.state.BlockBehaviour.class, "explosionResistance", block); } public static final MethodHandle MATERIAL_PUSH_REACTION_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(BlockBehaviour.BlockStateBase.class, PushReaction.class); 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 index 8325b63cca..ae556afc23 100644 --- 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 @@ -5,8 +5,8 @@ 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); + public static final Field REGISTRY_FROZEN = ReflectionHelper.getFields(MappedRegistry.class).get("frozen", boolean.class); + public static final Field REGISTRY_INTRUSIVE_HOLDERS = ReflectionHelper.getFields(MappedRegistry.class).get("unregisteredIntrusiveHolders", Map.class); @Override public org.bukkit.enchantments.Enchantment registerFakeEnchantment(EnchantmentScriptContainer.EnchantmentReference script) { 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 index b08f82d4c8..410be78441 100644 --- 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 @@ -4,7 +4,6 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.interfaces.EntityHelper; import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.properties.entity.EntityState; @@ -92,9 +91,9 @@ 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 MethodHandle ENTITY_ONGROUND_SETTER = ReflectionHelper.getFinalSetter(net.minecraft.world.entity.Entity.class, "onGround", boolean.class); - public static final EntityDataAccessor ENDERMAN_DATA_ACCESSOR_SCREAMING = ReflectionHelper.getFieldValue(EnderMan.class, ReflectionMappingsInfo.EnderMan_DATA_CREEPY, null); + public static final EntityDataAccessor ENDERMAN_DATA_ACCESSOR_SCREAMING = ReflectionHelper.getFieldValue(EnderMan.class, "DATA_CREEPY", null); @Override public void setInvisible(Entity entity, boolean invisible) { @@ -152,8 +151,8 @@ public double getDamageTo(LivingEntity attacker, Entity target) { 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); + public static final MethodHandle LIVINGENTITY_AUTOSPINATTACK_SETTER = ReflectionHelper.getFinalSetter(net.minecraft.world.entity.LivingEntity.class, "autoSpinAttackTicks"); + public static final MethodHandle LIVINGENTITY_SETLIVINGENTITYFLAG = ReflectionHelper.getMethodHandle(net.minecraft.world.entity.LivingEntity.class, "setLivingEntityFlag", int.class, boolean.class); @Override public void setRiptide(Entity entity, boolean state) { @@ -548,7 +547,7 @@ 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); + public static final Field EXPERIENCE_ORB_AGE = ReflectionHelper.getFields(net.minecraft.world.entity.ExperienceOrb.class).get("age", int.class); @Override public void setTicksLived(Entity entity, int ticks) { @@ -687,7 +686,7 @@ public EntityTag getMobSpawnerDisplayEntity(CreatureSpawner spawner) { 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); + public static final Field ZOMBIE_INWATERTIME = ReflectionHelper.getFields(net.minecraft.world.entity.monster.zombie.Zombie.class).get("inWaterTime", int.class); @Override public int getInWaterTime(Zombie zombie) { @@ -767,7 +766,7 @@ public void setUUID(Entity entity, UUID id) { } } - public static final Field SynchedEntityData_itemsById = ReflectionHelper.getFields(SynchedEntityData.class).get(ReflectionMappingsInfo.SynchedEntityData_itemsById); + public static final Field SynchedEntityData_itemsById = ReflectionHelper.getFields(SynchedEntityData.class).get("itemsById"); public static Int2ObjectMap> getDataItems(Entity entity) { try { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java index a3ae8177bd..5f52ffec86 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java @@ -1,7 +1,6 @@ package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.nms.interfaces.FishingHelper; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.resources.ResourceKey; @@ -97,9 +96,9 @@ private ItemStack catchRandomFish(FishingHook fishHook) { return getRandomReward(fishHook, BuiltInLootTables.FISHING_FISH); } - public static final Field FISHING_HOOK_NIBBLE = ReflectionHelper.getFields(FishingHook.class).get(ReflectionMappingsInfo.FishingHook_nibble, int.class); - public static final Field FISHING_HOOK_LURE_TIME = ReflectionHelper.getFields(FishingHook.class).get(ReflectionMappingsInfo.FishingHook_timeUntilLured, int.class); - public static final Field FISHING_HOOK_HOOK_TIME = ReflectionHelper.getFields(FishingHook.class).get(ReflectionMappingsInfo.FishingHook_timeUntilHooked, int.class); + public static final Field FISHING_HOOK_NIBBLE = ReflectionHelper.getFields(FishingHook.class).get("nibble", int.class); + public static final Field FISHING_HOOK_LURE_TIME = ReflectionHelper.getFields(FishingHook.class).get("timeUntilLured", int.class); + public static final Field FISHING_HOOK_HOOK_TIME = ReflectionHelper.getFields(FishingHook.class).get("timeUntilHooked", int.class); @Override public FishHook getHookFrom(Player player) { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java index c69b375fb3..0cf25fdf8e 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java @@ -4,7 +4,6 @@ import com.denizenscript.denizen.nms.interfaces.ItemHelper; import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.properties.item.ItemComponentsPatch; @@ -102,7 +101,7 @@ public static net.minecraft.world.item.crafting.RecipeHolder getNMSRecipe(Nam return ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager().byKey(nmsKey).orElse(null); } - public static final Field Item_components = ReflectionHelper.getFields(Item.class).get(ReflectionMappingsInfo.Item_components, DataComponentMap.class); + public static final Field Item_components = ReflectionHelper.getFields(Item.class).get("components", DataComponentMap.class); public static final Field RecipeManager_featureFlagSet = ReflectionHelper.getFields(RecipeManager.class).getFirstOfType(FeatureFlagSet.class); @@ -484,7 +483,7 @@ public ItemStack setRawComponentsPatch(ItemStack item, MapTag rawComponentsMap, return CraftItemStack.asBukkitCopy(nmsItemStack); } - public static final Field AdventureModePredicate_predicates = ReflectionHelper.getFields(AdventureModePredicate.class).get(ReflectionMappingsInfo.AdventureModePredicate_predicates); + public static final Field AdventureModePredicate_predicates = ReflectionHelper.getFields(AdventureModePredicate.class).get("predicates"); @Override public List getCanPlaceOn(ItemStack item) { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java index 773a78bff2..3f3d84a134 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java @@ -3,7 +3,6 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.interfaces.PacketHelper; import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.SidebarImpl; import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.LocationTag; @@ -32,9 +31,9 @@ import net.minecraft.world.entity.Relative; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.monster.spider.CaveSpider; import net.minecraft.world.entity.monster.Creeper; import net.minecraft.world.entity.monster.EnderMan; +import net.minecraft.world.entity.monster.spider.CaveSpider; import net.minecraft.world.entity.monster.spider.Spider; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.block.Block; @@ -71,19 +70,19 @@ public class PacketHelperImpl implements PacketHelper { - public static final EntityDataAccessor PLAYER_DATA_ACCESSOR_ABSORPTION = ReflectionHelper.getFieldValue(net.minecraft.world.entity.player.Player.class, ReflectionMappingsInfo.Player_DATA_PLAYER_ABSORPTION_ID, null); + public static final EntityDataAccessor PLAYER_DATA_ACCESSOR_ABSORPTION = ReflectionHelper.getFieldValue(net.minecraft.world.entity.player.Player.class, "DATA_PLAYER_ABSORPTION_ID", null); - public static final EntityDataAccessor ENTITY_DATA_ACCESSOR_FLAGS = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, ReflectionMappingsInfo.Entity_DATA_SHARED_FLAGS_ID, null); + public static final EntityDataAccessor ENTITY_DATA_ACCESSOR_FLAGS = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, "DATA_SHARED_FLAGS_ID", null); - public static final MethodHandle ABILITIES_PACKET_FOV_SETTER = ReflectionHelper.getFinalSetter(ClientboundPlayerAbilitiesPacket.class, ReflectionMappingsInfo.ClientboundPlayerAbilitiesPacket_walkingSpeed); + public static final MethodHandle ABILITIES_PACKET_FOV_SETTER = ReflectionHelper.getFinalSetter(ClientboundPlayerAbilitiesPacket.class, "walkingSpeed"); public static final Field ENTITY_TRACKER_ENTRY_GETTER = ReflectionHelper.getFields(ChunkMap.TrackedEntity.class).getFirstOfType(ServerEntity.class); public static final MethodHandle CANVAS_GET_BUFFER = ReflectionHelper.getMethodHandle(CraftMapCanvas.class, "getBuffer"); public static final Field MAPVIEW_WORLDMAP = ReflectionHelper.getFields(CraftMapView.class).get("worldMap"); - public static final EntityDataAccessor> ENTITY_DATA_ACCESSOR_CUSTOM_NAME = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, ReflectionMappingsInfo.Entity_DATA_CUSTOM_NAME, null); - public static final EntityDataAccessor ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, ReflectionMappingsInfo.Entity_DATA_CUSTOM_NAME_VISIBLE, null); + public static final EntityDataAccessor> ENTITY_DATA_ACCESSOR_CUSTOM_NAME = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, "DATA_CUSTOM_NAME", null); + public static final EntityDataAccessor ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, "DATA_CUSTOM_NAME_VISIBLE", null); @Override public void setFakeAbsorption(Player player, float value) { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java index e1b527bddc..0760d3bbee 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PlayerHelperImpl.java @@ -6,7 +6,6 @@ import com.denizenscript.denizen.nms.enums.CustomEntityType; import com.denizenscript.denizen.nms.interfaces.PlayerHelper; import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.ImprovedOfflinePlayerImpl; import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; import com.denizenscript.denizen.nms.v26_1.impl.entities.CraftFakePlayerImpl; @@ -81,13 +80,13 @@ public class PlayerHelperImpl extends PlayerHelper { - public static final Field ATTACK_COOLDOWN_TICKS = ReflectionHelper.getFields(LivingEntity.class).get(ReflectionMappingsInfo.LivingEntity_attackStrengthTicker, int.class); + public static final Field ATTACK_COOLDOWN_TICKS = ReflectionHelper.getFields(LivingEntity.class).get("attackStrengthTicker", int.class); - public static final Field FLY_TICKS = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_aboveGroundTickCount, int.class); - public static final Field VEHICLE_FLY_TICKS = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_aboveGroundVehicleTickCount, int.class); - public static final Field PASSENGERS_PACKET_PASSENGERS = ReflectionHelper.getFields(ClientboundSetPassengersPacket.class).get(ReflectionMappingsInfo.ClientboundSetPassengersPacket_passengers, int[].class); - public static final MethodHandle PLAYER_RESPAWNCONFIG_SETTER = ReflectionHelper.getFinalSetter(ServerPlayer.class, ReflectionMappingsInfo.ServerPlayer_respawnConfig, ServerPlayer.RespawnConfig.class); - public static final MethodHandle SERVER_RECIPE_BOOK_ADD_HIGHLIGHT = ReflectionHelper.getMethodHandle(ServerRecipeBook.class, ReflectionMappingsInfo.ServerRecipeBook_addHighlight_method, ResourceKey.class); + public static final Field FLY_TICKS = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("aboveGroundTickCount", int.class); + public static final Field VEHICLE_FLY_TICKS = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("aboveGroundVehicleTickCount", int.class); + public static final Field PASSENGERS_PACKET_PASSENGERS = ReflectionHelper.getFields(ClientboundSetPassengersPacket.class).get("passengers", int[].class); + public static final MethodHandle PLAYER_RESPAWNCONFIG_SETTER = ReflectionHelper.getFinalSetter(ServerPlayer.class, "respawnConfig", ServerPlayer.RespawnConfig.class); + public static final MethodHandle SERVER_RECIPE_BOOK_ADD_HIGHLIGHT = ReflectionHelper.getMethodHandle(ServerRecipeBook.class, "addHighlight", ResourceKey.class); @Override public void stopSound(Player player, NamespacedKey sound, SoundCategory category) { @@ -465,7 +464,7 @@ public void sendPlayerInfoRemovePacket(Player player, UUID id) { @Override public void sendClimbableMaterials(Player player, List materials) { Map>, TagNetworkSerialization.NetworkPayload> packetInput = TagNetworkSerialization.serializeTagsToNetwork(((CraftServer) Bukkit.getServer()).getServer().registries()); - Map tags = ReflectionHelper.getFieldValue(TagNetworkSerialization.NetworkPayload.class, ReflectionMappingsInfo.TagNetworkSerializationNetworkPayload_tags, packetInput.get(BuiltInRegistries.BLOCK.key())); + Map tags = ReflectionHelper.getFieldValue(TagNetworkSerialization.NetworkPayload.class, "tags", packetInput.get(BuiltInRegistries.BLOCK.key())); IntList climbableBlocks = tags.get(BlockTags.CLIMBABLE.location()); climbableBlocks.clear(); for (Material material : materials) { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java index fbdeb27e21..92a36c9877 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java @@ -1,7 +1,6 @@ package com.denizenscript.denizen.nms.v26_1.helpers; import com.denizenscript.denizen.nms.interfaces.WorldHelper; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.BiomeNMSImpl; import com.denizenscript.denizen.objects.BiomeTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -28,7 +27,7 @@ public boolean isStatic(World world) { @Override public void setStatic(World world, boolean isStatic) { ServerLevel worldServer = ((CraftWorld) world).getHandle(); - ReflectionHelper.setFieldValue(net.minecraft.world.level.Level.class, ReflectionMappingsInfo.Level_isClientSide, worldServer, isStatic); + ReflectionHelper.setFieldValue(net.minecraft.world.level.Level.class, "isClientSide", worldServer, isStatic); } @Override @@ -50,14 +49,14 @@ public Location getNearestBiomeLocation(Location start, BiomeTag biome) { @Override public boolean areEnoughSleeping(World world, int percentage) { - SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, ReflectionMappingsInfo.ServerLevel_sleepStatus, ((CraftWorld) world).getHandle()); + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, "sleepStatus", ((CraftWorld) world).getHandle()); return status.areEnoughSleeping(percentage); } @Override public boolean areEnoughDeepSleeping(World world, int percentage) { ServerLevel level = ((CraftWorld) world).getHandle(); - SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, ReflectionMappingsInfo.ServerLevel_sleepStatus, level); + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, "sleepStatus", level); return status.areEnoughDeepSleeping(percentage, level.players()); } @@ -90,7 +89,7 @@ public void setGameTime(World world, long time) { @Override public void wakeUpAllPlayers(World world) { ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); - SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, ReflectionMappingsInfo.ServerLevel_sleepStatus, nmsWorld); + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, "sleepStatus", nmsWorld); status.removeAllSleepers(); nmsWorld.getPlayers(LivingEntity::isSleeping).forEach((player) -> player.stopSleepInBed(false, false)); } diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java index e8875f27fa..d99c80dd4b 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java @@ -2,7 +2,6 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.BiomeNMS; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.core.BlockPos; @@ -40,8 +39,8 @@ public class BiomeNMSImpl extends BiomeNMS { public static final MethodHandle BIOME_CLIMATESETTINGS_CONSTRUCTOR = ReflectionHelper.getConstructor(Biome.ClimateSettings.class, boolean.class, float.class, Biome.TemperatureModifier.class, float.class); - public static final MethodHandle MAPPED_REGISTRY_REGISTRATION_INFOS = ReflectionHelper.getFields(MappedRegistry.class).getGetter(ReflectionMappingsInfo.MappedRegistry_registrationInfos); - public static final MethodHandle BIOME_ATTRIBUTES_SETTER = ReflectionHelper.getFields(Biome.class).getSetter(ReflectionMappingsInfo.Biome_attributes); + public static final MethodHandle MAPPED_REGISTRY_REGISTRATION_INFOS = ReflectionHelper.getFields(MappedRegistry.class).getGetter("registrationInfos"); + public static final MethodHandle BIOME_ATTRIBUTES_SETTER = ReflectionHelper.getFields(Biome.class).getSetter("attributes"); public Holder.Reference biomeHolder; public ServerLevel world; @@ -126,7 +125,7 @@ public int getFoliageColor() { public void setClimate(boolean hasPrecipitation, float temperature, Biome.TemperatureModifier temperatureModifier, float downfall) { try { Object newClimate = BIOME_CLIMATESETTINGS_CONSTRUCTOR.invoke(hasPrecipitation, temperature, temperatureModifier, downfall); - ReflectionHelper.setFieldValue(Biome.class, ReflectionMappingsInfo.Biome_climateSettings, biomeHolder.value(), newClimate); + ReflectionHelper.setFieldValue(Biome.class, "climateSettings", biomeHolder.value(), newClimate); setNetworkedRegistrationInfo(); } catch (Throwable ex) { @@ -155,7 +154,7 @@ public void setFoliageColor(int color) { BiomeSpecialEffects nmsNewEffects = new BiomeSpecialEffects( nmsCurrEffects.waterColor(), Optional.of(color), nmsCurrEffects.dryFoliageColorOverride(), nmsCurrEffects.grassColorOverride(), nmsCurrEffects.grassColorModifier() ); - ReflectionHelper.setFieldValue(Biome.class, ReflectionMappingsInfo.Biome_specialEffects, biomeHolder.value(), nmsNewEffects); + ReflectionHelper.setFieldValue(Biome.class, "specialEffects", biomeHolder.value(), nmsNewEffects); setNetworkedRegistrationInfo(); } diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java index f6aa5807cd..d620ff984f 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ProfileEditorImpl.java @@ -5,7 +5,6 @@ import com.denizenscript.denizen.nms.abstracts.ProfileEditor; import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; @@ -140,10 +139,10 @@ public static GameProfile getGameProfile(PlayerProfile playerProfile) { return createGameProfile(playerProfile.getUniqueId(), playerProfile.getName(), playerProfile.getTexture(), playerProfile.getTextureSignature()); } - public static final MethodHandle RESOLVABLEPROFILE_UNPACK = ReflectionHelper.getMethodHandle(ResolvableProfile.class, ReflectionMappingsInfo.ResolvableProfile_unpack_method); + public static final MethodHandle RESOLVABLEPROFILE_UNPACK = ReflectionHelper.getMethodHandle(ResolvableProfile.class, "unpack"); public static final MethodHandle RESOLVABLEPROFILE_PARTIAL_ID = ReflectionHelper .getFields(ReflectionHelper.getClassOrThrow("net.minecraft.world.item.component.ResolvableProfile$Partial")) - .getGetter(ReflectionMappingsInfo.ResolvableProfilePartial_id, Optional.class); + .getGetter("id", Optional.class); public static UUID getUUID(ResolvableProfile resolvableProfile) { try { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java index f5d7c4f40a..6bae8317f4 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java @@ -2,7 +2,6 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.BlockLight; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -39,7 +38,7 @@ public class BlockLightImpl extends BlockLight { static { Object preObj = null; try { - preObj = ReflectionHelper.getFields(LIGHTENGINETHREADED_TASKTYPE).get(ReflectionMappingsInfo.ThreadedLevelLightEngineTaskType_PRE_UPDATE).get(null); + preObj = ReflectionHelper.getFields(LIGHTENGINETHREADED_TASKTYPE).get("PRE_UPDATE").get(null); } catch (Throwable ex) { ex.printStackTrace(); @@ -47,7 +46,7 @@ public class BlockLightImpl extends BlockLight { LIGHTENGINETHREADED_TASKTYPE_PRE = preObj; } - public static final MethodHandle LIGHTENGINETHREADED_QUEUERUNNABLE = ReflectionHelper.getMethodHandle(ThreadedLevelLightEngine.class, ReflectionMappingsInfo.ThreadedLevelLightEngine_addTask_method, + public static final MethodHandle LIGHTENGINETHREADED_QUEUERUNNABLE = ReflectionHelper.getMethodHandle(ThreadedLevelLightEngine.class, "addTask", int.class, int.class, LIGHTENGINETHREADED_TASKTYPE, Runnable.class); public static void enqueueRunnable(LevelChunk chunk, Runnable runnable) { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java index 3c5b3ea259..60539e4a85 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java @@ -1,6 +1,5 @@ package com.denizenscript.denizen.nms.v26_1.impl.entities; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.google.common.base.Preconditions; @@ -28,7 +27,7 @@ public class EntityItemProjectileImpl extends ThrowableProjectile { static { EntityDataAccessor watcher = null; try { - watcher = (EntityDataAccessor) ReflectionHelper.getFields(ItemEntity.class).get(ReflectionMappingsInfo.ItemEntity_DATA_ITEM).get(null); + watcher = (EntityDataAccessor) ReflectionHelper.getFields(ItemEntity.class).get("DATA_ITEM").get(null); } catch (Throwable ex) { Debug.echoError(ex); diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java index 9432cae053..6d5d5a2b48 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/AbstractListenerPlayInImpl.java @@ -2,7 +2,6 @@ import com.denizenscript.denizen.events.player.PlayerSendPacketScriptEvent; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; @@ -41,9 +40,9 @@ public class AbstractListenerPlayInImpl extends ServerGamePacketListenerImpl { - public static final Field ServerGamePacketListenerImpl_chunkSender = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_chunkSender); + public static final Field ServerGamePacketListenerImpl_chunkSender = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("chunkSender"); - public static final MethodHandle SERVER_COMMON_PACKET_LISTENER_IMPL_CREATE_COOKIE = ReflectionHelper.getMethodHandle(ServerCommonPacketListenerImpl.class, ReflectionMappingsInfo.ServerCommonPacketListenerImpl_createCookie_method, ClientInformation.class); + public static final MethodHandle SERVER_COMMON_PACKET_LISTENER_IMPL_CREATE_COOKIE = ReflectionHelper.getMethodHandle(ServerCommonPacketListenerImpl.class, "createCookie", ClientInformation.class); public static CommonListenerCookie createCookie(ServerPlayer nmsPlayer) { try { @@ -179,8 +178,8 @@ public void send(Packet packet, ChannelFutureListener channelfuturelistener) oldListener.send(packet, channelfuturelistener); } - public static Field AWAITING_POS_FIELD = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_awaitingPositionFromClient, Vec3.class); - public static Field AWAITING_TELEPORT_FIELD = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get(ReflectionMappingsInfo.ServerGamePacketListenerImpl_awaitingTeleport, int.class); + public static Field AWAITING_POS_FIELD = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("awaitingPositionFromClient", Vec3.class); + public static Field AWAITING_TELEPORT_FIELD = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("awaitingTeleport", int.class); public void debugPacketOutput(Packet packet) { try { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java index 6eb4dd9943..23e1da3234 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -2,7 +2,6 @@ import com.denizenscript.denizen.events.player.PlayerReceivesPacketScriptEvent; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet.*; import com.denizenscript.denizen.utilities.Settings; @@ -528,10 +527,10 @@ public void setBandwidthLogger(LocalSampleLogger localsamplelogger) { //// Reflection Methods/Fields /////////// - private static final Field protocolDirectionField = ReflectionHelper.getFields(Connection.class).get(ReflectionMappingsInfo.Connection_receiving, PacketFlow.class); - public static final Field Connection_packetListener = ReflectionHelper.getFields(Connection.class).get(ReflectionMappingsInfo.Connection_packetListener, PacketListener.class); - private static final Field ServerGamePacketListener_ConnectionField = ReflectionHelper.getFields(ServerCommonPacketListenerImpl.class).get(ReflectionMappingsInfo.ServerCommonPacketListenerImpl_connection); - private static final MethodHandle ServerGamePacketListener_ConnectionSetter = ReflectionHelper.getFinalSetter(ServerCommonPacketListenerImpl.class, ReflectionMappingsInfo.ServerCommonPacketListenerImpl_connection); + private static final Field protocolDirectionField = ReflectionHelper.getFields(Connection.class).get("receiving", PacketFlow.class); + public static final Field Connection_packetListener = ReflectionHelper.getFields(Connection.class).get("packetListener", PacketListener.class); + private static final Field ServerGamePacketListener_ConnectionField = ReflectionHelper.getFields(ServerCommonPacketListenerImpl.class).get("connection"); + private static final MethodHandle ServerGamePacketListener_ConnectionSetter = ReflectionHelper.getFinalSetter(ServerCommonPacketListenerImpl.class, "connection"); private static PacketFlow getProtocolDirection(Connection networkManager) { PacketFlow direction = null; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java index ec922bd71e..11a61644f0 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/FakeBlockHelper.java @@ -1,7 +1,6 @@ package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; import com.denizenscript.denizen.Denizen; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -42,8 +41,8 @@ public class FakeBlockHelper { public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; - public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); - public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); + public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get("packedXZ"); + public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get("y"); public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 2).findFirst().get(); diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java index 69ad484907..195004dedc 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java @@ -1,7 +1,6 @@ package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; import com.denizenscript.denizencore.utilities.CoreConfiguration; @@ -30,12 +29,12 @@ public static void registerHandlers() { DenizenNetworkManagerImpl.registerPacketHandler(ClientboundRemoveEntitiesPacket.class, AttachPacketHandlers::processAttachToForPacket); } - public static Field POS_X_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_xa, short.class); - public static Field POS_Y_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_ya, short.class); - public static Field POS_Z_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_za, short.class); - public static Field YAW_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_yRot, byte.class); - public static Field PITCH_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get(ReflectionMappingsInfo.ClientboundMoveEntityPacket_xRot, byte.class); - public static Field ENTITY_ID_PACKVELENT = ReflectionHelper.getFields(ClientboundSetEntityMotionPacket.class).get(ReflectionMappingsInfo.ClientboundSetEntityMotionPacket_id, int.class); + public static Field POS_X_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("xa", short.class); + public static Field POS_Y_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("ya", short.class); + public static Field POS_Z_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("za", short.class); + public static Field YAW_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("yRot", byte.class); + public static Field PITCH_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("xRot", byte.class); + public static Field ENTITY_ID_PACKVELENT = ReflectionHelper.getFields(ClientboundSetEntityMotionPacket.class).get("id", int.class); public static Vector VECTOR_ZERO = new Vector(0, 0, 0); diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 17f6afd713..0144bcfa08 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -1,6 +1,5 @@ package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v26_1.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.FakeBlockHelper; import com.denizenscript.denizen.objects.LocationTag; @@ -26,9 +25,9 @@ public static void registerHandlers() { DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); } - public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); - public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); - public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); + public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("sectionPos", SectionPos.class); + public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("positions", short[].class); + public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("states", BlockState[].class); public static Packet processShowFakeForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { if (FakeBlock.blocks.isEmpty()) { From a6b23a90c0eda1cff20e53c9a062d26e398a10f8 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 27 Mar 2026 03:33:43 +0000 Subject: [PATCH 084/169] 26.1 part 5: initial code updates --- .../denizenscript/denizen/nms/NMSVersion.java | 3 +- .../containers/core/ItemScriptHelper.java | 15 ++++++---- .../v26_1/helpers/AdvancementHelperImpl.java | 2 +- .../nms/v26_1/helpers/BlockHelperImpl.java | 4 +-- .../nms/v26_1/helpers/FishingHelperImpl.java | 4 +-- .../nms/v26_1/helpers/ItemHelperImpl.java | 28 +++++++++---------- .../nms/v26_1/helpers/WorldHelperImpl.java | 15 +++------- .../v26_1/impl/ImprovedOfflinePlayerImpl.java | 10 +++---- .../nms/v26_1/impl/blocks/BlockLightImpl.java | 4 +-- .../entities/EntityItemProjectileImpl.java | 8 ------ .../handlers/DenizenNetworkManagerImpl.java | 2 +- .../handlers/packet/AttachPacketHandlers.java | 2 +- .../packet/HiddenEntitiesPacketHandlers.java | 2 +- 13 files changed, 42 insertions(+), 57 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/nms/NMSVersion.java b/plugin/src/main/java/com/denizenscript/denizen/nms/NMSVersion.java index 8b75de4b81..3445604ad2 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/nms/NMSVersion.java +++ b/plugin/src/main/java/com/denizenscript/denizen/nms/NMSVersion.java @@ -7,7 +7,8 @@ public enum NMSVersion { v1_18("1.18"), v1_19("1.19"), v1_20("1.20"), - v1_21("1.21"); + v1_21("1.21"), + v26_1("26.1"); final String minecraftVersion; diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/ItemScriptHelper.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/ItemScriptHelper.java index 2a416d20b0..c57b5f43cf 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/ItemScriptHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/ItemScriptHelper.java @@ -60,14 +60,17 @@ public static void removeDenizenRecipes() { Iterator recipeIterator = Bukkit.recipeIterator(); ArrayList keys = new ArrayList<>(); while (recipeIterator.hasNext()) { - if (recipeIterator.next() instanceof Keyed keyed && keyed.getKey().getNamespace().equals("denizen")) { - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { - keys.add(keyed.getKey()); - } - else { - recipeIterator.remove(); + try { + if (recipeIterator.next() instanceof Keyed keyed && keyed.getKey().getNamespace().equals("denizen")) { + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + keys.add(keyed.getKey()); + } + else { + recipeIterator.remove(); + } } } + catch (AbstractMethodError ignored) {} // TODO: 26.1: work around Spigot bug } if (!keys.isEmpty()) { NMSHandler.itemHelper.removeRecipes(keys); 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 index 4db89cee5f..79157f437a 100644 --- 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 @@ -174,7 +174,7 @@ private static AdvancementHolder asNMSCopy(com.denizenscript.denizen.nms.util.Ad AdvancementHolder parent = advancement.parent != null ? getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.parent)) : null; - DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSCopy(advancement.icon), + DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSTemplate(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); 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 index 3916ff35b8..50d60b6c5b 100644 --- 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 @@ -184,11 +184,11 @@ public void doRandomTick(Location location) { 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); + nmsBlock.randomTick(nmsWorld, pos, nmsWorld.getRandom()); } FluidState fluid = nmsBlock.getFluidState(); if (fluid.isRandomlyTicking()) { - fluid.animateTick(nmsWorld, pos, nmsWorld.random); + fluid.animateTick(nmsWorld, pos, nmsWorld.getRandom()); } } diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java index 5f52ffec86..f6630b5a3c 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/FishingHelperImpl.java @@ -37,7 +37,7 @@ public org.bukkit.inventory.ItemStack getResult(FishHook fishHook, CatchType cat case DEFAULT -> { ServerLevel nmsWorld = ((CraftWorld) fishHook.getWorld()).getHandle(); ItemStack nmsFishingRod = nmsHook.getPlayerOwner().getMainHandItem(); - float f = nmsWorld.random.nextFloat(); + float f = nmsWorld.getRandom().nextFloat(); float i = EnchantmentHelper.getFishingTimeReduction(nmsWorld, nmsFishingRod, nmsHook.getPlayerOwner()); int j = EnchantmentHelper.getFishingLuckBonus(nmsWorld, nmsFishingRod, nmsHook.getPlayerOwner()); float f1 = 0.1F - i * 0.025F - (float) j * 0.01F; @@ -73,7 +73,7 @@ public ItemStack getRandomReward(FishingHook nmsHook, ResourceKey key .withParameter(LootContextParams.TOOL, new ItemStack(Items.FISHING_ROD)) .create(LootContextParamSets.FISHING); List nmsItems = nmsWorld.getServer().reloadableRegistries().getLootTable(key).getRandomItems(nmsLootParams); - return nmsItems.get(nmsWorld.random.nextInt(nmsItems.size())); + return nmsItems.get(nmsWorld.getRandom().nextInt(nmsItems.size())); } @Override diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java index 0cf25fdf8e..10306582e2 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java @@ -52,6 +52,7 @@ import net.minecraft.world.item.component.TypedEntityData; import net.minecraft.world.item.crafting.*; import net.minecraft.world.item.crafting.BlastingRecipe; +import net.minecraft.world.item.crafting.CraftingRecipe; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.ShapelessRecipe; import net.minecraft.world.item.crafting.SmithingTransformRecipe; @@ -96,21 +97,20 @@ public class ItemHelperImpl extends ItemHelper { + public static final Recipe.CommonInfo BASE_RECIPE_INFO = new Recipe.CommonInfo(true); + public static net.minecraft.world.item.crafting.RecipeHolder getNMSRecipe(NamespacedKey key) { ResourceKey> nmsKey = ResourceKey.create(Registries.RECIPE, CraftNamespacedKey.toMinecraft(key)); return ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager().byKey(nmsKey).orElse(null); } - public static final Field Item_components = ReflectionHelper.getFields(Item.class).get("components", DataComponentMap.class); - public static final Field RecipeManager_featureFlagSet = ReflectionHelper.getFields(RecipeManager.class).getFirstOfType(FeatureFlagSet.class); public void setMaxStackSize(Material material, int size) { try { ReflectionHelper.getFinalSetter(Material.class, "maxStack").invoke(material, size); - Item nmsItem = BuiltInRegistries.ITEM.getValue(CraftNamespacedKey.toMinecraft(material.getKey())); - DataComponentMap currentComponents = nmsItem.components(); - Item_components.set(nmsItem, DataComponentMap.composite(currentComponents, DataComponentMap.builder().set(DataComponents.MAX_STACK_SIZE, size).build())); + Holder.Reference nmsItemHolder = BuiltInRegistries.ITEM.get(CraftNamespacedKey.toMinecraft(material.getKey())).orElseThrow(); + nmsItemHolder.bindComponents(DataComponentMap.composite(nmsItemHolder.components(), DataComponentMap.builder().set(DataComponents.MAX_STACK_SIZE, size).build())); } catch (Throwable ex) { Debug.echoError(ex); @@ -211,18 +211,18 @@ public void registerFurnaceRecipe(String keyName, String group, ItemStack result ResourceKey> key = createRecipeKey(keyName); Ingredient itemRecipe = itemArrayToRecipe(ingredient, exact); AbstractCookingRecipe recipe; - CookingBookCategory categoryValue = category == null ? CookingBookCategory.MISC : CookingBookCategory.valueOf(CoreUtilities.toUpperCase(category)); + AbstractCookingRecipe.CookingBookInfo bookInfo = new AbstractCookingRecipe.CookingBookInfo(category == null ? CookingBookCategory.MISC : CookingBookCategory.valueOf(CoreUtilities.toUpperCase(category)), group); if (type.equalsIgnoreCase("smoker")) { - recipe = new SmokingRecipe(group, categoryValue, itemRecipe, CraftItemStack.asNMSCopy(result), exp, time); + recipe = new SmokingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, CraftItemStack.asNMSTemplate(result), exp, time); } else if (type.equalsIgnoreCase("blast")) { - recipe = new BlastingRecipe(group, categoryValue, itemRecipe, CraftItemStack.asNMSCopy(result), exp, time); + recipe = new BlastingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, CraftItemStack.asNMSTemplate(result), exp, time); } else if (type.equalsIgnoreCase("campfire")) { - recipe = new CampfireCookingRecipe(group, categoryValue, itemRecipe, CraftItemStack.asNMSCopy(result), exp, time); + recipe = new CampfireCookingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, CraftItemStack.asNMSTemplate(result), exp, time); } else { - recipe = new SmeltingRecipe(group, categoryValue, itemRecipe, CraftItemStack.asNMSCopy(result), exp, time); + recipe = new SmeltingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, CraftItemStack.asNMSTemplate(result), exp, time); } RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); @@ -232,7 +232,7 @@ else if (type.equalsIgnoreCase("campfire")) { public void registerStonecuttingRecipe(String keyName, String group, ItemStack result, ItemStack[] ingredient, boolean exact) { ResourceKey> key = createRecipeKey(keyName); Ingredient itemRecipe = itemArrayToRecipe(ingredient, exact); - StonecutterRecipe recipe = new StonecutterRecipe(group, itemRecipe, CraftItemStack.asNMSCopy(result)); + StonecutterRecipe recipe = new StonecutterRecipe(BASE_RECIPE_INFO, itemRecipe, CraftItemStack.asNMSTemplate(result)); RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); } @@ -243,8 +243,7 @@ public void registerSmithingRecipe(String keyName, ItemStack result, ItemStack[] Ingredient templateItemRecipe = templateItem.length == 0 ? null : itemArrayToRecipe(templateItem, templateExact); Ingredient baseItemRecipe = itemArrayToRecipe(baseItem, baseExact); Ingredient upgradeItemRecipe = itemArrayToRecipe(upgradeItem, upgradeExact); - net.minecraft.world.item.ItemStack nmsCopy = CraftItemStack.asNMSCopy(result); - SmithingTransformRecipe recipe = new SmithingTransformRecipe(Optional.ofNullable(templateItemRecipe), baseItemRecipe, Optional.of(upgradeItemRecipe), new TransmuteResult(nmsCopy.getItemHolder(), nmsCopy.getCount(), nmsCopy.getComponentsPatch())); + SmithingTransformRecipe recipe = new SmithingTransformRecipe(BASE_RECIPE_INFO, Optional.ofNullable(templateItemRecipe), baseItemRecipe, Optional.of(upgradeItemRecipe), CraftItemStack.asNMSTemplate(result)); RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); } @@ -257,8 +256,7 @@ public void registerShapelessRecipe(String keyName, String group, ItemStack resu for (int i = 0; i < ingredients.size(); i++) { ingredientList.add(itemArrayToRecipe(ingredients.get(i), exact[i])); } - // TODO: 1.19.3: Add support for choosing a CraftingBookCategory - ShapelessRecipe recipe = new ShapelessRecipe(group, categoryValue, CraftItemStack.asNMSCopy(result), NonNullList.of(null, ingredientList.toArray(new Ingredient[0]))); + ShapelessRecipe recipe = new ShapelessRecipe(BASE_RECIPE_INFO, new CraftingRecipe.CraftingBookInfo(categoryValue, group), CraftItemStack.asNMSTemplate(result), NonNullList.of(null, ingredientList.toArray(new Ingredient[0]))); RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); } diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java index 92a36c9877..ce84fabd38 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/WorldHelperImpl.java @@ -16,6 +16,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.event.world.TimeSkipEvent; public class WorldHelperImpl implements WorldHelper { @@ -77,7 +78,8 @@ public boolean isNight(World world) { @Override public void setDayTime(World world, long time) { - ((CraftWorld) world).getHandle().setDayTime(time); + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + nmsWorld.dimensionType().defaultClock().ifPresent((clock) -> nmsWorld.clockManager().setTotalTicks(clock, time, TimeSkipEvent.SkipReason.CUSTOM)); } @Override @@ -94,17 +96,8 @@ public void wakeUpAllPlayers(World world) { nmsWorld.getPlayers(LivingEntity::isSleeping).forEach((player) -> player.stopSleepInBed(false, false)); } - // net.minecraft.server.level.ServerLevel#resetWeatherCycle() @Override public void clearWeather(World world) { - PrimaryLevelData data = ((CraftWorld) world).getHandle().serverLevelData; - data.setRaining(false); - if (!data.isRaining()) { - data.setRainTime(0); - } - data.setThundering(false); - if (!data.isThundering()) { - data.setThunderTime(0); - } + ((CraftWorld) world).getHandle().resetWeatherCycle(); } } diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java index 17596e6dc2..dfed25aac1 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/ImprovedOfflinePlayerImpl.java @@ -145,12 +145,10 @@ public void setAttributes(AttributeMap attributes) { protected boolean loadPlayerData(UUID uuid) { try { this.player = uuid; - for (org.bukkit.World w : Bukkit.getWorlds()) { - this.file = new File(w.getWorldFolder(), "playerdata" + File.separator + this.player + ".dat"); - if (this.file.exists()) { - this.compound = NBTAdapter.toAPI(NbtIo.readCompressed(new FileInputStream(this.file), NbtAccounter.unlimitedHeap())); - return true; - } + this.file = new File(MinecraftServer.getServer().playerDataStorage.getPlayerDir(), this.player + ".dat"); + if (this.file.exists()) { + this.compound = NBTAdapter.toAPI(NbtIo.readCompressed(new FileInputStream(this.file), NbtAccounter.unlimitedHeap())); + return true; } } catch (Exception e) { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java index 6bae8317f4..e64e9483fb 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/blocks/BlockLightImpl.java @@ -54,7 +54,7 @@ public static void enqueueRunnable(LevelChunk chunk, Runnable runnable) { if (lightEngine instanceof ThreadedLevelLightEngine) { ChunkPos coord = chunk.getPos(); try { - LIGHTENGINETHREADED_QUEUERUNNABLE.invoke(lightEngine, coord.x, coord.z, LIGHTENGINETHREADED_TASKTYPE_PRE, runnable); + LIGHTENGINETHREADED_QUEUERUNNABLE.invoke(lightEngine, coord.x(), coord.z(), LIGHTENGINETHREADED_TASKTYPE_PRE, runnable); } catch (Throwable ex) { Debug.echoError(ex); @@ -241,7 +241,7 @@ public void sendNearbyChunkUpdates() { public static void sendNearbyChunkUpdates(LevelChunk chunk) { ChunkPos pos = chunk.getPos(); for (Vector vec : RELATIVE_CHUNKS) { - ChunkAccess other = chunk.getLevel().getChunk(pos.x + vec.getBlockX(), pos.z + vec.getBlockZ(), ChunkStatus.FULL, false); + ChunkAccess other = chunk.getLevel().getChunk(pos.x() + vec.getBlockX(), pos.z() + vec.getBlockZ(), ChunkStatus.FULL, false); if (other instanceof LevelChunk) { sendSingleChunkUpdate((LevelChunk) other); } diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java index 60539e4a85..e385265301 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/entities/EntityItemProjectileImpl.java @@ -69,14 +69,6 @@ protected void onHitBlock(BlockHitResult movingobjectpositionblock) { remove(RemovalReason.KILLED); } - @Override - public void onSyncedDataUpdated(EntityDataAccessor datawatcherobject) { - super.onSyncedDataUpdated(datawatcherobject); - if (ITEM.equals(datawatcherobject)) { - this.getItemStack().setEntityRepresentation(this); - } - } - @Override public boolean save(ValueOutput nmsValueOutput) { if (!this.getItemStack().isEmpty()) { diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java index 23e1da3234..4023acd8d5 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -271,7 +271,7 @@ public void debugOutputPacket(Packet packet) { } else if (packet instanceof ClientboundSetEntityMotionPacket) { ClientboundSetEntityMotionPacket velPacket = (ClientboundSetEntityMotionPacket) packet; - doPacketOutput("Packet: ClientboundSetEntityMotionPacket sent to " + player.getScoreboardName() + " for entity ID: " + velPacket.getId() + ": " + velPacket.getMovement()); + doPacketOutput("Packet: ClientboundSetEntityMotionPacket sent to " + player.getScoreboardName() + " for entity ID: " + velPacket.id() + ": " + velPacket.movement()); } else if (packet instanceof ClientboundAddEntityPacket) { ClientboundAddEntityPacket addEntityPacket = (ClientboundAddEntityPacket) packet; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java index 195004dedc..848ccb423b 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java @@ -267,7 +267,7 @@ else if (packet instanceof ClientboundRotateHeadPacket rotateHeadPacket) { return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; } else if (packet instanceof ClientboundSetEntityMotionPacket setEntityMotionPacket) { - int ider = setEntityMotionPacket.getId(); + int ider = setEntityMotionPacket.id(); Entity e = networkManager.player.level().getEntity(ider); if (e == null) { return packet; diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java index 86f1d921c5..d905b22d07 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java @@ -47,7 +47,7 @@ else if (packet instanceof ClientboundSetEntityDataPacket) { ider = ((ClientboundSetEntityDataPacket) packet).id(); } else if (packet instanceof ClientboundSetEntityMotionPacket) { - ider = ((ClientboundSetEntityMotionPacket) packet).getId(); + ider = ((ClientboundSetEntityMotionPacket) packet).id(); } else if (packet instanceof ClientboundTeleportEntityPacket) { ider = ((ClientboundTeleportEntityPacket) packet).id(); From 04b281ccbdb2d8229a99fbc3d33dd0cd22deebd0 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 27 Mar 2026 22:14:42 +0000 Subject: [PATCH 085/169] 26.1 part 6: handle Java 25 --- plugin/src/main/java/com/denizenscript/denizen/Denizen.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/Denizen.java b/plugin/src/main/java/com/denizenscript/denizen/Denizen.java index 9060b805b9..9067738df1 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/Denizen.java +++ b/plugin/src/main/java/com/denizenscript/denizen/Denizen.java @@ -147,11 +147,14 @@ else if (javaVersion.startsWith("17")) { Debug.log("Running on fully supported Java 17."); } else if (javaVersion.startsWith("18") || javaVersion.startsWith("19")) { - getLogger().warning("Running unreliable Java version. modern Minecraft versions are built for Java 21 or 17. Other Java versions are not guaranteed to function properly."); + getLogger().warning("Running unreliable Java version. modern Minecraft versions are built for Java 25, 21, or 17. Other Java versions are not guaranteed to function properly."); } else if (javaVersion.startsWith("21")) { Debug.log("Running on fully supported Java 21."); } + else if (javaVersion.startsWith("25")) { + Debug.log("Running on fully supported Java 25."); + } else { Debug.log("Running on unrecognized (future?) Java version. May or may not work."); } From 85a7bcb8731e2a23d488abfe700f6a8c59684c7f Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Fri, 27 Mar 2026 17:10:22 -0700 Subject: [PATCH 086/169] `EntityTag.color`: bugfix for cat types (#2818) * cat color bug fix * version change --- .../denizen/objects/properties/entity/EntityColor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityColor.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityColor.java index 75fbf49b06..3e858feff3 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityColor.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityColor.java @@ -259,6 +259,9 @@ public String getColor(boolean includeDeprecated) { case CAT -> { Cat cat = as(Cat.class); // TODO once 1.21 is the minimum supported version, replace with direct registry-based handling + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + yield Utilities.namespacedKeyToString(cat.getCatType().getKey()) + "|" + cat.getCollarColor().name(); + } yield cat.getCatType() + "|" + cat.getCollarColor().name(); } case PANDA -> { From 06c398a9725b235fcfccdd8cf54266769d5f29ef Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 28 Mar 2026 13:58:38 +0000 Subject: [PATCH 087/169] 26.1 part 7: bump Denizen version --- README.md | 4 ++-- dist/pom.xml | 2 +- paper/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 4 ++-- v1_17/pom.xml | 2 +- v1_18/pom.xml | 2 +- v1_19/pom.xml | 2 +- v1_20/pom.xml | 2 +- v1_21/pom.xml | 2 +- v26_1/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 5246dcd86e..1dd5af587f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.3.1**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, and 26.1! +**Version 1.3.2**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, and 26.1! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html @@ -45,7 +45,7 @@ An implementation of the Denizen Scripting Language for Spigot servers, with str com.denizenscript denizen - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT jar provided diff --git a/dist/pom.xml b/dist/pom.xml index a379213c15..5ed619f97c 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -5,7 +5,7 @@ com.denizenscript denizen-parent - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT 4.0.0 diff --git a/paper/pom.xml b/paper/pom.xml index 7d3b6b0869..9ca83c1805 100644 --- a/paper/pom.xml +++ b/paper/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-paper - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT diff --git a/plugin/pom.xml b/plugin/pom.xml index a6a069d70b..6266771721 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -5,7 +5,7 @@ com.denizenscript denizen - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT Denizen Scriptable Minecraft and Citizens2 diff --git a/pom.xml b/pom.xml index 237da72570..70b1bda368 100644 --- a/pom.xml +++ b/pom.xml @@ -6,13 +6,13 @@ com.denizenscript denizen-parent pom - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT UTF-8 Unknown CUSTOM - 1.3.1 + 1.3.2 diff --git a/v1_17/pom.xml b/v1_17/pom.xml index 36caa23f16..38e34558a0 100644 --- a/v1_17/pom.xml +++ b/v1_17/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_17 - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT diff --git a/v1_18/pom.xml b/v1_18/pom.xml index bda527e371..83179366f0 100644 --- a/v1_18/pom.xml +++ b/v1_18/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_18 - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT diff --git a/v1_19/pom.xml b/v1_19/pom.xml index 71d0daf7c3..98ae81ac0b 100644 --- a/v1_19/pom.xml +++ b/v1_19/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_19 - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT diff --git a/v1_20/pom.xml b/v1_20/pom.xml index 50b8cebb62..282b840be6 100644 --- a/v1_20/pom.xml +++ b/v1_20/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_20 - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT diff --git a/v1_21/pom.xml b/v1_21/pom.xml index 1449c8e8a8..58b14d7cc1 100644 --- a/v1_21/pom.xml +++ b/v1_21/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_21 - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT diff --git a/v26_1/pom.xml b/v26_1/pom.xml index 0b20031d3d..89e411ad20 100644 --- a/v26_1/pom.xml +++ b/v26_1/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v26_1 - 1.3.1-SNAPSHOT + 1.3.2-SNAPSHOT From bc73decdc83750c5ca09ea31edaf85e955b1c9f2 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Fri, 3 Apr 2026 06:10:03 -0700 Subject: [PATCH 088/169] it is 2026 --- LICENSE.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 36ee398701..aa041d8e7d 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2019-2024 The Denizen Script Team +Copyright (c) 2019-2026 The Denizen Script Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 1dd5af587f..e3c17448a0 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Copyright (C) 2013-2019 The Denizen Script Team, All Rights Reserved. The MIT License (MIT) -Copyright (c) 2019-2024 The Denizen Script Team +Copyright (c) 2019-2026 The Denizen Script Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 3b4eb3438e40a63d7c1095aa3bab982209f04038 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 3 Apr 2026 14:40:34 +0100 Subject: [PATCH 089/169] 26.1.1 bump --- README.md | 2 +- plugin/pom.xml | 2 +- v26_1/pom.xml | 4 ++-- .../java/com/denizenscript/denizen/nms/v26_1/Handler.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e3c17448a0..60f9372ded 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.3.2**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, and 26.1! +**Version 1.3.2**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, and 26.1.1! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html diff --git a/plugin/pom.xml b/plugin/pom.xml index 6266771721..bf35e01467 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -30,7 +30,7 @@ org.spigotmc spigot-api - 26.1-R0.1-SNAPSHOT + 26.1.1-R0.1-SNAPSHOT jar provided diff --git a/v26_1/pom.xml b/v26_1/pom.xml index 89e411ad20..72bb01901d 100644 --- a/v26_1/pom.xml +++ b/v26_1/pom.xml @@ -19,13 +19,13 @@ org.spigotmc spigot-api - 26.1-R0.1-SNAPSHOT + 26.1.1-R0.1-SNAPSHOT provided org.spigotmc spigot - 26.1-R0.1-SNAPSHOT + 26.1.1-R0.1-SNAPSHOT provided 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 index 3bc942fd6a..41a94eaebd 100644 --- 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 @@ -150,7 +150,7 @@ public void undisableAsyncCatcher() { @Override public boolean isExactServerVersionMatch() { - return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("26.1") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e8ece90188c951d866bd2fffc52c803e"); + return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("26.1.1") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e8ece90188c951d866bd2fffc52c803e"); } @Override From 65c796dc37fef9f260bdc6955c9fc3711c6a3be6 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 5 Apr 2026 11:19:56 +0100 Subject: [PATCH 090/169] Fix and bump for Paper 26.1.1 --- paper/pom.xml | 4 ++-- plugin/pom.xml | 2 +- .../com/denizenscript/denizen/nms/v26_1/Handler.java | 11 +++++++++-- .../denizen/nms/v26_1/helpers/BlockHelperImpl.java | 5 ++--- .../denizen/nms/v26_1/helpers/EntityHelperImpl.java | 3 +-- .../denizen/nms/v26_1/helpers/PacketHelperImpl.java | 11 +++++------ .../denizen/nms/v26_1/impl/BiomeNMSImpl.java | 6 +++--- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/paper/pom.xml b/paper/pom.xml index 9ca83c1805..016fe5ee77 100644 --- a/paper/pom.xml +++ b/paper/pom.xml @@ -25,13 +25,13 @@ io.papermc.paper paper-api - 1.21.11-R0.1-SNAPSHOT + 26.1.1.build.20-alpha provided net.citizensnpcs citizens-main - 2.0.41-SNAPSHOT + 2.0.42-SNAPSHOT jar provided diff --git a/plugin/pom.xml b/plugin/pom.xml index bf35e01467..455a5fbed6 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -44,7 +44,7 @@ net.citizensnpcs citizens-main - 2.0.41-SNAPSHOT + 2.0.42-SNAPSHOT jar provided 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 index 41a94eaebd..5a4c9c8325 100644 --- 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 @@ -79,7 +79,10 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.legacy.FieldRename; import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; -import org.bukkit.craftbukkit.util.*; +import org.bukkit.craftbukkit.util.ApiVersion; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; @@ -99,6 +102,10 @@ public class Handler extends NMSHandler { + public static BlockPos toBlockPos(Location location) { // TODO: Paper renamed 'CraftLocation#toBlockPosition', switch back once on Paper NMS + return new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + public Handler() { advancementHelper = new AdvancementHelperImpl(); animationHelper = new AnimationHelperImpl(); @@ -117,7 +124,7 @@ public Handler() { 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(LocationTag.class, BlockPos.class, Handler::toBlockPos); registerConversion(MapTag.class, CompoundTag.class, map -> { CompoundBinaryTag compoundTag = (CompoundBinaryTag) ItemRawNBT.convertObjectToNbt(map, CoreUtilities.noDebugContext, "(item)."); return compoundTag != null ? NBTAdapter.toNMS(compoundTag) : null; 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 index 50d60b6c5b..5eb4aea0b2 100644 --- 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 @@ -42,7 +42,6 @@ import org.bukkit.craftbukkit.block.CraftSkull; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.lang.invoke.MethodHandle; @@ -65,7 +64,7 @@ public class BlockHelperImpl implements BlockHelper { @Override public void applyPhysics(Location location) { - ((CraftWorld) location.getWorld()).getHandle().updateNeighborsAt(CraftLocation.toBlockPosition(location), CraftMagicNumbers.getBlock(location.getBlock().getType())); + ((CraftWorld) location.getWorld()).getHandle().updateNeighborsAt(Handler.toBlockPos(location), CraftMagicNumbers.getBlock(location.getBlock().getType())); } public static T getTE(CraftBlockEntityState cbs) { @@ -179,7 +178,7 @@ public void setBlockStrength(Material mat, float strength) { @Override public void doRandomTick(Location location) { - BlockPos pos = CraftLocation.toBlockPosition(location); + BlockPos pos = Handler.toBlockPos(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(); 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 index 410be78441..5931d2a712 100644 --- 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 @@ -75,7 +75,6 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.*; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.entity.*; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.EquipmentSlot; @@ -171,7 +170,7 @@ 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)); + new BlockHitResult(new Vec3(0, 0, 0), null, Handler.toBlockPos(location), false)); } @Override diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java index 3f3d84a134..38a889be6f 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/PacketHelperImpl.java @@ -55,7 +55,6 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.map.CraftMapCanvas; import org.bukkit.craftbukkit.map.CraftMapView; -import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; @@ -144,7 +143,7 @@ else if (entityType == EntityType.ENDERMAN) { @Override public void showBlockAction(Player player, Location location, int action, int state) { - BlockPos position = CraftLocation.toBlockPosition(location); + BlockPos position = Handler.toBlockPos(location); Block block = ((CraftWorld) location.getWorld()).getHandle().getBlockState(position).getBlock(); send(player, new ClientboundBlockEventPacket(position, block, action, state)); } @@ -187,12 +186,12 @@ public void showSignEditor(Player player, Location location) { // TODO: MC 1.18: } else { sign = null; - toOpen = CraftLocation.toBlockPosition(toCheck); + toOpen = Handler.toBlockPos(toCheck); break; } } if (sign != null) { - toOpen = CraftLocation.toBlockPosition(sign.getLocation()); + toOpen = Handler.toBlockPos(sign.getLocation()); SignSide front = sign.getSide(Side.FRONT); for (int line = 0; line < 4; line++) { front.setLine(line, ""); @@ -350,9 +349,9 @@ public void enableNetworkManager() { @Override public void showDebugTestMarker(Player player, Location location, ColorTag color, String name, int time) { - BlockPos nmsPos = CraftLocation.toBlockPosition(location); + BlockPos nmsPos = Handler.toBlockPos(location); LocationTag displayPos = !name.isEmpty() ? LocationTag.valueOf(name, CoreUtilities.noDebugContext) : null; - send(player, new ClientboundGameTestHighlightPosPacket(nmsPos, displayPos != null ? CraftLocation.toBlockPosition(displayPos) : nmsPos)); + send(player, new ClientboundGameTestHighlightPosPacket(nmsPos, displayPos != null ? Handler.toBlockPos(displayPos) : nmsPos)); } @Override diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java index d99c80dd4b..47e5afc040 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/BiomeNMSImpl.java @@ -2,6 +2,7 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.BiomeNMS; +import com.denizenscript.denizen.nms.v26_1.Handler; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.core.BlockPos; @@ -26,7 +27,6 @@ import org.bukkit.block.Block; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftEntityType; -import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.EntityType; @@ -57,7 +57,7 @@ private MappedRegistry getBiomeRegistry() { @Override public DownfallType getDownfallTypeAt(Location location) { - Biome.Precipitation precipitation = biomeHolder.value().getPrecipitationAt(CraftLocation.toBlockPosition(location), world.getSeaLevel()); + Biome.Precipitation precipitation = biomeHolder.value().getPrecipitationAt(Handler.toBlockPos(location), world.getSeaLevel()); return switch (precipitation) { case RAIN -> DownfallType.RAIN; case SNOW -> DownfallType.SNOW; @@ -77,7 +77,7 @@ public float getBaseTemperature() { @Override public float getTemperatureAt(Location location) { - return biomeHolder.value().getTemperature(CraftLocation.toBlockPosition(location), world.getSeaLevel()); + return biomeHolder.value().getTemperature(Handler.toBlockPos(location), world.getSeaLevel()); } @Override From d6b4f2b47087b6fdf1c9abc1848f9c0f95513450 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 5 Apr 2026 15:33:37 +0100 Subject: [PATCH 091/169] Additional Paper NMS rename --- .../java/com/denizenscript/denizen/Denizen.java | 16 ++++++++-------- .../nms/v26_1/helpers/ItemHelperImpl.java | 11 ++++++++++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/Denizen.java b/plugin/src/main/java/com/denizenscript/denizen/Denizen.java index 9067738df1..65ee2cf9aa 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/Denizen.java +++ b/plugin/src/main/java/com/denizenscript/denizen/Denizen.java @@ -158,14 +158,6 @@ else if (javaVersion.startsWith("25")) { else { Debug.log("Running on unrecognized (future?) Java version. May or may not work."); } - if (!NMSHandler.initialize(this)) { - getLogger().warning("-------------------------------------"); - getLogger().warning("This build of Denizen is not compatible with this Spigot version! Deactivating Denizen!"); - getLogger().warning("-------------------------------------"); - getServer().getPluginManager().disablePlugin(this); - startedSuccessful = false; - return; - } try { if (Class.forName("com.destroystokyo.paper.PaperConfig") != null) { supportsPaper = true; @@ -177,6 +169,14 @@ else if (javaVersion.startsWith("25")) { catch (Throwable ex) { Debug.echoError(ex); } + if (!NMSHandler.initialize(this)) { + getLogger().warning("-------------------------------------"); + getLogger().warning("This build of Denizen is not compatible with this Spigot version! Deactivating Denizen!"); + getLogger().warning("-------------------------------------"); + getServer().getPluginManager().disablePlugin(this); + startedSuccessful = false; + return; + } if (!NMSHandler.instance.isExactServerVersionMatch()) { String serverSoftware = supportsPaper ? "Paper" : "Spigot"; getLogger().warning(""" diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java index 10306582e2..b9ea9c2fca 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java @@ -90,6 +90,7 @@ import org.bukkit.inventory.TransmuteRecipe; import org.bukkit.map.MapView; +import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; import java.util.*; import java.util.function.Consumer; @@ -261,6 +262,9 @@ public void registerShapelessRecipe(String keyName, String group, ItemStack resu getRecipeManager().addRecipe(holder); } + // TODO: Paper renamed 'CraftRecipe#addToCraftingManager', switch back once on Paper NMS + public static final MethodHandle CRAFT_RECIPE_ADD_TO_MANAGER = ReflectionHelper.getMethodHandle(CraftRecipe.class, Denizen.supportsPaper ? "addToRecipeManager" : "addToCraftingManager"); + @Override public void registerOtherRecipe(org.bukkit.inventory.Recipe recipe) { // This method copied from Bukkit CraftServer source, just to bypass unwanted paper patch @@ -304,7 +308,12 @@ else if (recipe instanceof org.bukkit.inventory.SmithingTrimRecipe) { } toAdd = CraftTransmuteRecipe.fromBukkitRecipe((TransmuteRecipe)recipe); } - toAdd.addToCraftingManager(); + try { + CRAFT_RECIPE_ADD_TO_MANAGER.invokeExact(toAdd); + } + catch (Throwable e) { + Debug.echoError(e); + } } @Override From 7f6475f516e3b0ad6d9593a336a48dc790607844 Mon Sep 17 00:00:00 2001 From: hyper <39167664+heypr@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:50:35 -0400 Subject: [PATCH 092/169] `ItemTag.item_model/max_durability/max_stack_size/rarity` (#2734) * Components :o - Added support for the `item_model`, `max_durability`, `food`, `max_stack_size`, and `rarity` item components. - Additionally made sure that the paper `ItemTag.rarity` didn't conflict with the new >1.20 rarity component mech. * Updated name + corrected registration * Addressed comments * Addressed comments. * Max durability tag for <=1.19 * Update ItemDurability.java * Reverted changes. * Forgot to revert item extensions file. * New item component registry system * toString --> asMinimalString * Addressed comments * tern * Update PaperModule.java * moved version check into paperitemextension file * Removed legacy tag meta --- .../ComponentAdaptersRegistry.java | 4 +++ .../datacomponents/ItemModelAdapter.java | 36 +++++++++++++++++++ .../datacomponents/MaxDurabilityAdapter.java | 32 +++++++++++++++++ .../datacomponents/MaxStackSizeAdapter.java | 32 +++++++++++++++++ .../paper/datacomponents/RarityAdapter.java | 34 ++++++++++++++++++ .../paper/properties/PaperItemExtensions.java | 18 ++++------ .../properties/item/ItemCustomModel.java | 2 ++ 7 files changed, 147 insertions(+), 11 deletions(-) create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ItemModelAdapter.java create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxDurabilityAdapter.java create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxStackSizeAdapter.java create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/RarityAdapter.java diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ComponentAdaptersRegistry.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ComponentAdaptersRegistry.java index ad691abf2b..2029b783e1 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ComponentAdaptersRegistry.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ComponentAdaptersRegistry.java @@ -5,5 +5,9 @@ public class ComponentAdaptersRegistry { public static void register() { DataComponentAdapter.register(new FoodAdapter()); DataComponentAdapter.register(new GliderAdapter()); + DataComponentAdapter.register(new ItemModelAdapter()); + DataComponentAdapter.register(new MaxDurabilityAdapter()); + DataComponentAdapter.register(new MaxStackSizeAdapter()); + DataComponentAdapter.register(new RarityAdapter()); } } diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ItemModelAdapter.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ItemModelAdapter.java new file mode 100644 index 0000000000..f9eb15acbd --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/ItemModelAdapter.java @@ -0,0 +1,36 @@ +package com.denizenscript.denizen.paper.datacomponents; + +import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; +import io.papermc.paper.datacomponent.DataComponentTypes; +import net.kyori.adventure.key.Key; + +public class ItemModelAdapter extends DataComponentAdapter.Valued { + + // <--[property] + // @object ItemTag + // @name item_model + // @input ElementTag + // @description + // Controls an item's model <@link language Item Components> in namespaced key format. + // The default namespace is "minecraft", so for example an input of "stone" becomes "minecraft:stone", and will set the item model to a stone block. + // This can also be used to display item models from your own custom resource packs. + // @mechanism + // Provide no input to reset the item to its default value. + // --> + + public ItemModelAdapter() { + super(ElementTag.class, DataComponentTypes.ITEM_MODEL, "item_model"); + } + + @Override + public ElementTag toDenizen(Key value) { + return new ElementTag(value.asMinimalString(), true); + } + + @Override + public Key fromDenizen(ElementTag value, Mechanism mechanism) { + return Utilities.parseNamespacedKey(value.asString()); + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxDurabilityAdapter.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxDurabilityAdapter.java new file mode 100644 index 0000000000..6a9967d95f --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxDurabilityAdapter.java @@ -0,0 +1,32 @@ +package com.denizenscript.denizen.paper.datacomponents; + +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; +import io.papermc.paper.datacomponent.DataComponentTypes; + +public class MaxDurabilityAdapter extends DataComponentAdapter.Valued { + + // <--[property] + // @object ItemTag + // @name max_durability + // @input ElementTag(Number) + // @description + // Controls an item's max durability <@link language Item Components>. + // @mechanism + // Provide no input to reset the item to its default value. + // --> + + public MaxDurabilityAdapter() { + super(ElementTag.class, DataComponentTypes.MAX_DAMAGE, "max_durability"); + } + + @Override + public ElementTag toDenizen(Integer value) { + return new ElementTag(value); + } + + @Override + public Integer fromDenizen(ElementTag value, Mechanism mechanism) { + return mechanism.requireInteger() ? value.asInt() : null; + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxStackSizeAdapter.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxStackSizeAdapter.java new file mode 100644 index 0000000000..c9365207dd --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxStackSizeAdapter.java @@ -0,0 +1,32 @@ +package com.denizenscript.denizen.paper.datacomponents; + +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; +import io.papermc.paper.datacomponent.DataComponentTypes; + +public class MaxStackSizeAdapter extends DataComponentAdapter.Valued { + + // <--[property] + // @object ItemTag + // @name max_stack_size + // @input ElementTag(Number) + // @description + // Controls an item's max stack size <@link language Item Components>. + // @mechanism + // Provide no input to reset the item to its default value. + // --> + + public MaxStackSizeAdapter() { + super(ElementTag.class, DataComponentTypes.MAX_STACK_SIZE, "max_stack_size"); + } + + @Override + public ElementTag toDenizen(Integer value) { + return new ElementTag(value); + } + + @Override + public Integer fromDenizen(ElementTag value, Mechanism mechanism) { + return mechanism.requireInteger() ? value.asInt() : null; + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/RarityAdapter.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/RarityAdapter.java new file mode 100644 index 0000000000..9772fd51bf --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/RarityAdapter.java @@ -0,0 +1,34 @@ +package com.denizenscript.denizen.paper.datacomponents; + +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; +import io.papermc.paper.datacomponent.DataComponentTypes; +import org.bukkit.inventory.ItemRarity; + +public class RarityAdapter extends DataComponentAdapter.Valued { + + // <--[property] + // @object ItemTag + // @name rarity + // @input ElementTag + // @description + // Controls an item's rarity <@link language Item Components>. + // See <@link url https://jd.papermc.io/paper/org/bukkit/inventory/ItemRarity.html> for valid rarity values. + // @mechanism + // Provide no input to reset the item to its default value. + // --> + + public RarityAdapter() { + super(ElementTag.class, DataComponentTypes.RARITY, "rarity"); + } + + @Override + public ElementTag toDenizen(ItemRarity value) { + return new ElementTag(value); + } + + @Override + public ItemRarity fromDenizen(ElementTag value, Mechanism mechanism) { + return mechanism.requireEnum(ItemRarity.class) ? value.asEnum(ItemRarity.class) : null; + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperItemExtensions.java b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperItemExtensions.java index f2829a34fe..0dd4e809b4 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperItemExtensions.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperItemExtensions.java @@ -1,5 +1,7 @@ package com.denizenscript.denizen.paper.properties; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizencore.objects.core.ElementTag; @@ -7,16 +9,10 @@ public class PaperItemExtensions { public static void register() { - // <--[tag] - // @attribute - // @returns ElementTag - // @group paper - // @Plugin Paper - // @description - // Returns the rarity of an item, as "common", "uncommon", "rare", or "epic". - // --> - ItemTag.tagProcessor.registerTag(ElementTag.class, "rarity", (attribute, item) -> { - return new ElementTag(item.getItemStack().getRarity()); - }); + if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_20)) { + ItemTag.tagProcessor.registerTag(ElementTag.class, "rarity", (attribute, item) -> { + return new ElementTag(item.getItemStack().getRarity()); + }); + } } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemCustomModel.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemCustomModel.java index c47897271e..e97bea7df7 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemCustomModel.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemCustomModel.java @@ -15,6 +15,7 @@ public class ItemCustomModel extends ItemProperty { // @description // Controls the custom model data ID number of the item. // Use with no input to remove the custom model data. + // Prefer <@link property ItemTag.item_model> on MC 1.21+. // See also <@link tag ItemTag.has_custom_model_data> // --> public static boolean describes(ItemTag item) { @@ -56,6 +57,7 @@ public static void register() { // @group properties // @description // Returns whether the item has a custom model data ID number set on it. + // Prefer <@link property ItemTag.item_model> on MC 1.21+. // See also <@link tag ItemTag.custom_model_data>. // --> PropertyParser.registerTag(ItemCustomModel.class, ElementTag.class, "has_custom_model_data", (attribute, prop) -> { From 87709c74ce6dfbe2101c3d5ba9c85ab76148b969 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Sat, 11 Apr 2026 15:13:47 -0700 Subject: [PATCH 093/169] Trial Spawners and Vaults support (#2790) * Trial spawners and vaults compatibility * slight fixes * added BlockDispenseLootScriptEvent to accommodate vault loot dispensing * minor changes * meta correction * minor changes * better item checking for context * removed variable from determination * clarified OminousItem`Spawner` * minor changes * fix for npcs * minor changes * minor changes --- .../denizen/paper/PaperModule.java | 3 + .../events/VaultChangesStateScriptEvent.java | 74 ++++++++ .../denizen/events/ScriptEventRegistry.java | 12 +- .../block/BlockDispensesScriptEvent.java | 2 +- .../LootDispensesFromBlockScriptEvent.java | 89 +++++++++ .../block/VaultDisplayItemScriptEvent.java | 72 +++++++ .../objects/properties/PropertyRegistry.java | 3 + .../objects/properties/entity/EntityItem.java | 175 +++++------------- .../properties/material/MaterialMode.java | 24 ++- .../properties/material/MaterialOminous.java | 55 ++++++ .../utilities/BukkitImplDeprecations.java | 5 - 11 files changed, 371 insertions(+), 143 deletions(-) create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/events/VaultChangesStateScriptEvent.java create mode 100644 plugin/src/main/java/com/denizenscript/denizen/events/block/LootDispensesFromBlockScriptEvent.java create mode 100644 plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplayItemScriptEvent.java create mode 100644 plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialOminous.java diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index 305f8e41ce..d0fb32d783 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -104,6 +104,9 @@ public static void init() { ScriptEvent.registerScriptEvent(TNTPrimesScriptEvent.class); } ScriptEvent.registerScriptEvent(UnknownCommandScriptEvent.class); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + ScriptEvent.registerScriptEvent(VaultChangesStateScriptEvent.class); + } if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19)) { ScriptEvent.registerScriptEvent(WardenChangesAngerLevelScriptEvent.class); } diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/VaultChangesStateScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/VaultChangesStateScriptEvent.java new file mode 100644 index 0000000000..330667a1c1 --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/VaultChangesStateScriptEvent.java @@ -0,0 +1,74 @@ +package com.denizenscript.denizen.paper.events; + +import com.denizenscript.denizen.events.BukkitScriptEvent; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.scripts.ScriptEntryData; +import io.papermc.paper.event.block.VaultChangeStateEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class VaultChangesStateScriptEvent extends BukkitScriptEvent implements Listener { + + // <--[event] + // @Events + // vault changes state + // + // @Plugin Paper + // + // @Group Block + // + // @Cancellable true + // + // @Location true + // + // @Triggers when a vault block's state changes. A list of states can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/block/data/type/Vault.State.html>. + // + // @Context + // returns the LocationTag of the vault block. + // returns the vault state before the change. + // returns the vault state after the change. + // + // @Player when the entity who triggered the change is a player. + // + // --> + + public VaultChangesStateScriptEvent() { + registerCouldMatcher("vault changes state"); + } + + public LocationTag location; + public VaultChangeStateEvent event; + + @Override + public boolean matches(ScriptPath path) { + if (!runInCheck(path, location)) { + return false; + } + return super.matches(path); + } + + @Override + public ScriptEntryData getScriptEntryData() { + return new BukkitScriptEntryData(event.getPlayer()); + } + + @Override + public ObjectTag getContext(String name) { + return switch (name) { + case "old_state" -> new ElementTag(event.getCurrentState()); + case "new_state" -> new ElementTag(event.getNewState()); + case "location" -> location; + default -> super.getContext(name); + }; + } + + @EventHandler + public void onVaultChangesStateEvent(VaultChangeStateEvent event) { + location = new LocationTag(event.getBlock().getLocation()); + this.event = event; + fire(event); + } +} diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/ScriptEventRegistry.java b/plugin/src/main/java/com/denizenscript/denizen/events/ScriptEventRegistry.java index a3e71d4ec1..cf8863ffb0 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/ScriptEventRegistry.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/ScriptEventRegistry.java @@ -80,14 +80,23 @@ public static void registerMainEvents() { ScriptEvent.registerScriptEvent(BlockShearEntityScriptEvent.class); ScriptEvent.registerScriptEvent(BlockSpreadsScriptEvent.class); ScriptEvent.registerScriptEvent(BrewingStandFueledScriptEvent.class); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19)) { + ScriptEvent.registerScriptEvent(BrewingStartsScriptEvent.class); + } ScriptEvent.registerScriptEvent(BrewsScriptEvent.class); ScriptEvent.registerScriptEvent(CauldronLevelChangeScriptEvent.class); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + ScriptEvent.registerScriptEvent(CrafterCraftsScriptEvent.class); + } ScriptEvent.registerScriptEvent(DragonEggMovesScriptEvent.class); ScriptEvent.registerScriptEvent(FurnaceBurnsItemScriptEvent.class); ScriptEvent.registerScriptEvent(FurnaceStartsSmeltingScriptEvent.class); ScriptEvent.registerScriptEvent(LeafDecaysScriptEvent.class); ScriptEvent.registerScriptEvent(LiquidLevelChangeScriptEvent.class); ScriptEvent.registerScriptEvent(LiquidSpreadScriptEvent.class); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + ScriptEvent.registerScriptEvent(LootDispensesFromBlockScriptEvent.class); + } ScriptEvent.registerScriptEvent(MoistureChangeScriptEvent.class); ScriptEvent.registerScriptEvent(NoteBlockPlaysNoteScriptEvent.class); ScriptEvent.registerScriptEvent(PistonExtendsScriptEvent.class); @@ -95,11 +104,10 @@ public static void registerMainEvents() { ScriptEvent.registerScriptEvent(RedstoneScriptEvent.class); ScriptEvent.registerScriptEvent(SpongeAbsorbsScriptEvent.class); if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19)) { - ScriptEvent.registerScriptEvent(BrewingStartsScriptEvent.class); ScriptEvent.registerScriptEvent(TNTPrimesScriptEvent.class); } if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { - ScriptEvent.registerScriptEvent(CrafterCraftsScriptEvent.class); + ScriptEvent.registerScriptEvent(VaultDisplayItemScriptEvent.class); } // Entity events diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/BlockDispensesScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/BlockDispensesScriptEvent.java index 60e44ac303..3d287a092b 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/BlockDispensesScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/BlockDispensesScriptEvent.java @@ -22,7 +22,7 @@ public class BlockDispensesScriptEvent extends BukkitScriptEvent implements List // // @Cancellable true // - // @Triggers when a block dispenses an item. + // @Triggers when a block dispenses a single item. // // @Context // returns the LocationTag of the dispenser. diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/LootDispensesFromBlockScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/LootDispensesFromBlockScriptEvent.java new file mode 100644 index 0000000000..6d378d079c --- /dev/null +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/LootDispensesFromBlockScriptEvent.java @@ -0,0 +1,89 @@ +package com.denizenscript.denizen.events.block; + +import com.denizenscript.denizen.events.BukkitScriptEvent; +import com.denizenscript.denizen.objects.*; +import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ListTag; +import com.denizenscript.denizencore.scripts.ScriptEntryData; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockDispenseLootEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class LootDispensesFromBlockScriptEvent extends BukkitScriptEvent implements Listener { + + // <--[event] + // @Events + // loot dispenses from + // + // @Group Block + // + // @Location true + // + // @Cancellable true + // + // @Player when a player triggered the loot to dispense. + // + // @Triggers when a block dispenses loot containing multiple items. + // + // @Context + // returns a ListTag(ItemTag) of loot items. + // returns a LocationTag of the block that is dispensing the items. + // + // @Determine + // "LOOT:" to determine the new items that are outputted. + // + // --> + + public LootDispensesFromBlockScriptEvent() { + registerCouldMatcher("loot dispenses from "); + this.registerDetermination("loot", ListTag.class, (evt, context, input) -> { + List items = new ArrayList<>(input.size()); + for (ItemTag item : input.filter(ItemTag.class, context)) { + items.add(item.getItemStack()); + } + evt.event.setDispensedLoot(items); + }); + } + + public MaterialTag block; + public LocationTag location; + public BlockDispenseLootEvent event; + + @Override + public boolean matches(ScriptPath path) { + if (!path.tryArgObject(3, block)) { + return false; + } + if (!runInCheck(path, location)) { + return false; + } + return super.matches(path); + } + + @Override + public ScriptEntryData getScriptEntryData() { + return new BukkitScriptEntryData(event.getPlayer()); + } + + @Override + public ObjectTag getContext(String name) { + return switch (name) { + case "loot" -> new ListTag(event.getDispensedLoot(), ItemTag::new); + case "location" -> location; + default -> super.getContext(name); + }; + } + + @EventHandler + public void onLootDispensesFromBlock(BlockDispenseLootEvent event) { + block = new MaterialTag(event.getBlock().getType()); + location = new LocationTag(event.getBlock().getLocation()); + this.event = event; + fire(event); + } +} diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplayItemScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplayItemScriptEvent.java new file mode 100644 index 0000000000..28d5dfdd3d --- /dev/null +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplayItemScriptEvent.java @@ -0,0 +1,72 @@ +package com.denizenscript.denizen.events.block; + +import com.denizenscript.denizen.events.BukkitScriptEvent; +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizencore.objects.ObjectTag; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.VaultDisplayItemEvent; + +public class VaultDisplayItemScriptEvent extends BukkitScriptEvent implements Listener { + + // <--[event] + // @Events + // vault displays + // + // @Group Block + // + // @Location true + // + // @Cancellable true + // + // @Triggers when a vault block displays an item. + // + // @Context + // returns the LocationTag of the vault block. + // returns the ItemTag being displayed. + // + // @Determine + // "ITEM:" to set the item being displayed. + // + // --> + + public VaultDisplayItemScriptEvent() { + registerCouldMatcher("vault displays "); + this.registerDetermination("item", ItemTag.class, (evt, context, input) -> { + evt.event.setDisplayItem(input.getItemStack()); + }); + } + + public LocationTag location; + public VaultDisplayItemEvent event; + public ItemTag item; + + @Override + public boolean matches(ScriptPath path) { + if (!runInCheck(path, location)) { + return false; + } + if (!path.tryArgObject(2, item)) { + return false; + } + return super.matches(path); + } + + @Override + public ObjectTag getContext(String name) { + return switch (name) { + case "item" -> new ItemTag(event.getDisplayItem()); + case "location" -> location; + default -> super.getContext(name); + }; + } + + @EventHandler + public void onVaultDisplayItemEvent(VaultDisplayItemEvent event) { + location = new LocationTag(event.getBlock().getLocation()); + item = new ItemTag(event.getDisplayItem()); + this.event = event; + fire(event); + } +} diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java index abfdd8ef35..8f7f2410a4 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java @@ -299,6 +299,9 @@ public static void registerMainProperties() { PropertyParser.registerProperty(MaterialLightable.class, MaterialTag.class); PropertyParser.registerProperty(MaterialMode.class, MaterialTag.class); PropertyParser.registerProperty(MaterialNote.class, MaterialTag.class); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + PropertyParser.registerProperty(MaterialOminous.class, MaterialTag.class); + } PropertyParser.registerProperty(MaterialPersistent.class, MaterialTag.class); PropertyParser.registerProperty(MaterialPower.class, MaterialTag.class); PropertyParser.registerProperty(MaterialShape.class, MaterialTag.class); diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityItem.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityItem.java index 36fa15c2f7..80d0cbc86f 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityItem.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntityItem.java @@ -4,19 +4,11 @@ import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.ItemTag; -import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizencore.objects.Mechanism; -import com.denizenscript.denizencore.objects.ObjectTag; -import com.denizenscript.denizencore.objects.properties.Property; -import com.denizenscript.denizencore.objects.properties.PropertyParser; -import com.denizenscript.denizencore.tags.TagContext; import net.citizensnpcs.api.npc.NPC; -import org.bukkit.Material; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; -import org.bukkit.inventory.ItemStack; -public class EntityItem implements Property { +public class EntityItem extends EntityProperty { // <--[property] // @object EntityTag @@ -30,118 +22,66 @@ public class EntityItem implements Property { // - an eye-of-ender's item, which is both displayed and dropped. // - a fireball's display item. // - an item display's display item. + // - an ominous item spawner's display item. // --> - public static boolean describes(ObjectTag object) { - if (!(object instanceof EntityTag)) { - return false; - } - Entity entity = ((EntityTag) object).getBukkitEntity(); + public static boolean describes(EntityTag object) { + Entity entity = object.getBukkitEntity(); return entity instanceof Item || entity instanceof Enderman || entity instanceof SizedFireball || entity instanceof ThrowableProjectile || entity instanceof EnderSignal - || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && entity instanceof ItemDisplay); - } - - public static EntityItem getFrom(ObjectTag entity) { - if (!describes(entity)) { - return null; - } - else { - return new EntityItem((EntityTag) entity); - } + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && entity instanceof ItemDisplay) + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && entity instanceof OminousItemSpawner); } - public static final String[] handledMechs = new String[] { - "item" - }; - - public EntityItem(EntityTag entity) { - item = entity; - } - - EntityTag item; - - public ItemTag getItem(boolean includeDeprecated, TagContext context) { - if (isDroppedItem()) { - return new ItemTag(getDroppedItem().getItemStack()); + @Override + public ItemTag getPropertyValue() { + if (getEntity() instanceof Item item) { + return new ItemTag(item.getItemStack()); } - else if (includeDeprecated && isEnderman()) { - BukkitImplDeprecations.entityItemEnderman.warn(context); - BlockData data = getEnderman().getCarriedBlock(); - if (data == null) { - return new ItemTag(Material.AIR); - } - return new ItemTag(data.getMaterial()); + else if (getEntity() instanceof SizedFireball fireball) { + return new ItemTag(fireball.getDisplayItem()); } - else if (isFireball()) { - return new ItemTag(getFireball().getDisplayItem()); + else if (getEntity() instanceof ThrowableProjectile projectile) { + return new ItemTag(projectile.getItem()); } - else if (isThrowableProjectile()) { - return new ItemTag(getThrowableProjectile().getItem()); + else if (getEntity() instanceof EnderSignal signal) { + return new ItemTag(signal.getItem()); } - else if (isEnderSignal()) { - return new ItemTag(getEnderSignal().getItem()); + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getEntity() instanceof ItemDisplay itemDisplay) { + return new ItemTag(itemDisplay.getItemStack()); } - else if (isDisplay()) { // TODO: 1.19: when 1.19 is minimum, make a 'getDisplay' - return new ItemTag(((ItemDisplay) item.getBukkitEntity()).getItemStack()); + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getEntity() instanceof OminousItemSpawner ominousItemSpawner) { + return new ItemTag(ominousItemSpawner.getItem()); } return null; } - public boolean isDroppedItem() { - return item.getBukkitEntity() instanceof Item; - } - - public boolean isEnderman() { - return item.getBukkitEntity() instanceof Enderman; - } - - public boolean isFireball() { - return item.getBukkitEntity() instanceof SizedFireball; - } - - public boolean isThrowableProjectile() { - return item.getBukkitEntity() instanceof ThrowableProjectile; - } - - public boolean isEnderSignal() { - return item.getBukkitEntity() instanceof EnderSignal; - } - - public boolean isDisplay() { - return NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && item.getBukkitEntity() instanceof Display; - } - - public Item getDroppedItem() { - return (Item) item.getBukkitEntity(); - } - - public Enderman getEnderman() { - return (Enderman) item.getBukkitEntity(); - } - - public EnderSignal getEnderSignal() { - return (EnderSignal) item.getBukkitEntity(); - } - - public ThrowableProjectile getThrowableProjectile() { - return (ThrowableProjectile) item.getBukkitEntity(); - } - - public SizedFireball getFireball() { - return (SizedFireball) item.getBukkitEntity(); - } - @Override - public String getPropertyString() { - ItemTag item = getItem(false, null); - if (item.getBukkitMaterial() != Material.AIR) { - return item.identify(); + public void setPropertyValue(ItemTag item, Mechanism mechanism) { + if (object.isCitizensNPC()) { + object.getDenizenNPC().getCitizen().data().setPersistent(NPC.Metadata.ITEM_ID, item.getBukkitMaterial().name()); + } + if (getEntity() instanceof Item droppedItem) { + droppedItem.setItemStack(item.getItemStack()); + } + else if (getEntity() instanceof SizedFireball fireball) { + fireball.setDisplayItem(item.getItemStack()); + } + else if (getEntity() instanceof ThrowableProjectile projectile) { + projectile.setItem(item.getItemStack()); + } + else if (getEntity() instanceof EnderSignal signal) { + signal.setItem(item.getItemStack()); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getEntity() instanceof ItemDisplay itemDisplay) { + itemDisplay.setItemStack(item.getItemStack()); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getEntity() instanceof OminousItemSpawner ominousItemSpawner) { + ominousItemSpawner.setItem(item.getItemStack()); } - return null; } @Override @@ -150,37 +90,6 @@ public String getPropertyId() { } public static void register() { - PropertyParser.registerTag(EntityItem.class, ItemTag.class, "item", (attribute, object) -> { - return object.getItem(true, attribute.context); - }); - } - - @Override - public void adjust(Mechanism mechanism) { - if (mechanism.matches("item") && mechanism.requireObject(ItemTag.class)) { - ItemStack itemStack = mechanism.valueAsType(ItemTag.class).getItemStack(); - if (item.isCitizensNPC()) { - item.getDenizenNPC().getCitizen().data().setPersistent(NPC.Metadata.ITEM_ID, itemStack.getType().name()); - } - if (isDroppedItem()) { - getDroppedItem().setItemStack(itemStack); - } - else if (isEnderman()) { - BukkitImplDeprecations.entityItemEnderman.warn(mechanism.context); - getEnderman().setCarriedBlock(itemStack.getType().createBlockData()); - } - else if (isFireball()) { - getFireball().setDisplayItem(itemStack); - } - else if (isThrowableProjectile()) { - getThrowableProjectile().setItem(itemStack); - } - else if (isEnderSignal()) { - getEnderSignal().setItem(itemStack); - } - else if (isDisplay()) { // TODO: 1.19: when 1.19 is minimum, make a 'getDisplay' - ((ItemDisplay) item.getBukkitEntity()).setItemStack(itemStack); - } - } + autoRegister("item", EntityItem.class, ItemTag.class, false); } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java index 3b7250537d..1f40830f93 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java @@ -28,6 +28,8 @@ public class MaterialMode extends MaterialProperty { // For sculk_shriekers, modes are SHRIEKING and NORMAL. // For tripwires, modes are ARMED and DISARMED. // For creaking_hearts, modes are AWAKE, DORMANT, and UPROOTED. + // For trial_spawners, modes are ACTIVE, COOLDOWN, EJECTING_REWARD, INACTIVE, WAITING_FOR_PLAYERS, and WAITING_FOR_REWARD_EJECTION. + // For vaults, modes are ACTIVE, EJECTING, INACTIVE, and UNLOCKING. // --> public static boolean describes(MaterialTag material) { @@ -42,8 +44,10 @@ public static boolean describes(MaterialTag material) { || data instanceof BigDripleaf || data instanceof Tripwire || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && (data instanceof SculkCatalyst - || data instanceof SculkShrieker)) - || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && data instanceof CreakingHeart); + || data instanceof SculkShrieker)) + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && (data instanceof CreakingHeart + || data instanceof TrialSpawner + || data instanceof Vault)); } @Override @@ -84,6 +88,12 @@ else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && getBlockData() i else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof CreakingHeart creakingHeart) { return new ElementTag(creakingHeart.getCreakingHeartState().name(), true); // TODO: once 1.21 is the minimum supported version, use the enum constructor } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof TrialSpawner trialSpawner) { + return new ElementTag(trialSpawner.getTrialSpawnerState().name(), true); // TODO: once 1.21 is the minimum supported version, use the enum constructor + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof Vault vault) { + return new ElementTag(vault.getVaultState().name(), true); // TODO: once 1.21 is the minimum supported version, use the enum constructor + } return null; } @@ -135,6 +145,16 @@ else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() i creakingHeart.setCreakingHeartState(value.asEnum(CreakingHeart.State.class)); } } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof TrialSpawner trialSpawner) { + if (mechanism.requireEnum(TrialSpawner.State.class)) { + trialSpawner.setTrialSpawnerState(value.asEnum(TrialSpawner.State.class)); + } + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof Vault vault) { + if (mechanism.requireEnum(Vault.State.class)) { + vault.setVaultState(value.asEnum(Vault.State.class)); + } + } } @Override diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialOminous.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialOminous.java new file mode 100644 index 0000000000..dcdf4a56d2 --- /dev/null +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialOminous.java @@ -0,0 +1,55 @@ +package com.denizenscript.denizen.objects.properties.material; + +import com.denizenscript.denizen.objects.MaterialTag; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ElementTag; +import org.bukkit.block.data.type.TrialSpawner; +import org.bukkit.block.data.type.Vault; + +public class MaterialOminous extends MaterialProperty { + + // <--[property] + // @object MaterialTag + // @name ominous + // @input ElementTag(Boolean) + // @description + // Controls whether a trial spawner or vault is in ominous mode. + // --> + + public static boolean describes(MaterialTag material) { + return material.getModernData() instanceof TrialSpawner + || material.getModernData() instanceof Vault; + } + + @Override + public ElementTag getPropertyValue() { + if (getBlockData() instanceof TrialSpawner trialSpawner) { + return new ElementTag(trialSpawner.isOminous()); + } + else if (getBlockData() instanceof Vault vault) { + return new ElementTag(vault.isOminous()); + } + return null; + } + + @Override + public void setPropertyValue(ElementTag value, Mechanism mechanism) { + if (mechanism.requireBoolean()) { + if (getBlockData() instanceof TrialSpawner trialSpawner) { + trialSpawner.setOminous(value.asBoolean()); + } + else if (getBlockData() instanceof Vault vault) { + vault.setOminous(value.asBoolean()); + } + } + } + + @Override + public String getPropertyId() { + return "ominous"; + } + + public static void register() { + autoRegister("ominous", MaterialOminous.class, ElementTag.class, false); + } +} diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java index 949a31a77f..1b6a37b84a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java @@ -230,11 +230,6 @@ public class BukkitImplDeprecations { public static Warning itemEnchantmentsLegacy = new Warning("itemEnchantmentsLegacy", "The tag 'ItemTag.enchantments' is deprecated: use enchantment_map, or enchantment_types."); public static Warning echantmentTagUpdate = new Warning("echantmentTagUpdate", "Several legacy enchantment-related tags are deprecated in favor of using EnchantmentTag."); - // Added 2022/01/30, made very-slow 2022/12/31, made slow 2024/01/02, made normal 2025/01/15. - // 2023-year-end commonality: #29 - // Safe to remove now. - public static Warning entityItemEnderman = new Warning("entityItemEnderman", "The property 'entity.item' for endermen has been replaced by 'entity.material' due to usage of block materials."); - // Added 2021/06/19, made very-slow 2022/12/31, made slow 2024/01/02, made normal 2025/01/15. public static Warning entityMapTraceTag = new Warning("entityMapTraceTag", "The tag 'EntityTag.map_trace' is deprecated in favor of EntityTag.trace_framed_map"); From b427c5f894607531ea54a708cf238bbe2891dd4f Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 11 Apr 2026 23:52:39 +0100 Subject: [PATCH 094/169] Several minor fixes --- .../denizen/paper/PaperModule.java | 2 +- ...java => PlayerNamesEntityScriptEvent.java} | 8 ++++---- .../events/VaultChangesStateScriptEvent.java | 4 ++-- .../denizen/events/ScriptEventRegistry.java | 2 +- .../LootDispensesFromBlockScriptEvent.java | 4 ++-- ...java => VaultDisplaysItemScriptEvent.java} | 6 +++--- .../properties/material/MaterialOminous.java | 20 +++++++++---------- 7 files changed, 22 insertions(+), 24 deletions(-) rename paper/src/main/java/com/denizenscript/denizen/paper/events/{PlayerNameEntityScriptEvent.java => PlayerNamesEntityScriptEvent.java} (88%) rename plugin/src/main/java/com/denizenscript/denizen/events/block/{VaultDisplayItemScriptEvent.java => VaultDisplaysItemScriptEvent.java} (87%) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index d0fb32d783..3b53707e18 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -68,7 +68,7 @@ public static void init() { ScriptEvent.registerScriptEvent(PlayerJumpsScriptEventPaperImpl.class); ScriptEvent.registerScriptEvent(PlayerLecternPageChangeScriptEvent.class); ScriptEvent.registerScriptEvent(PlayerLoomPatternSelectScriptEvent.class); - ScriptEvent.registerScriptEvent(PlayerNameEntityScriptEvent.class); + ScriptEvent.registerScriptEvent(PlayerNamesEntityScriptEvent.class); if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { ScriptEvent.registerScriptEvent(PlayerOpenSignScriptEvent.class); } diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNameEntityScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNamesEntityScriptEvent.java similarity index 88% rename from paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNameEntityScriptEvent.java rename to paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNamesEntityScriptEvent.java index 41d421bd78..81627cd96c 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNameEntityScriptEvent.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNamesEntityScriptEvent.java @@ -13,7 +13,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -public class PlayerNameEntityScriptEvent extends BukkitScriptEvent implements Listener { +public class PlayerNamesEntityScriptEvent extends BukkitScriptEvent implements Listener { // <--[event] // @Events @@ -43,16 +43,16 @@ public class PlayerNameEntityScriptEvent extends BukkitScriptEvent implements Li // // --> - public PlayerNameEntityScriptEvent() { + public PlayerNamesEntityScriptEvent() { registerCouldMatcher("player names "); - this.registerOptionalDetermination("persistent", ElementTag.class, (evt, context, determination) -> { + this.registerOptionalDetermination("persistent", ElementTag.class, (evt, context, determination) -> { if (determination.isBoolean()) { evt.event.setPersistent(determination.asBoolean()); return true; } return false; }); - this.registerDetermination("name", ElementTag.class, (evt, context, determination) -> { + this.registerDetermination("name", ElementTag.class, (evt, context, determination) -> { evt.event.setName(PaperModule.parseFormattedText(determination.toString(), ChatColor.WHITE)); }); } diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/VaultChangesStateScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/VaultChangesStateScriptEvent.java index 330667a1c1..33100459ab 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/VaultChangesStateScriptEvent.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/VaultChangesStateScriptEvent.java @@ -24,14 +24,14 @@ public class VaultChangesStateScriptEvent extends BukkitScriptEvent implements L // // @Location true // - // @Triggers when a vault block's state changes. A list of states can be found at <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/block/data/type/Vault.State.html>. + // @Triggers when a vault block's state changes. A list of states can be found at <@link url https://jd.papermc.io/paper/org/bukkit/block/data/type/Vault.State.html>. // // @Context // returns the LocationTag of the vault block. // returns the vault state before the change. // returns the vault state after the change. // - // @Player when the entity who triggered the change is a player. + // @Player when the change is triggered by a player. // // --> diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/ScriptEventRegistry.java b/plugin/src/main/java/com/denizenscript/denizen/events/ScriptEventRegistry.java index cf8863ffb0..ea2764e4b1 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/ScriptEventRegistry.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/ScriptEventRegistry.java @@ -107,7 +107,7 @@ public static void registerMainEvents() { ScriptEvent.registerScriptEvent(TNTPrimesScriptEvent.class); } if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { - ScriptEvent.registerScriptEvent(VaultDisplayItemScriptEvent.class); + ScriptEvent.registerScriptEvent(VaultDisplaysItemScriptEvent.class); } // Entity events diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/LootDispensesFromBlockScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/LootDispensesFromBlockScriptEvent.java index 6d378d079c..d8c2e4671f 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/LootDispensesFromBlockScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/LootDispensesFromBlockScriptEvent.java @@ -26,7 +26,7 @@ public class LootDispensesFromBlockScriptEvent extends BukkitScriptEvent impleme // // @Cancellable true // - // @Player when a player triggered the loot to dispense. + // @Player when the loot dispensing is triggered by a player. // // @Triggers when a block dispenses loot containing multiple items. // @@ -35,7 +35,7 @@ public class LootDispensesFromBlockScriptEvent extends BukkitScriptEvent impleme // returns a LocationTag of the block that is dispensing the items. // // @Determine - // "LOOT:" to determine the new items that are outputted. + // "LOOT:" to set the loot items being dispensed. // // --> diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplayItemScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplaysItemScriptEvent.java similarity index 87% rename from plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplayItemScriptEvent.java rename to plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplaysItemScriptEvent.java index 28d5dfdd3d..eaec0a9c93 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplayItemScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/block/VaultDisplaysItemScriptEvent.java @@ -8,7 +8,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.VaultDisplayItemEvent; -public class VaultDisplayItemScriptEvent extends BukkitScriptEvent implements Listener { +public class VaultDisplaysItemScriptEvent extends BukkitScriptEvent implements Listener { // <--[event] // @Events @@ -31,9 +31,9 @@ public class VaultDisplayItemScriptEvent extends BukkitScriptEvent implements Li // // --> - public VaultDisplayItemScriptEvent() { + public VaultDisplaysItemScriptEvent() { registerCouldMatcher("vault displays "); - this.registerDetermination("item", ItemTag.class, (evt, context, input) -> { + this.registerDetermination("item", ItemTag.class, (evt, context, input) -> { evt.event.setDisplayItem(input.getItemStack()); }); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialOminous.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialOminous.java index dcdf4a56d2..5f40b316e0 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialOminous.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialOminous.java @@ -26,21 +26,19 @@ public ElementTag getPropertyValue() { if (getBlockData() instanceof TrialSpawner trialSpawner) { return new ElementTag(trialSpawner.isOminous()); } - else if (getBlockData() instanceof Vault vault) { - return new ElementTag(vault.isOminous()); - } - return null; + return new ElementTag(as(Vault.class).isOminous()); } @Override public void setPropertyValue(ElementTag value, Mechanism mechanism) { - if (mechanism.requireBoolean()) { - if (getBlockData() instanceof TrialSpawner trialSpawner) { - trialSpawner.setOminous(value.asBoolean()); - } - else if (getBlockData() instanceof Vault vault) { - vault.setOminous(value.asBoolean()); - } + if (!mechanism.requireBoolean()) { + return; + } + if (getBlockData() instanceof TrialSpawner trialSpawner) { + trialSpawner.setOminous(value.asBoolean()); + } + else { + as(Vault.class).setOminous(value.asBoolean()); } } From ae1a14346492cdf35185ff406d99eb008cf12986 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:13:29 +0100 Subject: [PATCH 095/169] Bump to 26.1.2 --- README.md | 2 +- paper/pom.xml | 2 +- plugin/pom.xml | 2 +- v26_1/pom.xml | 4 ++-- .../java/com/denizenscript/denizen/nms/v26_1/Handler.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 60f9372ded..a005cc2163 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.3.2**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, and 26.1.1! +**Version 1.3.2**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, and 26.1.2! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html diff --git a/paper/pom.xml b/paper/pom.xml index 016fe5ee77..68371fe434 100644 --- a/paper/pom.xml +++ b/paper/pom.xml @@ -25,7 +25,7 @@ io.papermc.paper paper-api - 26.1.1.build.20-alpha + [26.1.2.build,) provided diff --git a/plugin/pom.xml b/plugin/pom.xml index 455a5fbed6..44a4c6cd9c 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -30,7 +30,7 @@ org.spigotmc spigot-api - 26.1.1-R0.1-SNAPSHOT + 26.1.2-R0.1-SNAPSHOT jar provided diff --git a/v26_1/pom.xml b/v26_1/pom.xml index 72bb01901d..dc374277d1 100644 --- a/v26_1/pom.xml +++ b/v26_1/pom.xml @@ -19,13 +19,13 @@ org.spigotmc spigot-api - 26.1.1-R0.1-SNAPSHOT + 26.1.2-R0.1-SNAPSHOT provided org.spigotmc spigot - 26.1.1-R0.1-SNAPSHOT + 26.1.2-R0.1-SNAPSHOT provided 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 index 5a4c9c8325..b32f5b1a13 100644 --- 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 @@ -157,7 +157,7 @@ public void undisableAsyncCatcher() { @Override public boolean isExactServerVersionMatch() { - return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("26.1.1") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e8ece90188c951d866bd2fffc52c803e"); + return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("26.1.2") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e8ece90188c951d866bd2fffc52c803e"); } @Override From 335106ebc3ca82d695871e03b766b0d8f81357cf Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 20 Apr 2026 13:18:02 +0100 Subject: [PATCH 096/169] Several Paper NMS renames --- .../denizen/nms/v26_1/Handler.java | 5 ++++ .../v26_1/helpers/AdvancementHelperImpl.java | 3 +- .../nms/v26_1/helpers/BlockHelperImpl.java | 24 +++++++++++++-- .../nms/v26_1/helpers/EntityHelperImpl.java | 3 +- .../nms/v26_1/helpers/ItemHelperImpl.java | 29 +++++++++++++------ 5 files changed, 49 insertions(+), 15 deletions(-) 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 index b32f5b1a13..17c27ce687 100644 --- 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 @@ -106,6 +106,11 @@ public static BlockPos toBlockPos(Location location) { // TODO: Paper renamed 'C return new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } + // TODO: Paper renamed some NMS methods, switch back to direct calls once on Paper NMS + public static MethodHandle reflectPaperRenamed(Class clazz, String spigot, String paper, Class... params) { + return ReflectionHelper.getMethodHandle(clazz, Denizen.supportsPaper ? paper : spigot, params); + } + public Handler() { advancementHelper = new AdvancementHelperImpl(); animationHelper = new AnimationHelperImpl(); 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 index 79157f437a..a7e50ed538 100644 --- 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 @@ -16,7 +16,6 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; @@ -174,7 +173,7 @@ private static AdvancementHolder asNMSCopy(com.denizenscript.denizen.nms.util.Ad AdvancementHolder parent = advancement.parent != null ? getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.parent)) : null; - DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSTemplate(advancement.icon), + DisplayInfo display = new DisplayInfo(ItemHelperImpl.asNMSTemplate(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); 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 index 5eb4aea0b2..3a39a8215c 100644 --- 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 @@ -19,10 +19,12 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.level.BaseSpawner; +import net.minecraft.world.level.LevelAccessor; 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.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.material.FluidState; @@ -62,6 +64,17 @@ public class BlockHelperImpl implements BlockHelper { craftBlockEntityState_tileEntity = blockEntityField; } + public static final MethodHandle CRAFT_BLOCK_GET_STATE = Handler.reflectPaperRenamed(CraftBlock.class, "getNMS", "getBlockState"); + + public static BlockState getNMSState(Block block) { + try { + return (BlockState) CRAFT_BLOCK_GET_STATE.invokeExact((CraftBlock) block); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + @Override public void applyPhysics(Location location) { ((CraftWorld) location.getWorld()).getHandle().updateNeighborsAt(Handler.toBlockPos(location), CraftMagicNumbers.getBlock(location.getBlock().getType())); @@ -99,9 +112,16 @@ public void setPlayerProfile(Skull skull, PlayerProfile playerProfile) { skull.update(); } + public static final MethodHandle CRAFT_BLOCK_GET_LEVEL = Handler.reflectPaperRenamed(CraftBlock.class, "getHandle", "getLevel"); + public BlockEntity getBlockEntity(Block block) { CraftBlock craftBlock = ((CraftBlock) block); - return craftBlock.getHandle().getBlockEntity(craftBlock.getPosition()); + try { + return ((LevelAccessor) CRAFT_BLOCK_GET_LEVEL.invokeExact(craftBlock)).getBlockEntity(craftBlock.getPosition()); + } + catch (Throwable e) { + throw new RuntimeException(e); + } } @Override @@ -202,7 +222,7 @@ public int getExpDrop(Block block, org.bukkit.inventory.ItemStack item) { if (blockType == null) { return 0; } - return blockType.getExpDrop(((CraftBlock) block).getNMS(), ((CraftBlock) block).getCraftWorld().getHandle(), ((CraftBlock) block).getPosition(), + return blockType.getExpDrop(getNMSState(block), ((CraftBlock) block).getCraftWorld().getHandle(), ((CraftBlock) block).getPosition(), item == null ? null : CraftItemStack.asNMSCopy(item), true); } 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 index 5931d2a712..ac3e95b7b5 100644 --- 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 @@ -70,7 +70,6 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftCreatureSpawner; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.*; @@ -168,7 +167,7 @@ public void setRiptide(Entity entity, boolean state) { @Override public void forceInteraction(Player player, Location location) { ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); - ((CraftBlock) location.getBlock()).getNMS().useItemOn(nmsPlayer.getMainHandItem(), ((CraftWorld) location.getWorld()).getHandle(), + BlockHelperImpl.getNMSState(location.getBlock()).useItemOn(nmsPlayer.getMainHandItem(), ((CraftWorld) location.getWorld()).getHandle(), nmsPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(new Vec3(0, 0, 0), null, Handler.toBlockPos(location), false)); } diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java index b9ea9c2fca..8312001b82 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/helpers/ItemHelperImpl.java @@ -45,6 +45,7 @@ import net.minecraft.world.item.AdventureModePredicate; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStackTemplate; import net.minecraft.world.item.alchemy.PotionBrewing; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ItemLore; @@ -105,6 +106,17 @@ public static net.minecraft.world.item.crafting.RecipeHolder getNMSRecipe(Nam return ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager().byKey(nmsKey).orElse(null); } + public static final MethodHandle CRAFT_ITEM_STACK_AS_TEMPLATE = Handler.reflectPaperRenamed(CraftItemStack.class, "asNMSTemplate", "asTemplate", ItemStack.class); + + public static ItemStackTemplate asNMSTemplate(ItemStack item) { + try { + return (ItemStackTemplate) CRAFT_ITEM_STACK_AS_TEMPLATE.invokeExact(item); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + public static final Field RecipeManager_featureFlagSet = ReflectionHelper.getFields(RecipeManager.class).getFirstOfType(FeatureFlagSet.class); public void setMaxStackSize(Material material, int size) { @@ -214,16 +226,16 @@ public void registerFurnaceRecipe(String keyName, String group, ItemStack result AbstractCookingRecipe recipe; AbstractCookingRecipe.CookingBookInfo bookInfo = new AbstractCookingRecipe.CookingBookInfo(category == null ? CookingBookCategory.MISC : CookingBookCategory.valueOf(CoreUtilities.toUpperCase(category)), group); if (type.equalsIgnoreCase("smoker")) { - recipe = new SmokingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, CraftItemStack.asNMSTemplate(result), exp, time); + recipe = new SmokingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, asNMSTemplate(result), exp, time); } else if (type.equalsIgnoreCase("blast")) { - recipe = new BlastingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, CraftItemStack.asNMSTemplate(result), exp, time); + recipe = new BlastingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, asNMSTemplate(result), exp, time); } else if (type.equalsIgnoreCase("campfire")) { - recipe = new CampfireCookingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, CraftItemStack.asNMSTemplate(result), exp, time); + recipe = new CampfireCookingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, asNMSTemplate(result), exp, time); } else { - recipe = new SmeltingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, CraftItemStack.asNMSTemplate(result), exp, time); + recipe = new SmeltingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, asNMSTemplate(result), exp, time); } RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); @@ -233,7 +245,7 @@ else if (type.equalsIgnoreCase("campfire")) { public void registerStonecuttingRecipe(String keyName, String group, ItemStack result, ItemStack[] ingredient, boolean exact) { ResourceKey> key = createRecipeKey(keyName); Ingredient itemRecipe = itemArrayToRecipe(ingredient, exact); - StonecutterRecipe recipe = new StonecutterRecipe(BASE_RECIPE_INFO, itemRecipe, CraftItemStack.asNMSTemplate(result)); + StonecutterRecipe recipe = new StonecutterRecipe(BASE_RECIPE_INFO, itemRecipe, asNMSTemplate(result)); RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); } @@ -244,7 +256,7 @@ public void registerSmithingRecipe(String keyName, ItemStack result, ItemStack[] Ingredient templateItemRecipe = templateItem.length == 0 ? null : itemArrayToRecipe(templateItem, templateExact); Ingredient baseItemRecipe = itemArrayToRecipe(baseItem, baseExact); Ingredient upgradeItemRecipe = itemArrayToRecipe(upgradeItem, upgradeExact); - SmithingTransformRecipe recipe = new SmithingTransformRecipe(BASE_RECIPE_INFO, Optional.ofNullable(templateItemRecipe), baseItemRecipe, Optional.of(upgradeItemRecipe), CraftItemStack.asNMSTemplate(result)); + SmithingTransformRecipe recipe = new SmithingTransformRecipe(BASE_RECIPE_INFO, Optional.ofNullable(templateItemRecipe), baseItemRecipe, Optional.of(upgradeItemRecipe), asNMSTemplate(result)); RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); } @@ -257,13 +269,12 @@ public void registerShapelessRecipe(String keyName, String group, ItemStack resu for (int i = 0; i < ingredients.size(); i++) { ingredientList.add(itemArrayToRecipe(ingredients.get(i), exact[i])); } - ShapelessRecipe recipe = new ShapelessRecipe(BASE_RECIPE_INFO, new CraftingRecipe.CraftingBookInfo(categoryValue, group), CraftItemStack.asNMSTemplate(result), NonNullList.of(null, ingredientList.toArray(new Ingredient[0]))); + ShapelessRecipe recipe = new ShapelessRecipe(BASE_RECIPE_INFO, new CraftingRecipe.CraftingBookInfo(categoryValue, group), asNMSTemplate(result), NonNullList.of(null, ingredientList.toArray(new Ingredient[0]))); RecipeHolder holder = new RecipeHolder<>(key, recipe); getRecipeManager().addRecipe(holder); } - // TODO: Paper renamed 'CraftRecipe#addToCraftingManager', switch back once on Paper NMS - public static final MethodHandle CRAFT_RECIPE_ADD_TO_MANAGER = ReflectionHelper.getMethodHandle(CraftRecipe.class, Denizen.supportsPaper ? "addToRecipeManager" : "addToCraftingManager"); + public static final MethodHandle CRAFT_RECIPE_ADD_TO_MANAGER = Handler.reflectPaperRenamed(CraftRecipe.class, "addToCraftingManager", "addToRecipeManager"); @Override public void registerOtherRecipe(org.bukkit.inventory.Recipe recipe) { From d26deb8bb9e6314aca252fb958a7a5770455e62e Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:56:09 +0100 Subject: [PATCH 097/169] `attach`: fix velocity packet handling --- .../impl/network/handlers/packet/AttachPacketHandlers.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java index 848ccb423b..b1dc7adaf2 100644 --- a/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java +++ b/v26_1/src/main/java/com/denizenscript/denizen/nms/v26_1/impl/network/handlers/packet/AttachPacketHandlers.java @@ -34,7 +34,6 @@ public static void registerHandlers() { public static Field POS_Z_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("za", short.class); public static Field YAW_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("yRot", byte.class); public static Field PITCH_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("xRot", byte.class); - public static Field ENTITY_ID_PACKVELENT = ReflectionHelper.getFields(ClientboundSetEntityMotionPacket.class).get("id", int.class); public static Vector VECTOR_ZERO = new Vector(0, 0, 0); @@ -170,14 +169,13 @@ public static void tryProcessRotateHeadPacketForAttach(DenizenNetworkManagerImpl } } - public static void tryProcessVelocityPacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundSetEntityMotionPacket packet, Entity e) throws IllegalAccessException { + public static void tryProcessVelocityPacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundSetEntityMotionPacket packet, Entity e) { EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); if (attList != null) { for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); if (attMap.attached.isValid() && att != null) { - ClientboundSetEntityMotionPacket pNew = DenizenNetworkManagerImpl.copyPacket(packet, ClientboundSetEntityMotionPacket.STREAM_CODEC); - ENTITY_ID_PACKVELENT.setInt(pNew, att.attached.getBukkitEntity().getEntityId()); + ClientboundSetEntityMotionPacket pNew = new ClientboundSetEntityMotionPacket(att.attached.getBukkitEntity().getEntityId(), packet.movement()); if (NMSHandler.debugPackets) { DenizenNetworkManagerImpl.doPacketOutput("Attach Velocity Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName()); } From ed356260423a8f463b89b01d53e5a91bd6db78b9 Mon Sep 17 00:00:00 2001 From: MCSamuel Date: Mon, 27 Apr 2026 07:32:22 -0700 Subject: [PATCH 098/169] `MaterialTag.sides`: mossy carpet support (#2808) * Added MossyCarpet to MaterialSides, modernized property. * minor changes * slight changes in error handling * minor changes --- .../properties/material/MaterialSides.java | 237 ++++++++---------- 1 file changed, 101 insertions(+), 136 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialSides.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialSides.java index 7da3aeb2a3..137b5671b7 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialSides.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialSides.java @@ -1,118 +1,110 @@ package com.denizenscript.denizen.objects.properties.material; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizencore.objects.Mechanism; -import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; -import com.denizenscript.denizencore.objects.properties.Property; -import com.denizenscript.denizencore.objects.properties.PropertyParser; import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.debugging.DebugInternals; import org.bukkit.block.BlockFace; -import org.bukkit.block.data.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.MossyCarpet; import org.bukkit.block.data.type.RedstoneWire; import org.bukkit.block.data.type.Wall; -public class MaterialSides implements Property { - - public static boolean describes(ObjectTag material) { - if (!(material instanceof MaterialTag)) { - return false; - } - MaterialTag mat = (MaterialTag) material; - if (!mat.hasModernData()) { - return false; - } - BlockData data = mat.getModernData(); - if (!(data instanceof Wall) && !(data instanceof RedstoneWire)) { - return false; - } - return true; - } - - public static MaterialSides getFrom(ObjectTag _material) { - if (!describes(_material)) { - return null; - } - else { - return new MaterialSides((MaterialTag) _material); - } - } - - public static final String[] handledMechs = new String[] { - "sides", "heights" - }; - - public MaterialSides(MaterialTag _material) { - material = _material; - } - - MaterialTag material; - - public static void register() { - - // <--[tag] - // @attribute - // @returns ListTag - // @mechanism MaterialTag.heights - // @group properties - // @deprecated Use 'sides' - // @description - // Deprecated in favor of <@link tag MaterialTag.sides> - // --> - // <--[tag] - // @attribute - // @returns ListTag - // @mechanism MaterialTag.sides - // @group properties - // @description - // Returns the list of heights for a wall block, or connections for a redstone wire, in order North|East|South|West|Vertical. - // For wall blocks: For n/e/s/w, can be "tall", "low", or "none". For vertical, can be "tall" or "none". - // For redstone wires: For n/e/s/w, can be "none", "side", or "up". No vertical. - // --> - PropertyParser.registerStaticTag(MaterialSides.class, ListTag.class, "sides", (attribute, material) -> { - return material.getSidesList(); - }, "heights"); - } - - public boolean isWall() { - return material.getModernData() instanceof Wall; - } - - public Wall getWall() { - return (Wall) material.getModernData(); +import java.util.function.BiConsumer; + +public class MaterialSides extends MaterialProperty { + + // <--[property] + // @object MaterialTag + // @name sides + // @input ListTag + // @description + // Controls the heights for a wall block or mossy carpet, or connections for a redstone wire, in order North|East|South|West|Vertical. + // For wall blocks: For n/e/s/w, can be "tall", "low", or "none". For vertical, can be "tall" or "none". + // For redstone wires: For n/e/s/w, can be "none", "side", or "up". No vertical. + // For mossy carpets: For n/e/s/w, can be "tall", "low", or "none". Vertical controls the bottom, and can either be "bottom" or "none". + // --> + + public static boolean describes(MaterialTag material) { + BlockData data = material.getModernData(); + return data instanceof Wall + || data instanceof RedstoneWire + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && data instanceof MossyCarpet); } - public boolean isWire() { - return material.getModernData() instanceof RedstoneWire; - } - - public RedstoneWire getWire() { - return (RedstoneWire) material.getModernData(); - } - - public ListTag getSidesList() { + @Override + public ListTag getPropertyValue() { ListTag list = new ListTag(5); - if (isWall()) { - Wall wall = getWall(); + if (getBlockData() instanceof Wall wall) { list.add(wall.getHeight(BlockFace.NORTH).name()); list.add(wall.getHeight(BlockFace.EAST).name()); list.add(wall.getHeight(BlockFace.SOUTH).name()); list.add(wall.getHeight(BlockFace.WEST).name()); list.add(wall.isUp() ? "TALL" : "NONE"); } - else if (isWire()) { - RedstoneWire wire = getWire(); + else if (getBlockData() instanceof RedstoneWire wire) { list.add(wire.getFace(BlockFace.NORTH).name()); list.add(wire.getFace(BlockFace.EAST).name()); list.add(wire.getFace(BlockFace.SOUTH).name()); list.add(wire.getFace(BlockFace.WEST).name()); } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof MossyCarpet carpet) { + list.add(carpet.getHeight(BlockFace.NORTH).name()); + list.add(carpet.getHeight(BlockFace.EAST).name()); + list.add(carpet.getHeight(BlockFace.SOUTH).name()); + list.add(carpet.getHeight(BlockFace.WEST).name()); + list.add(carpet.isBottom() ? "BOTTOM" : "NONE"); + } return list; } @Override - public String getPropertyString() { - return getSidesList().identify(); + public void setPropertyValue(ListTag list, Mechanism mechanism) { + if (getBlockData() instanceof Wall wall) { + if (list.size() != 5) { + mechanism.echoError("Invalid sides list, size must be 5."); + return; + } + setSide(wall::setHeight, Wall.Height.class, BlockFace.NORTH, list, 0, mechanism); + setSide(wall::setHeight, Wall.Height.class, BlockFace.EAST, list, 1, mechanism); + setSide(wall::setHeight, Wall.Height.class, BlockFace.SOUTH, list, 2, mechanism); + setSide(wall::setHeight, Wall.Height.class, BlockFace.WEST, list, 3, mechanism); + wall.setUp(CoreUtilities.equalsIgnoreCase(list.get(4), "tall")); + } + else if (getBlockData() instanceof RedstoneWire wire) { + if (list.size() != 4) { + mechanism.echoError("Invalid sides list, size must be 4."); + return; + } + setSide(wire::setFace, RedstoneWire.Connection.class, BlockFace.NORTH, list, 0, mechanism); + setSide(wire::setFace, RedstoneWire.Connection.class, BlockFace.EAST, list, 1, mechanism); + setSide(wire::setFace, RedstoneWire.Connection.class, BlockFace.SOUTH, list, 2, mechanism); + setSide(wire::setFace, RedstoneWire.Connection.class, BlockFace.WEST, list, 3, mechanism); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof MossyCarpet carpet) { + if (list.size() != 5) { + mechanism.echoError("Invalid sides list, size must be 5."); + return; + } + setSide(carpet::setHeight, MossyCarpet.Height.class, BlockFace.NORTH, list, 0, mechanism); + setSide(carpet::setHeight, MossyCarpet.Height.class, BlockFace.EAST, list, 1, mechanism); + setSide(carpet::setHeight, MossyCarpet.Height.class, BlockFace.SOUTH, list, 2, mechanism); + setSide(carpet::setHeight, MossyCarpet.Height.class, BlockFace.WEST, list, 3, mechanism); + carpet.setBottom(CoreUtilities.equalsIgnoreCase(list.get(4), "bottom")); + } + } + + public static > void setSide(BiConsumer consumer, Class type, BlockFace face, ListTag list, int index, Mechanism mechanism) { + T value = new ElementTag(list.get(index)).asEnum(type); + if (value == null) { + mechanism.echoError("'" + list.get(index) + "' is not a valid " + DebugInternals.getClassNameOpti(type) + "."); + return; + } + consumer.accept(face, value); } @Override @@ -120,55 +112,28 @@ public String getPropertyId() { return "sides"; } - @Override - public void adjust(Mechanism mechanism) { + // <--[tag] + // @attribute + // @returns ListTag + // @mechanism MaterialTag.heights + // @group properties + // @deprecated use 'sides' + // @description + // Deprecated in favor of <@link property MaterialTag.sides> + // --> + + // <--[mechanism] + // @object MaterialTag + // @name heights + // @input ElementTag + // @deprecated use 'sides' + // @description + // Deprecated in favor of <@link property MaterialTag.sides> + // @tags + // + // --> - // <--[mechanism] - // @object MaterialTag - // @name heights - // @input ElementTag - // @deprecated Use 'sides' - // @description - // Deprecated in favor of <@link mechanism MaterialTag.sides> - // @tags - // - // --> - // <--[mechanism] - // @object MaterialTag - // @name sides - // @input ElementTag - // @description - // Sets the list of heights for a wall block, or connections for a redstone wire, in order North|East|South|West|Vertical. - // For wall blocks: For n/e/s/w, can be "tall", "low", or "none". For vertical, can be "tall" or "none". - // For redstone wires: For n/e/s/w, can be "none", "side", or "up". No vertical. - // @tags - // - // --> - if ((mechanism.matches("sides") || mechanism.matches("heights")) && mechanism.requireObject(ListTag.class)) { - ListTag list = mechanism.valueAsType(ListTag.class); - if (isWall()) { - if (list.size() != 5) { - mechanism.echoError("Invalid sides list, size must be 5."); - return; - } - Wall wall = getWall(); - wall.setHeight(BlockFace.NORTH, Wall.Height.valueOf(list.get(0).toUpperCase())); - wall.setHeight(BlockFace.EAST, Wall.Height.valueOf(list.get(1).toUpperCase())); - wall.setHeight(BlockFace.SOUTH, Wall.Height.valueOf(list.get(2).toUpperCase())); - wall.setHeight(BlockFace.WEST, Wall.Height.valueOf(list.get(3).toUpperCase())); - wall.setUp(CoreUtilities.toLowerCase(list.get(4)).equals("tall")); - } - else if (isWire()) { - if (list.size() != 4) { - mechanism.echoError("Invalid sides list, size must be 4."); - return; - } - RedstoneWire wire = getWire(); - wire.setFace(BlockFace.NORTH, RedstoneWire.Connection.valueOf(list.get(0).toUpperCase())); - wire.setFace(BlockFace.EAST, RedstoneWire.Connection.valueOf(list.get(1).toUpperCase())); - wire.setFace(BlockFace.SOUTH, RedstoneWire.Connection.valueOf(list.get(2).toUpperCase())); - wire.setFace(BlockFace.WEST, RedstoneWire.Connection.valueOf(list.get(3).toUpperCase())); - } - } + public static void register() { + autoRegister("sides", MaterialSides.class, ListTag.class, false, "heights"); } } From 2653b7513664ac2dca536cf47ac0871b5d2e8b3c Mon Sep 17 00:00:00 2001 From: MCSamuel <187220916+MC-Samuel@users.noreply.github.com> Date: Fri, 12 Jun 2026 04:04:17 -0700 Subject: [PATCH 099/169] `ChunkTag.regenerate`: was removed, deprecate (#2820) * deprecated ChunkTag.regenerate on 1.21+ * added official deprecation registration --- .../com/denizenscript/denizen/objects/ChunkTag.java | 10 ++++++++-- .../denizen/utilities/BukkitImplDeprecations.java | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/ChunkTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/ChunkTag.java index d2b8ba213b..bb2413349c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/ChunkTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/ChunkTag.java @@ -889,15 +889,21 @@ public void adjust(Mechanism mechanism) { // <--[mechanism] // @object ChunkTag // @name regenerate + // @deprecated This functionality was removed from Spigot and Paper as of 1.21. // @input None // @description + // Deprecated on MC 1.21+. // Causes the chunk to be entirely deleted and reformed from the world's seed. - // At time of writing this method only works as expected on Paper, and will error on Spigot. // @example // - adjust regenerate // --> if (mechanism.matches("regenerate")) { - getBukkitWorld().regenerateChunk(getX(), getZ()); + if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_20)) { + getBukkitWorld().regenerateChunk(getX(), getZ()); + } + else { + BukkitImplDeprecations.chunkRegeneration.warn(mechanism.context); + } } // <--[mechanism] diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java index 1b6a37b84a..5ba6887ed8 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java @@ -491,6 +491,9 @@ public class BukkitImplDeprecations { // ==================== PAST deprecations of things that are already gone but still have a warning left behind ==================== + // Removed upstream 2025/02/15 + public static Warning chunkRegeneration = new StrongWarning("chunkRegeneration", "The 'ChunkTag.regenerate' mechanism has been deprecated upstream and is no longer supported."); + // Removed upstream 2023/10/29 without warning. public static Warning npcHologramDirection = new StrongWarning("npcHologramDirection", "NPCTag's 'hologram_direction' is deprecated: it was removed from Citizens. Ask in the Citizens channel on the Discord if you need it."); From 9662b5073884973c04d85541d35700c6a750cfce Mon Sep 17 00:00:00 2001 From: hyper <39167664+heypr@users.noreply.github.com> Date: Fri, 12 Jun 2026 07:05:42 -0400 Subject: [PATCH 100/169] Add a `EntityTag.restock_trades` mechanism (#2815) * Restock trades mech * Separated sentences and corrected grammar --- .../properties/PaperEntityExtensions.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperEntityExtensions.java b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperEntityExtensions.java index 94bcb7f641..3ac1e86823 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperEntityExtensions.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperEntityExtensions.java @@ -13,6 +13,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.ExperienceOrb; import org.bukkit.entity.Goat; +import org.bukkit.entity.Villager; import org.bukkit.inventory.EquipmentSlot; import java.util.UUID; @@ -187,6 +188,27 @@ public static void register() { object.getLivingEntity().damageItemStack(slot.asEnum(EquipmentSlot.class), amount.asInt()); }); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + + // <--[mechanism] + // @object EntityTag + // @name restock_trades + // @input None + // @Plugin Paper + // @group paper + // @description + // Restocks a villager's trades. + // Note: this mechanism will fire the <@link event villager replenishes trade> event for every trade the villager is offering. + // This mechanism also updates the villager's demand for offers, which may cause item trade prices to rise or fall. + // --> + EntityTag.registerSpawnedOnlyMechanism("restock_trades", false, (object, mechanism) -> { + if (!(object.getBukkitEntity() instanceof Villager villager)) { + return; + } + villager.restock(); + }); + } + // <--[mechanism] // @object EntityTag // @name shear From cc39ed6a4c740dbf8e7406b2aecd8d14df77efcf Mon Sep 17 00:00:00 2001 From: MCSamuel <187220916+MC-Samuel@users.noreply.github.com> Date: Fri, 12 Jun 2026 04:09:18 -0700 Subject: [PATCH 101/169] `EntityTag.color`: patch for frogs (#2824) * frog color fix * remove todo --- .../denizen/utilities/MultiVersionHelper1_19.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/MultiVersionHelper1_19.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/MultiVersionHelper1_19.java index e649c9aec1..27565f5574 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/MultiVersionHelper1_19.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/MultiVersionHelper1_19.java @@ -20,7 +20,10 @@ public static boolean colorIsApplicable(EntityType type) { // TODO Frog variants technically have registries on all supported versions public static String getColor(Entity entity, boolean includeDeprecated) { if (entity instanceof Frog frog) { - return String.valueOf(frog.getVariant()); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + return Utilities.namespacedKeyToString(frog.getVariant().getKey()); + } + return frog.getVariant().toString(); } else if (entity instanceof Boat boat) { if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { From aa88bbe1e3245c4ba4f9f930195691d0a5d184c1 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 12 Jun 2026 13:14:35 +0100 Subject: [PATCH 102/169] Minor fixes to recent PRs --- .../paper/properties/PaperEntityExtensions.java | 5 ++--- .../com/denizenscript/denizen/objects/ChunkTag.java | 9 +++++---- .../denizen/utilities/BukkitImplDeprecations.java | 2 +- .../denizen/utilities/MultiVersionHelper1_19.java | 5 +---- .../denizenscript/denizen/utilities/Utilities.java | 13 +++++++++---- .../denizen/utilities/world/GameRuleReflect.java | 2 +- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperEntityExtensions.java b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperEntityExtensions.java index 3ac1e86823..bc2f6a5870 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperEntityExtensions.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperEntityExtensions.java @@ -202,10 +202,9 @@ public static void register() { // This mechanism also updates the villager's demand for offers, which may cause item trade prices to rise or fall. // --> EntityTag.registerSpawnedOnlyMechanism("restock_trades", false, (object, mechanism) -> { - if (!(object.getBukkitEntity() instanceof Villager villager)) { - return; + if (object.getBukkitEntity() instanceof Villager villager) { + villager.restock(); } - villager.restock(); }); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/ChunkTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/ChunkTag.java index bb2413349c..28819cb6cf 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/ChunkTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/ChunkTag.java @@ -1,14 +1,13 @@ package com.denizenscript.denizen.objects; +import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.utilities.BukkitImplDeprecations; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizen.utilities.flags.DataPersistenceFlagTracker; import com.denizenscript.denizen.utilities.flags.LocationFlagSearchHelper; import com.denizenscript.denizencore.flags.AbstractFlagTracker; import com.denizenscript.denizencore.flags.FlaggableObject; import com.denizenscript.denizencore.objects.*; -import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizencore.objects.core.DurationTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; @@ -16,6 +15,7 @@ import com.denizenscript.denizencore.tags.ObjectTagProcessor; import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.debugging.Debug; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; @@ -26,7 +26,8 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import java.util.*; +import java.util.ArrayList; +import java.util.List; public class ChunkTag implements ObjectTag, Adjustable, FlaggableObject { @@ -889,7 +890,7 @@ public void adjust(Mechanism mechanism) { // <--[mechanism] // @object ChunkTag // @name regenerate - // @deprecated This functionality was removed from Spigot and Paper as of 1.21. + // @deprecated functionality was removed from Spigot and Paper as of MC 1.21. // @input None // @description // Deprecated on MC 1.21+. diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java index 5ba6887ed8..19cd68ef9d 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/BukkitImplDeprecations.java @@ -492,7 +492,7 @@ public class BukkitImplDeprecations { // ==================== PAST deprecations of things that are already gone but still have a warning left behind ==================== // Removed upstream 2025/02/15 - public static Warning chunkRegeneration = new StrongWarning("chunkRegeneration", "The 'ChunkTag.regenerate' mechanism has been deprecated upstream and is no longer supported."); + public static Warning chunkRegeneration = new StrongWarning("chunkRegeneration", "'ChunkTag.regenerate' is deprecated: support for chunk regeneration has been removed upstream."); // Removed upstream 2023/10/29 without warning. public static Warning npcHologramDirection = new StrongWarning("npcHologramDirection", "NPCTag's 'hologram_direction' is deprecated: it was removed from Citizens. Ask in the Citizens channel on the Discord if you need it."); diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/MultiVersionHelper1_19.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/MultiVersionHelper1_19.java index 27565f5574..7413b4dbdf 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/MultiVersionHelper1_19.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/MultiVersionHelper1_19.java @@ -20,10 +20,7 @@ public static boolean colorIsApplicable(EntityType type) { // TODO Frog variants technically have registries on all supported versions public static String getColor(Entity entity, boolean includeDeprecated) { if (entity instanceof Frog frog) { - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { - return Utilities.namespacedKeyToString(frog.getVariant().getKey()); - } - return frog.getVariant().toString(); + return Utilities.keyedToString(frog.getVariant()); } else if (entity instanceof Boat boat) { if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java index cfac76d3aa..7f3923bcea 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/Utilities.java @@ -60,6 +60,11 @@ public static NamespacedKey parseNamespacedKey(String input) { } } + // Needed due to bytecode differences between versions (e.g. enum to interface changes) + public static String keyedToString(Keyed keyed) { + return namespacedKeyToString(keyed.getKey()); + } + public static String namespacedKeyToString(NamespacedKey key) { return key.getNamespace().equals(NamespacedKey.MINECRAFT) ? key.getKey() : key.toString(); } @@ -567,11 +572,11 @@ public static ListTag listLegacyTypes(Class type) { } public static ElementTag enumlikeToElement(Object val) { - if (val instanceof Enum) { - return new ElementTag(((Enum) val).name()); + if (val instanceof Enum enumVal) { + return new ElementTag(enumVal); } - if (val instanceof Keyed) { - return new ElementTag(namespacedKeyToString(((Keyed) val).getKey()), true); + if (val instanceof Keyed keyed) { + return new ElementTag(keyedToString(keyed), true); } return new ElementTag(val.toString()); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java index 6163452629..62b09b4dd3 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/world/GameRuleReflect.java @@ -40,7 +40,7 @@ public static GameRule getByName(String name) { public static String getName(GameRule gameRule) { if (MODERN_GAMERULE_NAMING) { - return Utilities.namespacedKeyToString(((Keyed) gameRule).getKey()); + return Utilities.keyedToString(gameRule); } try { return (String) GAMERULE_GET_NAME.invokeExact(gameRule); From f19ee47e3b59383ebaf869ecc74e071a0726181b Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 17 Jun 2026 18:44:21 +0100 Subject: [PATCH 103/169] 26.2 part 1: copy over 26.1 module --- v26_2/pom.xml | 47 + .../denizen/nms/v26_2/Handler.java | 435 +++++++++ .../v26_2/helpers/AdvancementHelperImpl.java | 195 ++++ .../v26_2/helpers/AnimationHelperImpl.java | 48 + .../nms/v26_2/helpers/BlockHelperImpl.java | 271 ++++++ .../nms/v26_2/helpers/ChunkHelperImpl.java | 119 +++ .../v26_2/helpers/CustomEntityHelperImpl.java | 149 +++ .../v26_2/helpers/EnchantmentHelperImpl.java | 195 ++++ .../v26_2/helpers/EntityDataNameMapper.java | 484 ++++++++++ .../nms/v26_2/helpers/EntityHelperImpl.java | 867 ++++++++++++++++++ .../nms/v26_2/helpers/FishingHelperImpl.java | 156 ++++ .../nms/v26_2/helpers/ItemHelperImpl.java | 796 ++++++++++++++++ .../denizen/nms/v26_2/helpers/NBTAdapter.java | 143 +++ .../nms/v26_2/helpers/PacketHelperImpl.java | 433 +++++++++ .../nms/v26_2/helpers/PlayerHelperImpl.java | 508 ++++++++++ .../nms/v26_2/helpers/WorldHelperImpl.java | 103 +++ .../denizen/nms/v26_2/impl/BiomeNMSImpl.java | 241 +++++ .../v26_2/impl/ImprovedOfflinePlayerImpl.java | 169 ++++ .../nms/v26_2/impl/ProfileEditorImpl.java | 168 ++++ .../denizen/nms/v26_2/impl/SidebarImpl.java | 103 +++ .../nms/v26_2/impl/blocks/BlockLightImpl.java | 263 ++++++ .../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 | 97 ++ .../impl/network/fakes/FakeChannelImpl.java | 80 ++ .../network/fakes/FakeNetworkManagerImpl.java | 16 + .../fakes/FakePlayerConnectionImpl.java | 20 + .../handlers/AbstractListenerPlayInImpl.java | 670 ++++++++++++++ .../handlers/DenizenNetworkManagerImpl.java | 579 ++++++++++++ .../handlers/DenizenPacketListenerImpl.java | 121 +++ .../network/handlers/FakeBlockHelper.java | 167 ++++ .../packet/ActionBarEventPacketHandlers.java | 39 + .../handlers/packet/AttachPacketHandlers.java | 307 +++++++ .../packet/BlockLightPacketHandlers.java | 27 + .../DenizenPacketHandlerPacketHandlers.java | 47 + .../packet/DisguisePacketHandlers.java | 160 ++++ .../packet/EntityMetadataPacketHandlers.java | 92 ++ .../packet/FakeBlocksPacketHandlers.java | 111 +++ .../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 + 50 files changed, 9254 insertions(+) create mode 100644 v26_2/pom.xml create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AdvancementHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AnimationHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/BlockHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ChunkHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/CustomEntityHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EnchantmentHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityDataNameMapper.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/FishingHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/NBTAdapter.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PacketHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PlayerHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/WorldHelperImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/BiomeNMSImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ImprovedOfflinePlayerImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ProfileEditorImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/SidebarImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/blocks/BlockLightImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakeArrowImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakePlayerImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftItemProjectileImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakeArrowImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakePlayerImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityItemProjectileImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeChannelImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeNetworkManagerImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakePlayerConnectionImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/AbstractListenerPlayInImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenPacketListenerImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/ActionBarEventPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/AttachPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/BlockLightPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DisguisePacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/EntityMetadataPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakePlayerPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HideParticlesPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInResourcePackStatusImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInSteerVehicleImpl.java create mode 100644 v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketOutChatImpl.java diff --git a/v26_2/pom.xml b/v26_2/pom.xml new file mode 100644 index 0000000000..dc374277d1 --- /dev/null +++ b/v26_2/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + com.denizenscript + denizen-v26_1 + 1.3.2-SNAPSHOT + + + + com.denizenscript + denizen + ${project.version} + compile + true + + + org.spigotmc + spigot-api + 26.1.2-R0.1-SNAPSHOT + provided + + + org.spigotmc + spigot + 26.1.2-R0.1-SNAPSHOT + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + 16 + 16 + + + + + + diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java new file mode 100644 index 0000000000..17c27ce687 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java @@ -0,0 +1,435 @@ +package com.denizenscript.denizen.nms.v26_1; + +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.v26_1.helpers.*; +import com.denizenscript.denizen.nms.v26_1.impl.BiomeNMSImpl; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.SidebarImpl; +import com.denizenscript.denizen.nms.v26_1.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.CraftRegistry; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.boss.CraftBossBar; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryCustom; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.legacy.FieldRename; +import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; +import org.bukkit.craftbukkit.util.ApiVersion; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +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 static BlockPos toBlockPos(Location location) { // TODO: Paper renamed 'CraftLocation#toBlockPosition', switch back once on Paper NMS + return new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + // TODO: Paper renamed some NMS methods, switch back to direct calls once on Paper NMS + public static MethodHandle reflectPaperRenamed(Class clazz, String spigot, String paper, Class... params) { + return ReflectionHelper.getMethodHandle(clazz, Denizen.supportsPaper ? paper : spigot, params); + } + + 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, Handler::toBlockPos); + 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("26.1.2") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e8ece90188c951d866bd2fffc52c803e"); + } + + @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_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AdvancementHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AdvancementHelperImpl.java new file mode 100644 index 0000000000..a7e50ed538 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AdvancementHelperImpl.java @@ -0,0 +1,195 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.nms.interfaces.AdvancementHelper; +import com.denizenscript.denizen.nms.v26_1.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.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.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(ItemHelperImpl.asNMSTemplate(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_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AnimationHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AnimationHelperImpl.java new file mode 100644 index 0000000000..2c12daf4ba --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AnimationHelperImpl.java @@ -0,0 +1,48 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.nms.abstracts.AnimationHelper; +import net.minecraft.world.entity.Entity; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftHorse; +import org.bukkit.craftbukkit.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_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/BlockHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/BlockHelperImpl.java new file mode 100644 index 0000000000..3a39a8215c --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/BlockHelperImpl.java @@ -0,0 +1,271 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.nms.interfaces.BlockHelper; +import com.denizenscript.denizen.nms.util.PlayerProfile; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.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.LevelAccessor; +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.block.state.BlockState; +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.CraftChunk; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.block.CraftSkull; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.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; + } + + public static final MethodHandle CRAFT_BLOCK_GET_STATE = Handler.reflectPaperRenamed(CraftBlock.class, "getNMS", "getBlockState"); + + public static BlockState getNMSState(Block block) { + try { + return (BlockState) CRAFT_BLOCK_GET_STATE.invokeExact((CraftBlock) block); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Override + public void applyPhysics(Location location) { + ((CraftWorld) location.getWorld()).getHandle().updateNeighborsAt(Handler.toBlockPos(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 static final MethodHandle CRAFT_BLOCK_GET_LEVEL = Handler.reflectPaperRenamed(CraftBlock.class, "getHandle", "getLevel"); + + public BlockEntity getBlockEntity(Block block) { + CraftBlock craftBlock = ((CraftBlock) block); + try { + return ((LevelAccessor) CRAFT_BLOCK_GET_LEVEL.invokeExact(craftBlock)).getBlockEntity(craftBlock.getPosition()); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @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, "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, "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 = Handler.toBlockPos(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.getRandom()); + } + FluidState fluid = nmsBlock.getFluidState(); + if (fluid.isRandomlyTicking()) { + fluid.animateTick(nmsWorld, pos, nmsWorld.getRandom()); + } + } + + @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(getNMSState(block), ((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_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ChunkHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ChunkHelperImpl.java new file mode 100644 index 0000000000..b203e0a2b5 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ChunkHelperImpl.java @@ -0,0 +1,119 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.nms.abstracts.BiomeNMS; +import com.denizenscript.denizen.nms.interfaces.ChunkHelper; +import com.denizenscript.denizen.nms.v26_1.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.CraftChunk; +import org.bukkit.craftbukkit.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_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/CustomEntityHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/CustomEntityHelperImpl.java new file mode 100644 index 0000000000..9905e036ef --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/CustomEntityHelperImpl.java @@ -0,0 +1,149 @@ +package com.denizenscript.denizen.nms.v26_1.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.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.CraftFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityFakeArrowImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_1.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.CraftWorld; +import org.bukkit.craftbukkit.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_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EnchantmentHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EnchantmentHelperImpl.java new file mode 100644 index 0000000000..ae556afc23 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EnchantmentHelperImpl.java @@ -0,0 +1,195 @@ +package com.denizenscript.denizen.nms.v26_1.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("frozen", boolean.class); + public static final Field REGISTRY_INTRUSIVE_HOLDERS = ReflectionHelper.getFields(MappedRegistry.class).get("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_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityDataNameMapper.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityDataNameMapper.java new file mode 100644 index 0000000000..8ce7da8054 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityDataNameMapper.java @@ -0,0 +1,484 @@ +package com.denizenscript.denizen.nms.v26_1.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 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 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_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityHelperImpl.java new file mode 100644 index 0000000000..ac3e95b7b5 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityHelperImpl.java @@ -0,0 +1,867 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.interfaces.EntityHelper; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.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.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.*; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +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, "onGround", boolean.class); + + public static final EntityDataAccessor ENDERMAN_DATA_ACCESSOR_SCREAMING = ReflectionHelper.getFieldValue(EnderMan.class, "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, "autoSpinAttackTicks"); + public static final MethodHandle LIVINGENTITY_SETLIVINGENTITYFLAG = ReflectionHelper.getMethodHandle(net.minecraft.world.entity.LivingEntity.class, "setLivingEntityFlag", 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(); + BlockHelperImpl.getNMSState(location.getBlock()).useItemOn(nmsPlayer.getMainHandItem(), ((CraftWorld) location.getWorld()).getHandle(), + nmsPlayer, InteractionHand.MAIN_HAND, + new BlockHitResult(new Vec3(0, 0, 0), null, Handler.toBlockPos(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("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("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("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 dataItem = dataItemsById.get(id); + if (dataItem == null) { + Debug.echoError("Invalid internal data id '" + id + "': couldn't be matched to any internal data for entity of type '" + entity.getType() + "'."); + return; + } + Object converted = ReflectionSetCommand.convertObjectTypeFor(dataItem.getValue().getClass(), entry.getValue()); + if (converted != null) { + processConverted.accept(dataItem, converted); + } + } + } + + @Override + public List convertInternalEntityDataValues(Entity entity, MapTag internalData) { + List dataValues = new ArrayList<>(internalData.size()); + convertToInternalData(entity, internalData, (dataItem, converted) -> dataValues.add(PacketHelperImpl.createEntityData(dataItem.getAccessor(), converted))); + return dataValues; + } + + @Override + public void modifyInternalEntityData(Entity entity, MapTag internalData) { + SynchedEntityData nmsEntityData = ((CraftEntity) entity).getHandle().getEntityData(); + convertToInternalData(entity, internalData, (dataItem, converted) -> nmsEntityData.set(dataItem.getAccessor(), converted)); + } + + @Override + public void startUsingItem(LivingEntity entity, EquipmentSlot hand) { + ((CraftLivingEntity) entity).getHandle().startUsingItem(hand == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); + } + + @Override + public void stopUsingItem(LivingEntity entity) { + ((CraftLivingEntity) entity).getHandle().stopUsingItem(); + } + + @Override + public void openHorseInventory(Player player, AbstractHorse horse) { + net.minecraft.world.entity.animal.equine.AbstractHorse nmsHorse = ((CraftAbstractHorse) horse).getHandle(); + ((CraftPlayer) player).getHandle().openHorseInventory(nmsHorse, nmsHorse.inventory); + } + + private CompoundTag getRawEntityNBT(net.minecraft.world.entity.Entity entity) { + return Handler.useValueOutput(entity::saveWithoutId); + } + + @Override + public CompoundBinaryTag getRawNBT(Entity entity) { + return NBTAdapter.toAPI(getRawEntityNBT(((CraftEntity) entity).getHandle())); + } + + @Override + public void modifyRawNBT(Entity entity, CompoundBinaryTag tag) { + net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle(); + CompoundTag nmsTag = NBTAdapter.toNMS(tag); + CompoundTag nmsMergedTag = getRawEntityNBT(nmsEntity).merge(nmsTag); + UUID uuid = nmsEntity.getUUID(); + Handler.useValueInput(nmsMergedTag, nmsEntity::load); + nmsEntity.setUUID(uuid); + } + + @Override + public EntityState.ArmadilloState getArmadilloState(org.bukkit.entity.Armadillo entity) { + Armadillo armadillo = (Armadillo) ((CraftEntity) entity).getHandle(); + return switch (armadillo.getState()) { + case IDLE -> EntityState.ArmadilloState.IDLE; + case ROLLING -> EntityState.ArmadilloState.ROLLING; + case SCARED -> EntityState.ArmadilloState.SCARED; + case UNROLLING -> EntityState.ArmadilloState.UNROLLING; + }; + } + + @Override + public void setArmadilloState(org.bukkit.entity.Armadillo entity, EntityState.ArmadilloState state) { + Armadillo armadillo = (Armadillo) ((CraftEntity) entity).getHandle(); + armadillo.switchToState(switch (state) { + case IDLE -> Armadillo.ArmadilloState.IDLE; + case ROLLING -> Armadillo.ArmadilloState.ROLLING; + case SCARED -> Armadillo.ArmadilloState.SCARED; + case UNROLLING -> Armadillo.ArmadilloState.UNROLLING; + }); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/FishingHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/FishingHelperImpl.java new file mode 100644 index 0000000000..f6630b5a3c --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/FishingHelperImpl.java @@ -0,0 +1,156 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.nms.interfaces.FishingHelper; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.projectile.FishingHook; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.level.storage.loot.BuiltInLootTables; +import net.minecraft.world.level.storage.loot.LootParams; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftFishHook; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.FishHook; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.Field; +import java.util.List; + +public class FishingHelperImpl implements FishingHelper { + + @Override + public org.bukkit.inventory.ItemStack getResult(FishHook fishHook, CatchType catchType) { + FishingHook nmsHook = ((CraftFishHook) fishHook).getHandle(); + ItemStack result = switch (catchType) { + case DEFAULT -> { + ServerLevel nmsWorld = ((CraftWorld) fishHook.getWorld()).getHandle(); + ItemStack nmsFishingRod = nmsHook.getPlayerOwner().getMainHandItem(); + float f = nmsWorld.getRandom().nextFloat(); + float i = EnchantmentHelper.getFishingTimeReduction(nmsWorld, nmsFishingRod, nmsHook.getPlayerOwner()); + int j = EnchantmentHelper.getFishingLuckBonus(nmsWorld, nmsFishingRod, nmsHook.getPlayerOwner()); + float f1 = 0.1F - i * 0.025F - (float) j * 0.01F; + float f2 = 0.05F + i * 0.01F - (float) j * 0.01F; + + f1 = Mth.clamp(f1, 0.0F, 1.0F); + f2 = Mth.clamp(f2, 0.0F, 1.0F); + if (f < f1) { + yield catchRandomJunk(nmsHook); + } + else { + f -= f1; + if (f < f2) { + yield catchRandomTreasure(nmsHook); + } + else { + yield catchRandomFish(nmsHook); + } + } + } + case JUNK -> catchRandomJunk(nmsHook); + case TREASURE -> catchRandomTreasure(nmsHook); + case FISH -> catchRandomFish(nmsHook); + default -> null; + }; + return result != null ? CraftItemStack.asBukkitCopy(result) : null; + } + + public ItemStack getRandomReward(FishingHook nmsHook, ResourceKey key) { + ServerLevel nmsWorld = (ServerLevel) nmsHook.level(); + LootParams nmsLootParams = new LootParams.Builder(nmsWorld) + .withParameter(LootContextParams.ORIGIN, new Vec3(nmsHook.getX(), nmsHook.getY(), nmsHook.getZ())) + .withParameter(LootContextParams.TOOL, new ItemStack(Items.FISHING_ROD)) + .create(LootContextParamSets.FISHING); + List nmsItems = nmsWorld.getServer().reloadableRegistries().getLootTable(key).getRandomItems(nmsLootParams); + return nmsItems.get(nmsWorld.getRandom().nextInt(nmsItems.size())); + } + + @Override + public FishHook spawnHook(Location location, Player player) { + ServerLevel nmsWorld = ((CraftWorld) location.getWorld()).getHandle(); + FishingHook hook = new FishingHook(((CraftPlayer) player).getHandle(), nmsWorld, 0, 0); + nmsWorld.addFreshEntity(hook, CreatureSpawnEvent.SpawnReason.CUSTOM); + return (FishHook) hook.getBukkitEntity(); + } + + private ItemStack catchRandomJunk(FishingHook fishHook) { + return getRandomReward(fishHook, BuiltInLootTables.FISHING_JUNK); + } + + private ItemStack catchRandomTreasure(FishingHook fishHook) { + return getRandomReward(fishHook, BuiltInLootTables.FISHING_TREASURE); + } + + private ItemStack catchRandomFish(FishingHook fishHook) { + return getRandomReward(fishHook, BuiltInLootTables.FISHING_FISH); + } + + public static final Field FISHING_HOOK_NIBBLE = ReflectionHelper.getFields(FishingHook.class).get("nibble", int.class); + public static final Field FISHING_HOOK_LURE_TIME = ReflectionHelper.getFields(FishingHook.class).get("timeUntilLured", int.class); + public static final Field FISHING_HOOK_HOOK_TIME = ReflectionHelper.getFields(FishingHook.class).get("timeUntilHooked", int.class); + + @Override + public FishHook getHookFrom(Player player) { + FishingHook nmsHook = ((CraftPlayer) player).getHandle().fishing; + if (nmsHook == null) { + return null; + } + return (FishHook) nmsHook.getBukkitEntity(); + } + + @Override + public void setNibble(FishHook hook, int ticks) { + FishingHook nmsHook = ((CraftFishHook) hook).getHandle(); + try { + FISHING_HOOK_NIBBLE.setInt(nmsHook, ticks); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void setHookTime(FishHook hook, int ticks) { + FishingHook nmsHook = ((CraftFishHook) hook).getHandle(); + try { + FISHING_HOOK_HOOK_TIME.setInt(nmsHook, ticks); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public int getLureTime(FishHook hook) { + FishingHook nmsHook = ((CraftFishHook) hook).getHandle(); + try { + return FISHING_HOOK_LURE_TIME.getInt(nmsHook); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return -1; + } + + @Override + public void setLureTime(FishHook hook, int ticks) { + FishingHook nmsHook = ((CraftFishHook) hook).getHandle(); + try { + FISHING_HOOK_LURE_TIME.setInt(nmsHook, ticks); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java new file mode 100644 index 0000000000..8312001b82 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java @@ -0,0 +1,796 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.interfaces.ItemHelper; +import com.denizenscript.denizen.nms.util.PlayerProfile; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.objects.properties.item.ItemComponentsPatch; +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.core.ElementTag; +import com.denizenscript.denizencore.objects.core.MapTag; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.collect.*; +import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.JsonOps; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.advancements.criterion.BlockPredicate; +import net.minecraft.advancements.criterion.DataComponentMatchers; +import net.minecraft.core.*; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.item.AdventureModePredicate; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStackTemplate; +import net.minecraft.world.item.alchemy.PotionBrewing; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ItemLore; +import net.minecraft.world.item.component.ResolvableProfile; +import net.minecraft.world.item.component.TypedEntityData; +import net.minecraft.world.item.crafting.*; +import net.minecraft.world.item.crafting.BlastingRecipe; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.ShapelessRecipe; +import net.minecraft.world.item.crafting.SmithingTransformRecipe; +import net.minecraft.world.item.crafting.SmokingRecipe; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.level.saveddata.maps.MapId; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.*; +import org.bukkit.craftbukkit.map.CraftMapView; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.*; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.SmithingTrimRecipe; +import org.bukkit.inventory.TransmuteRecipe; +import org.bukkit.map.MapView; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class ItemHelperImpl extends ItemHelper { + + public static final Recipe.CommonInfo BASE_RECIPE_INFO = new Recipe.CommonInfo(true); + + public static net.minecraft.world.item.crafting.RecipeHolder getNMSRecipe(NamespacedKey key) { + ResourceKey> nmsKey = ResourceKey.create(Registries.RECIPE, CraftNamespacedKey.toMinecraft(key)); + return ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager().byKey(nmsKey).orElse(null); + } + + public static final MethodHandle CRAFT_ITEM_STACK_AS_TEMPLATE = Handler.reflectPaperRenamed(CraftItemStack.class, "asNMSTemplate", "asTemplate", ItemStack.class); + + public static ItemStackTemplate asNMSTemplate(ItemStack item) { + try { + return (ItemStackTemplate) CRAFT_ITEM_STACK_AS_TEMPLATE.invokeExact(item); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public static final Field RecipeManager_featureFlagSet = ReflectionHelper.getFields(RecipeManager.class).getFirstOfType(FeatureFlagSet.class); + + public void setMaxStackSize(Material material, int size) { + try { + ReflectionHelper.getFinalSetter(Material.class, "maxStack").invoke(material, size); + Holder.Reference nmsItemHolder = BuiltInRegistries.ITEM.get(CraftNamespacedKey.toMinecraft(material.getKey())).orElseThrow(); + nmsItemHolder.bindComponents(DataComponentMap.composite(nmsItemHolder.components(), DataComponentMap.builder().set(DataComponents.MAX_STACK_SIZE, size).build())); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public static RecipeManager getRecipeManager() { + return ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager(); + } + + public static CompoundTag serializeNmsItem(net.minecraft.world.item.ItemStack nmsItem) { + return (CompoundTag) net.minecraft.world.item.ItemStack.CODEC.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE), nmsItem).getOrThrow(); + } + + public static net.minecraft.world.item.ItemStack parseNmsItem(CompoundTag nmsTag) { + return net.minecraft.world.item.ItemStack.CODEC.parse(CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE), nmsTag).getOrThrow(); + } + + public Object recipeManagerFeatureFlagSetCache = null; + + @Override + public void blockRecipeFinalization() { + try { + RecipeManager manager = getRecipeManager(); + Object flags = RecipeManager_featureFlagSet.get(manager); + if (flags != null) { + recipeManagerFeatureFlagSetCache = flags; + RecipeManager_featureFlagSet.set(manager, null); + + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void restoreRecipeFinalization() { + try { + RecipeManager manager = getRecipeManager(); + if (recipeManagerFeatureFlagSetCache != null) { + RecipeManager_featureFlagSet.set(manager, recipeManagerFeatureFlagSetCache); + manager.finalizeRecipeLoading(); + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void removeRecipes(List keys) { + blockRecipeFinalization(); + RecipeManager manager = getRecipeManager(); + for (NamespacedKey key: keys) { + ResourceKey> nmsKey = ResourceKey.create(Registries.RECIPE, CraftNamespacedKey.toMinecraft(key)); + manager.removeRecipe(nmsKey); + } + restoreRecipeFinalization(); + } + + @Override + public Integer burnTime(Material material) { + return MinecraftServer.getServer().fuelValues().burnDuration(new net.minecraft.world.item.ItemStack(CraftMagicNumbers.getItem(material))); + } + + @Override + public void setShapedRecipeIngredient(ShapedRecipe recipe, char c, ItemStack[] item, boolean exact) { + if (item.length == 1 && item[0].getType() == Material.AIR) { + recipe.setIngredient(c, new RecipeChoice.MaterialChoice(Material.AIR)); + } + else if (exact) { + recipe.setIngredient(c, new RecipeChoice.ExactChoice(item)); + } + else { + Material[] mats = new Material[item.length]; + for (int i = 0; i < item.length; i++) { + mats[i] = item[i].getType(); + } + recipe.setIngredient(c, new RecipeChoice.MaterialChoice(mats)); + } + } + + // TODO: Recipe registration should be moved to the API + public static Ingredient itemArrayToRecipe(ItemStack[] items, boolean exact) { + if (!exact) { + return Ingredient.of(Arrays.stream(items).map(item -> CraftMagicNumbers.getItem(item.getType()))); + } + return Ingredient.ofStacks(Arrays.stream(items).map(CraftItemStack::asNMSCopy).toList()); + } + + public static ResourceKey> createRecipeKey(String name) { + return ResourceKey.create(Registries.RECIPE, Identifier.fromNamespaceAndPath("denizen", name)); + } + + @Override + public void registerFurnaceRecipe(String keyName, String group, ItemStack result, ItemStack[] ingredient, float exp, int time, String type, boolean exact, String category) { + ResourceKey> key = createRecipeKey(keyName); + Ingredient itemRecipe = itemArrayToRecipe(ingredient, exact); + AbstractCookingRecipe recipe; + AbstractCookingRecipe.CookingBookInfo bookInfo = new AbstractCookingRecipe.CookingBookInfo(category == null ? CookingBookCategory.MISC : CookingBookCategory.valueOf(CoreUtilities.toUpperCase(category)), group); + if (type.equalsIgnoreCase("smoker")) { + recipe = new SmokingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, asNMSTemplate(result), exp, time); + } + else if (type.equalsIgnoreCase("blast")) { + recipe = new BlastingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, asNMSTemplate(result), exp, time); + } + else if (type.equalsIgnoreCase("campfire")) { + recipe = new CampfireCookingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, asNMSTemplate(result), exp, time); + } + else { + recipe = new SmeltingRecipe(BASE_RECIPE_INFO, bookInfo, itemRecipe, asNMSTemplate(result), exp, time); + } + RecipeHolder holder = new RecipeHolder<>(key, recipe); + getRecipeManager().addRecipe(holder); + } + + @Override + public void registerStonecuttingRecipe(String keyName, String group, ItemStack result, ItemStack[] ingredient, boolean exact) { + ResourceKey> key = createRecipeKey(keyName); + Ingredient itemRecipe = itemArrayToRecipe(ingredient, exact); + StonecutterRecipe recipe = new StonecutterRecipe(BASE_RECIPE_INFO, itemRecipe, asNMSTemplate(result)); + RecipeHolder holder = new RecipeHolder<>(key, recipe); + getRecipeManager().addRecipe(holder); + } + + @Override + public void registerSmithingRecipe(String keyName, ItemStack result, ItemStack[] baseItem, boolean baseExact, ItemStack[] upgradeItem, boolean upgradeExact, ItemStack[] templateItem, boolean templateExact) { + ResourceKey> key = createRecipeKey(keyName); + Ingredient templateItemRecipe = templateItem.length == 0 ? null : itemArrayToRecipe(templateItem, templateExact); + Ingredient baseItemRecipe = itemArrayToRecipe(baseItem, baseExact); + Ingredient upgradeItemRecipe = itemArrayToRecipe(upgradeItem, upgradeExact); + SmithingTransformRecipe recipe = new SmithingTransformRecipe(BASE_RECIPE_INFO, Optional.ofNullable(templateItemRecipe), baseItemRecipe, Optional.of(upgradeItemRecipe), asNMSTemplate(result)); + RecipeHolder holder = new RecipeHolder<>(key, recipe); + getRecipeManager().addRecipe(holder); + } + + @Override + public void registerShapelessRecipe(String keyName, String group, ItemStack result, List ingredients, boolean[] exact, String category) { + ResourceKey> key = createRecipeKey(keyName); + ArrayList ingredientList = new ArrayList<>(); + CraftingBookCategory categoryValue = category == null ? CraftingBookCategory.MISC : CraftingBookCategory.valueOf(CoreUtilities.toUpperCase(category)); + for (int i = 0; i < ingredients.size(); i++) { + ingredientList.add(itemArrayToRecipe(ingredients.get(i), exact[i])); + } + ShapelessRecipe recipe = new ShapelessRecipe(BASE_RECIPE_INFO, new CraftingRecipe.CraftingBookInfo(categoryValue, group), asNMSTemplate(result), NonNullList.of(null, ingredientList.toArray(new Ingredient[0]))); + RecipeHolder holder = new RecipeHolder<>(key, recipe); + getRecipeManager().addRecipe(holder); + } + + public static final MethodHandle CRAFT_RECIPE_ADD_TO_MANAGER = Handler.reflectPaperRenamed(CraftRecipe.class, "addToCraftingManager", "addToRecipeManager"); + + @Override + public void registerOtherRecipe(org.bukkit.inventory.Recipe recipe) { + // This method copied from Bukkit CraftServer source, just to bypass unwanted paper patch + CraftRecipe toAdd; + if (recipe instanceof CraftRecipe craft) { + toAdd = craft; + } + else if (recipe instanceof ShapedRecipe) { + toAdd = CraftShapedRecipe.fromBukkitRecipe((ShapedRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.ShapelessRecipe) { + toAdd = CraftShapelessRecipe.fromBukkitRecipe((org.bukkit.inventory.ShapelessRecipe)recipe); + } + else if (recipe instanceof FurnaceRecipe) { + toAdd = CraftFurnaceRecipe.fromBukkitRecipe((FurnaceRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.BlastingRecipe) { + toAdd = CraftBlastingRecipe.fromBukkitRecipe((org.bukkit.inventory.BlastingRecipe)recipe); + } + else if (recipe instanceof CampfireRecipe) { + toAdd = CraftCampfireRecipe.fromBukkitRecipe((CampfireRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.SmokingRecipe) { + toAdd = CraftSmokingRecipe.fromBukkitRecipe((org.bukkit.inventory.SmokingRecipe)recipe); + } + else if (recipe instanceof StonecuttingRecipe) { + toAdd = CraftStonecuttingRecipe.fromBukkitRecipe((StonecuttingRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.SmithingTransformRecipe) { + toAdd = CraftSmithingTransformRecipe.fromBukkitRecipe((org.bukkit.inventory.SmithingTransformRecipe)recipe); + } + else if (recipe instanceof org.bukkit.inventory.SmithingTrimRecipe) { + toAdd = CraftSmithingTrimRecipe.fromBukkitRecipe((SmithingTrimRecipe)recipe); + } + else { + if (!(recipe instanceof org.bukkit.inventory.TransmuteRecipe)) { + if (recipe instanceof ComplexRecipe) { + throw new UnsupportedOperationException("Cannot add custom complex recipe"); + } + return; + } + toAdd = CraftTransmuteRecipe.fromBukkitRecipe((TransmuteRecipe)recipe); + } + try { + CRAFT_RECIPE_ADD_TO_MANAGER.invokeExact(toAdd); + } + catch (Throwable e) { + Debug.echoError(e); + } + } + + @Override + public String getJsonString(ItemStack itemStack) { + String json = CraftItemStack.asNMSCopy(itemStack).getDisplayName().getStyle().toString().replace("\\", "\\\\").replace("\"", "\\\""); + return json.substring(176, json.length() - 185); + } + + @Override + public JsonObject getRawHoverComponentsJson(ItemStack item) { + DataComponentPatch nmsComponents = CraftItemStack.asNMSCopy(item).getComponentsPatch(); + if (nmsComponents.isEmpty()) { + return null; + } + return DataComponentPatch.CODEC.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE), nmsComponents).getOrThrow().getAsJsonObject(); + } + + @Override + public ItemStack applyRawHoverComponentsJson(ItemStack item, JsonObject components) { + return DataComponentPatch.CODEC.parse(CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE), components).mapOrElse( + nmsComponents -> { + net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); + nmsItem.applyComponents(nmsComponents); + return CraftItemStack.asCraftMirror(nmsItem); + }, + error -> { + Debug.echoError("Invalid hover item data '" + components + "': " + error.message()); + return item; + }); + } + + @Override + public PlayerProfile getSkullSkin(ItemStack is) { + net.minecraft.world.item.ItemStack itemStack = CraftItemStack.asNMSCopy(is); + ResolvableProfile profile = itemStack.get(DataComponents.PROFILE); + if (profile != null) { + 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, + property != null ? property.signature() : null); + } + return null; + } + + @Override + public ItemStack setSkullSkin(ItemStack itemStack, PlayerProfile playerProfile) { + GameProfile gameProfile = ProfileEditorImpl.getGameProfile(playerProfile); + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); + nmsItemStack.set(DataComponents.PROFILE, ResolvableProfile.createResolved(gameProfile)); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + @Override + public ItemStack addNbtData(ItemStack itemStack, String key, BinaryTag value) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); + nmsItemStack.update(DataComponents.CUSTOM_DATA, CustomData.EMPTY, customData -> customData.update(nmsCompoundTag -> nmsCompoundTag.put(key, NBTAdapter.toNMS(value)))); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + // TODO: 1.20.6: this now needs to serialize components into NBT every single time, should probably only return custom NBT data with specialized methods for other usages + // TODO: 1.20.6: NBT structure is different basically everywhere, usages of this will need an update + @Override + public CompoundBinaryTag getNbtData(ItemStack itemStack) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); + if (nmsItemStack != null && !nmsItemStack.isEmpty()) { + return NBTAdapter.toAPI(serializeNmsItem(nmsItemStack)); + } + return CompoundBinaryTag.empty(); + } + + // TODO: 1.20.6: same as getNbtData, ideally needs to only set custom NBT data and have specialized methods for other usages + @Override + public ItemStack setNbtData(ItemStack itemStack, CompoundBinaryTag compoundTag) { + return CraftItemStack.asBukkitCopy(parseNmsItem(NBTAdapter.toNMS(compoundTag))); + } + + @Override + public CompoundBinaryTag getCustomData(ItemStack item) { + CustomData customData = CraftItemStack.asNMSCopy(item).get(DataComponents.CUSTOM_DATA); + return customData != null ? NBTAdapter.toAPI(customData.copyTag()) : null; + } + + @Override + public ItemStack setCustomData(ItemStack item, CompoundBinaryTag data) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + if (data == null) { + nmsItemStack.remove(DataComponents.CUSTOM_DATA); + } + else { + nmsItemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(NBTAdapter.toNMS(data))); + } + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + public static final int DATA_VERSION_1_20_4 = 3700; + + @Override + public ItemStack setPartialOldNbt(ItemStack item, CompoundBinaryTag oldTag) { + int currentDataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + CompoundTag nmsOldTag = new CompoundTag(); + nmsOldTag.putString("id", item.getType().getKey().toString()); + nmsOldTag.putByte("Count", (byte) item.getAmount()); + nmsOldTag.put("tag", NBTAdapter.toNMS(oldTag)); + CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, nmsOldTag), DATA_VERSION_1_20_4, currentDataVersion).getValue(); + CompoundTag nmsCurrentTag = serializeNmsItem(CraftItemStack.asNMSCopy(item)); + CompoundTag nmsMergedTag = nmsCurrentTag.merge(nmsUpdatedTag); + return CraftItemStack.asBukkitCopy(parseNmsItem(nmsMergedTag)); + } + + @Override + public CompoundBinaryTag getEntityData(ItemStack item) { + TypedEntityData> entityData = CraftItemStack.asNMSCopy(item).get(DataComponents.ENTITY_DATA); + return entityData != null ? NBTAdapter.toAPI(entityData.getUnsafe()) : null; + } + + @Override + public ItemStack setEntityData(ItemStack item, CompoundBinaryTag entityNbt, EntityType entityType) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + if (entityNbt == null || entityNbt.isEmpty() || (entityNbt.size() == 1 && entityNbt.contains("id"))) { + nmsItemStack.remove(DataComponents.ENTITY_DATA); + } + else { + CompoundTag nmsEntityNbt = NBTAdapter.toNMS(entityNbt); + nmsEntityNbt.remove("id"); + nmsItemStack.set(DataComponents.ENTITY_DATA, TypedEntityData.of(CraftEntityType.bukkitToMinecraft(entityType), nmsEntityNbt)); + } + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + @Override + public MapTag getRawComponentsPatch(ItemStack item, boolean excludeHandled) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + DataComponentPatch patch = nmsItemStack.getComponentsPatch(); + if (excludeHandled) { + patch = patch.forget(componentType -> { + Identifier componentId = BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(componentType); + return ItemComponentsPatch.propertyHandledComponents.contains(componentId.toString()); + }); + } + if (patch.isEmpty()) { + return new MapTag(); + } + RegistryOps registryOps = CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE); + CompoundTag nmsPatch = (CompoundTag) DataComponentPatch.CODEC.encodeStart(registryOps, patch).getOrThrow(); + if (excludeHandled && Denizen.supportsPaper) { + nmsPatch.keySet().removeIf(s -> s.charAt(0) == '!'); + if (nmsPatch.isEmpty()) { + return new MapTag(); + } + } + MapTag rawComponents = (MapTag) ItemRawNBT.nbtTagToObject(NBTAdapter.toAPI(nmsPatch)); + rawComponents.putObject(ItemComponentsPatch.DATA_VERSION_KEY, new ElementTag(CraftMagicNumbers.INSTANCE.getDataVersion())); + return rawComponents; + } + + @Override + public ItemStack setRawComponentsPatch(ItemStack item, MapTag rawComponentsMap, int dataVersion, Consumer errorHandler) { + int currentDataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + CompoundBinaryTag rawComponents = (CompoundBinaryTag) ItemRawNBT.convertObjectToNbt(rawComponentsMap, CoreUtilities.errorButNoDebugContext, ""); + CompoundTag nmsRawComponents = NBTAdapter.toNMS(rawComponents); + RegistryOps registryOps = CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE); + if (dataVersion < currentDataVersion) { + CompoundTag legacyItemData = new CompoundTag(); + legacyItemData.putString("id", item.getType().getKey().toString()); + legacyItemData.putInt("count", item.getAmount()); + legacyItemData.put("components", nmsRawComponents); + CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(registryOps, legacyItemData), dataVersion, currentDataVersion).getValue(); + nmsRawComponents = nmsUpdatedTag.getCompound("components").orElseGet(CompoundTag::new); + } + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + DataComponentPatch.CODEC.parse(registryOps, nmsRawComponents) + .ifError(error -> errorHandler.accept(error.message())) + .ifSuccess(nmsItemStack::applyComponents); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + public static final Field AdventureModePredicate_predicates = ReflectionHelper.getFields(AdventureModePredicate.class).get("predicates"); + + @Override + public List getCanPlaceOn(ItemStack item) { + return getAdventureModePredicateMaterials(item, DataComponents.CAN_PLACE_ON); + } + + @Override + public ItemStack setCanPlaceOn(ItemStack item, List canPlaceOn) { + return setAdventureModePredicateMaterials(item, DataComponents.CAN_PLACE_ON, canPlaceOn); + } + + @Override + public List getCanBreak(ItemStack item) { + return getAdventureModePredicateMaterials(item, DataComponents.CAN_BREAK); + } + + @Override + public ItemStack setCanBreak(ItemStack item, List canBreak) { + return setAdventureModePredicateMaterials(item, DataComponents.CAN_BREAK, canBreak); + } + + private List getAdventureModePredicateMaterials(ItemStack item, DataComponentType nmsComponent) { + AdventureModePredicate nmsAdventurePredicate = CraftItemStack.asNMSCopy(item).get(nmsComponent); + if (nmsAdventurePredicate == null) { + return null; + } + List nmsPredicates; + try { + nmsPredicates = (List) AdventureModePredicate_predicates.get(nmsAdventurePredicate); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + List materials = new ArrayList<>(); + for (BlockPredicate nmsPredicate : nmsPredicates) { + nmsPredicate.blocks().ifPresent(nmsHolderSet -> { + for (Holder nmsHolder : nmsHolderSet) { + materials.add(CraftMagicNumbers.getMaterial(nmsHolder.value())); + } + }); + } + return materials; + } + + private ItemStack setAdventureModePredicateMaterials(ItemStack item, DataComponentType nmsComponent, List materials) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); + AdventureModePredicate nmsAdventurePredicate = nmsItemStack.get(nmsComponent); + if (materials == null) { + if (nmsAdventurePredicate == null) { + return item; + } + nmsItemStack.remove(nmsComponent); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + BlockPredicate nmsPredicate = new BlockPredicate(Optional.of( + HolderSet.direct(material -> BuiltInRegistries.BLOCK.get(CraftNamespacedKey.toMinecraft(material.getKey())).orElseThrow(), materials) + ), Optional.empty(), Optional.empty(), DataComponentMatchers.ANY); + nmsItemStack.set(nmsComponent, new AdventureModePredicate(List.of(nmsPredicate))); + return CraftItemStack.asBukkitCopy(nmsItemStack); + } + + @Override + public void setInventoryItem(Inventory inventory, ItemStack item, int slot) { + if (inventory instanceof CraftInventoryPlayer && ((CraftInventoryPlayer) inventory).getInventory().player == null) { + ((CraftInventoryPlayer) inventory).getInventory().setItem(slot, CraftItemStack.asNMSCopy(item)); + } + else { + inventory.setItem(slot, item); + } + } + + @Override + public String getDisplayName(ItemTag item) { + if (!item.getItemMeta().hasDisplayName()) { + return null; + } + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); + Component nmsDisplayName = nmsItemStack.get(DataComponents.CUSTOM_NAME); + return FormattedTextHelper.stringify(Handler.componentToSpigot(nmsDisplayName)); + } + + @Override + public List getLore(ItemTag item) { + if (!item.getItemMeta().hasLore()) { + return null; + } + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); + ItemLore nmsLore = nmsItemStack.get(DataComponents.LORE); + List outList = new ArrayList<>(nmsLore.lines().size()); + for (Component nmsLoreLine : nmsLore.lines()) { + outList.add(FormattedTextHelper.stringify(Handler.componentToSpigot(nmsLoreLine))); + } + return outList; + } + + @Override + public void setDisplayName(ItemTag item, String name) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); + if (name == null || name.isEmpty()) { + nmsItemStack.remove(DataComponents.CUSTOM_NAME); + } + else { + nmsItemStack.set(DataComponents.CUSTOM_NAME, Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE))); + } + item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); + } + + @Override + public void setLore(ItemTag item, List lore) { + net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); + if (lore == null || lore.isEmpty()) { + nmsItemStack.remove(DataComponents.LORE); + } + else { + List nmsLore = new ArrayList<>(lore.size()); + for (String loreLine : lore) { + nmsLore.add(Handler.componentToNMS(FormattedTextHelper.parse(loreLine, ChatColor.WHITE))); + } + nmsItemStack.set(DataComponents.LORE, new ItemLore(nmsLore)); + } + item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); + } + + /** + * Copied from MapItem.getCorrectStateForFluidBlock. + */ + public static BlockState getCorrectStateForFluidBlock(Level world, BlockState blockState, BlockPos blockPos) { + FluidState fluid = blockState.getFluidState(); + return !fluid.isEmpty() && !blockState.isFaceSturdy(world, blockPos, Direction.UP) ? fluid.createLegacyBlock() : blockState; + } + + /** + * Copied from MapItem.update, redesigned slightly to render totally rather than just relative to a player. + * Some variables manually renamed for readability. + */ + public static void renderFullMap(MapItemSavedData worldmap, int xMin, int zMin, int xMax, int zMax) { + Level world = ((CraftWorld) worldmap.mapView.getWorld()).getHandle(); + int scale = 1 << worldmap.scale; + int mapX = worldmap.centerX; + int mapZ = worldmap.centerZ; + for (int x = xMin; x < xMax; x++) { + double d0 = 0.0D; + for (int z = zMin; z < zMax; z++) { + int k2 = (mapX / scale + x - 64) * scale; + int l2 = (mapZ / scale + z - 64) * scale; + Multiset multiset = LinkedHashMultiset.create(); + LevelChunk chunk = world.getChunkAt(new BlockPos(k2, 0, l2)); + if (!chunk.isEmpty()) { + ChunkPos chunkcoordintpair = chunk.getPos(); + int i3 = k2 & 15; + int j3 = l2 & 15; + int k3 = 0; + double d1 = 0.0D; + if (world.dimensionType().hasCeiling()) { + int l3 = k2 + l2 * 231871; + l3 = l3 * l3 * 31287121 + l3 * 11; + if ((l3 >> 20 & 1) == 0) { + multiset.add(Blocks.DIRT.defaultBlockState().getMapColor(world, BlockPos.ZERO), 10); + } + else { + multiset.add(Blocks.STONE.defaultBlockState().getMapColor(world, BlockPos.ZERO), 100); + } + + d1 = 100.0D; + } + else { + BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); + BlockPos.MutableBlockPos blockposition_mutableblockposition1 = new BlockPos.MutableBlockPos(); + for (int i4 = 0; i4 < scale; ++i4) { + for (int j4 = 0; j4 < scale; ++j4) { + int k4 = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i4 + i3, j4 + j3) + 1; + BlockState iblockdata; + if (k4 <= world.getMinY() + 1) { + iblockdata = Blocks.BEDROCK.defaultBlockState(); + } + else { + do { + --k4; + blockposition_mutableblockposition.set(chunkcoordintpair.getMinBlockX() + i4 + i3, k4, chunkcoordintpair.getMinBlockZ() + j4 + j3); + iblockdata = chunk.getBlockState(blockposition_mutableblockposition); + } while (iblockdata.getMapColor(world, blockposition_mutableblockposition) == MapColor.NONE && k4 > world.getMinY()); + if (k4 > world.getMinY() && !iblockdata.getFluidState().isEmpty()) { + int l4 = k4 - 1; + blockposition_mutableblockposition1.set(blockposition_mutableblockposition); + + BlockState iblockdata1; + do { + blockposition_mutableblockposition1.setY(l4--); + iblockdata1 = chunk.getBlockState(blockposition_mutableblockposition1); + k3++; + } while (l4 > world.getMinY() && !iblockdata1.getFluidState().isEmpty()); + iblockdata = getCorrectStateForFluidBlock(world, iblockdata, blockposition_mutableblockposition); + } + } + worldmap.checkBanners(world, chunkcoordintpair.getMinBlockX() + i4 + i3, chunkcoordintpair.getMinBlockZ() + j4 + j3); + d1 += (double) k4 / (double) (scale * scale); + multiset.add(iblockdata.getMapColor(world, blockposition_mutableblockposition)); + } + } + } + k3 /= scale * scale; + double d2 = (d1 - d0) * 4.0D / (double) (scale + 4) + ((double) (x + z & 1) - 0.5D) * 0.4D; + byte b0 = 1; + if (d2 > 0.6D) { + b0 = 2; + } + if (d2 < -0.6D) { + b0 = 0; + } + MapColor materialmapcolor = Iterables.getFirst(Multisets.copyHighestCountFirst(multiset), MapColor.NONE); + if (materialmapcolor == MapColor.WATER) { + d2 = (double) k3 * 0.1D + (double) (x + z & 1) * 0.2D; + b0 = 1; + if (d2 < 0.5D) { + b0 = 2; + } + if (d2 > 0.9D) { + b0 = 0; + } + } + d0 = d1; + worldmap.updateColor(x, z, (byte) (materialmapcolor.id * 4 + b0)); + } + } + } + } + + @Override + public boolean renderEntireMap(int mapId, int xMin, int zMin, int xMax, int zMax) { + MapItemSavedData worldmap = ((CraftServer) Bukkit.getServer()).getServer().getLevel(net.minecraft.world.level.Level.OVERWORLD).getMapData(new MapId(mapId)); + if (worldmap == null) { + return false; + } + renderFullMap(worldmap, xMin, zMin, xMax, zMax); + return true; + } + + @Override + public BlockData getPlacedBlock(Material material) { + Item nmsItem = BuiltInRegistries.ITEM.getOptional(CraftNamespacedKey.toMinecraft(material.getKey())).orElse(null); + if (nmsItem instanceof BlockItem) { + Block block = ((BlockItem) nmsItem).getBlock(); + return CraftBlockData.fromData(block.defaultBlockState()); + } + return null; + } + + @Override + public boolean isValidMix(ItemStack input, ItemStack ingredient) { + net.minecraft.world.item.ItemStack nmsInput = CraftItemStack.asNMSCopy(input); + net.minecraft.world.item.ItemStack nmsIngredient = CraftItemStack.asNMSCopy(ingredient); + return MinecraftServer.getServer().potionBrewing().hasMix(nmsInput, nmsIngredient); + } + + public static Class PaperPotionMix_CLASS = null; + public static Map customBrewingRecipes = null; + + @Override + public Map getCustomBrewingRecipes() { + if (customBrewingRecipes == null) { + customBrewingRecipes = Maps.transformValues((Map) ReflectionHelper.getFieldValue(PotionBrewing.class, "customMixes", MinecraftServer.getServer().potionBrewing()), paperMix -> { + if (PaperPotionMix_CLASS == null) { + PaperPotionMix_CLASS = paperMix.getClass(); + } + RecipeChoice ingredient = convertChoice(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "ingredient", paperMix)); + RecipeChoice input = convertChoice(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "input", paperMix)); + ItemStack result = CraftItemStack.asBukkitCopy(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "result", paperMix)); + return new BrewingRecipe(input, ingredient, result); + }); + } + return customBrewingRecipes; + } + + private RecipeChoice convertChoice(Predicate nmsPredicate) { + // Not an instance of net.minecraft.world.item.crafting.Ingredient = a predicate recipe choice + if (nmsPredicate instanceof Ingredient ingredient) { + return CraftRecipe.toBukkit(ingredient); + } + return PaperAPITools.instance.createPredicateRecipeChoice(item -> nmsPredicate.test(CraftItemStack.asNMSCopy(item))); + } + + @Override + public byte[] renderMap(MapView mapView, Player player) { + return ((CraftMapView) mapView).render((CraftPlayer) player).buffer; + } + + @Override + public int getFoodPoints(Material itemType) { + return CraftMagicNumbers.getItem(itemType).components().get(DataComponents.FOOD).nutrition(); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/NBTAdapter.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/NBTAdapter.java new file mode 100644 index 0000000000..9072903cba --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/NBTAdapter.java @@ -0,0 +1,143 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import net.kyori.adventure.nbt.*; +import net.minecraft.nbt.*; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NBTAdapter { + + public static final MethodHandle COMPOUND_TAG_MAP_CONSTRUCTOR = ReflectionHelper.getConstructor(CompoundTag.class, Map.class); + + public static Tag toNMS(BinaryTag tag) { + if (tag instanceof ByteBinaryTag byteTag) { + return switch (byteTag.value()) { + case 0 -> ByteTag.ZERO; + case 1 -> ByteTag.ONE; + default -> ByteTag.valueOf(byteTag.value()); + }; + } + else if (tag instanceof ShortBinaryTag shortTag) { + return ShortTag.valueOf(shortTag.value()); + } + else if (tag instanceof IntBinaryTag intTag) { + return IntTag.valueOf(intTag.value()); + } + else if (tag instanceof LongBinaryTag longTag) { + return LongTag.valueOf(longTag.value()); + } + else if (tag instanceof FloatBinaryTag floatTag) { + return FloatTag.valueOf(floatTag.value()); + } + else if (tag instanceof DoubleBinaryTag doubleTag) { + return DoubleTag.valueOf(doubleTag.value()); + } + else if (tag instanceof ByteArrayBinaryTag byteArrayTag) { + return new ByteArrayTag(byteArrayTag.value()); + } + else if (tag instanceof IntArrayBinaryTag intArrayTag) { + return new IntArrayTag(intArrayTag.value()); + } + else if (tag instanceof LongArrayBinaryTag longArrayTag) { + return new LongArrayTag(longArrayTag.value()); + } + else if (tag instanceof StringBinaryTag stringTag) { + return StringTag.valueOf(stringTag.value()); + } + else if (tag instanceof ListBinaryTag listTag) { + return toNMS(listTag); + } + else if (tag instanceof CompoundBinaryTag compoundTag) { + return toNMS(compoundTag); + } + else if (tag instanceof EndBinaryTag) { + return EndTag.INSTANCE; + } + throw new IllegalStateException("Unrecognized API tag of type '" + tag.type() + "': " + tag); + } + + public static BinaryTag toAPI(Tag nmsTag) { + if (nmsTag instanceof ByteTag nmsByteTag) { + return ByteBinaryTag.byteBinaryTag(nmsByteTag.value()); + } + else if (nmsTag instanceof ShortTag nmsShortTag) { + return ShortBinaryTag.shortBinaryTag(nmsShortTag.value()); + } + else if (nmsTag instanceof IntTag nmsIntTag) { + return IntBinaryTag.intBinaryTag(nmsIntTag.value()); + } + else if (nmsTag instanceof LongTag nmsLongTag) { + return LongBinaryTag.longBinaryTag(nmsLongTag.value()); + } + else if (nmsTag instanceof FloatTag nmsFloatTag) { + return FloatBinaryTag.floatBinaryTag(nmsFloatTag.value()); + } + else if (nmsTag instanceof DoubleTag nmsDoubleTag) { + return DoubleBinaryTag.doubleBinaryTag(nmsDoubleTag.value()); + } + else if (nmsTag instanceof ByteArrayTag nmsByteArrayTag) { + return ByteArrayBinaryTag.byteArrayBinaryTag(nmsByteArrayTag.getAsByteArray()); + } + else if (nmsTag instanceof IntArrayTag nmsIntArrayTag) { + return IntArrayBinaryTag.intArrayBinaryTag(nmsIntArrayTag.getAsIntArray()); + } + else if (nmsTag instanceof LongArrayTag nmsLongArrayTag) { + return LongArrayBinaryTag.longArrayBinaryTag(nmsLongArrayTag.getAsLongArray()); + } + else if (nmsTag instanceof StringTag nmsStringTag) { + return StringBinaryTag.stringBinaryTag(nmsStringTag.value()); + } + else if (nmsTag instanceof ListTag nmsListTag) { + return toAPI(nmsListTag); + } + else if (nmsTag instanceof CompoundTag nmsCompoundTag) { + return toAPI(nmsCompoundTag); + } + else if (nmsTag instanceof EndTag) { + return EndBinaryTag.endBinaryTag(); + } + throw new IllegalStateException("Unrecognized NMS tag of type '" + nmsTag.getClass().getName() + '/' + nmsTag.getType().getName() + "': " + nmsTag); + } + + public static ListBinaryTag toAPI(ListTag nmsListTag) { + ListBinaryTag.Builder builder = ListBinaryTag.heterogeneousListBinaryTag(nmsListTag.size()); + for (Tag nmsValue : nmsListTag) { + builder.add(toAPI(nmsValue)); + } + return builder.build(); + } + + public static ListTag toNMS(ListBinaryTag listTag) { + List nmsTags = new ArrayList<>(listTag.size()); + for (BinaryTag value : listTag) { + nmsTags.add(toNMS(value)); + } + return new ListTag(nmsTags); + } + + public static CompoundBinaryTag toAPI(CompoundTag nmsCompoundTag) { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(nmsCompoundTag.size()); + for (Map.Entry nmsEntry : nmsCompoundTag.entrySet()) { + builder.put(nmsEntry.getKey(), toAPI(nmsEntry.getValue())); + } + return builder.build(); + } + + public static CompoundTag toNMS(CompoundBinaryTag compoundTag) { + Map nmsTags = new HashMap<>(compoundTag.size()); + for (Map.Entry entry : compoundTag) { + nmsTags.put(entry.getKey(), toNMS(entry.getValue())); + } + try { + return (CompoundTag) COMPOUND_TAG_MAP_CONSTRUCTOR.invokeExact(nmsTags); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PacketHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PacketHelperImpl.java new file mode 100644 index 0000000000..38a889be6f --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PacketHelperImpl.java @@ -0,0 +1,433 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.interfaces.PacketHelper; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.SidebarImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizen.utilities.maps.MapImage; +import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; +import com.denizenscript.denizencore.objects.core.ColorTag; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.custom.BrandPayload; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.Relative; +import net.minecraft.world.entity.ai.attributes.AttributeInstance; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.monster.Creeper; +import net.minecraft.world.entity.monster.EnderMan; +import net.minecraft.world.entity.monster.spider.CaveSpider; +import net.minecraft.world.entity.monster.spider.Spider; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.scores.PlayerTeam; +import net.minecraft.world.scores.Team; +import org.bukkit.Bukkit; +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Sign; +import org.bukkit.block.sign.Side; +import org.bukkit.block.sign.SignSide; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.map.CraftMapCanvas; +import org.bukkit.craftbukkit.map.CraftMapView; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapPalette; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.*; + +public class PacketHelperImpl implements PacketHelper { + + public static final EntityDataAccessor PLAYER_DATA_ACCESSOR_ABSORPTION = ReflectionHelper.getFieldValue(net.minecraft.world.entity.player.Player.class, "DATA_PLAYER_ABSORPTION_ID", null); + + public static final EntityDataAccessor ENTITY_DATA_ACCESSOR_FLAGS = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, "DATA_SHARED_FLAGS_ID", null); + + public static final MethodHandle ABILITIES_PACKET_FOV_SETTER = ReflectionHelper.getFinalSetter(ClientboundPlayerAbilitiesPacket.class, "walkingSpeed"); + + public static final Field ENTITY_TRACKER_ENTRY_GETTER = ReflectionHelper.getFields(ChunkMap.TrackedEntity.class).getFirstOfType(ServerEntity.class); + + public static final MethodHandle CANVAS_GET_BUFFER = ReflectionHelper.getMethodHandle(CraftMapCanvas.class, "getBuffer"); + public static final Field MAPVIEW_WORLDMAP = ReflectionHelper.getFields(CraftMapView.class).get("worldMap"); + + public static final EntityDataAccessor> ENTITY_DATA_ACCESSOR_CUSTOM_NAME = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, "DATA_CUSTOM_NAME", null); + public static final EntityDataAccessor ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE = ReflectionHelper.getFieldValue(net.minecraft.world.entity.Entity.class, "DATA_CUSTOM_NAME_VISIBLE", null); + + @Override + public void setFakeAbsorption(Player player, float value) { + send(player, new ClientboundSetEntityDataPacket(player.getEntityId(), List.of(createEntityData(PLAYER_DATA_ACCESSOR_ABSORPTION, value)))); + } + + @Override + public void setSlot(Player player, int slot, ItemStack itemStack, boolean playerOnly) { + AbstractContainerMenu menu = ((CraftPlayer) player).getHandle().containerMenu; + int windowId = playerOnly ? 0 : menu.containerId; + send(player, new ClientboundContainerSetSlotPacket(windowId, menu.incrementStateId(), slot, CraftItemStack.asNMSCopy(itemStack))); + } + + @Override + public void setFieldOfView(Player player, float fov) { + ClientboundPlayerAbilitiesPacket packet = new ClientboundPlayerAbilitiesPacket(((CraftPlayer) player).getHandle().getAbilities()); + if (!Float.isNaN(fov)) { + try { + ABILITIES_PACKET_FOV_SETTER.invoke(packet, fov); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + send(player, packet); + } + + @Override + public void respawn(Player player) { + ((CraftPlayer) player).getHandle().connection.handleClientCommand(new ServerboundClientCommandPacket(ServerboundClientCommandPacket.Action.PERFORM_RESPAWN)); + } + + @Override + public void setVision(Player player, EntityType entityType) { + final net.minecraft.world.entity.LivingEntity entity; + if (entityType == EntityType.CREEPER) { + entity = new Creeper(net.minecraft.world.entity.EntityType.CREEPER, ((CraftWorld) player.getWorld()).getHandle()); + } + else if (entityType == EntityType.SPIDER) { + entity = new Spider(net.minecraft.world.entity.EntityType.SPIDER, ((CraftWorld) player.getWorld()).getHandle()); + } + else if (entityType == EntityType.CAVE_SPIDER) { + entity = new CaveSpider(net.minecraft.world.entity.EntityType.CAVE_SPIDER, ((CraftWorld) player.getWorld()).getHandle()); + } + else if (entityType == EntityType.ENDERMAN) { + entity = new EnderMan(net.minecraft.world.entity.EntityType.ENDERMAN, ((CraftWorld) player.getWorld()).getHandle()); + } + else { + return; + } + + // Spectating an entity then immediately respawning the player prevents a client shader update, + // allowing the player to retain whatever vision the mob they spectated had. + send(player, new ClientboundAddEntityPacket(entity, 0, BlockPos.ZERO)); + send(player, new ClientboundSetCameraPacket(entity)); + NMSHandler.playerHelper.refreshPlayer(player); + send(player, new ClientboundRemoveEntitiesPacket(entity.getId())); + } + + @Override + public void showBlockAction(Player player, Location location, int action, int state) { + BlockPos position = Handler.toBlockPos(location); + Block block = ((CraftWorld) location.getWorld()).getHandle().getBlockState(position).getBlock(); + send(player, new ClientboundBlockEventPacket(position, block, action, state)); + } + + @Override + public void showTabListHeaderFooter(Player player, String header, String footer) { + Component cHeader = Handler.componentToNMS(FormattedTextHelper.parse(header, ChatColor.WHITE)); + Component cFooter = Handler.componentToNMS(FormattedTextHelper.parse(footer, ChatColor.WHITE)); + send(player, new ClientboundTabListPacket(cHeader, cFooter)); + } + + @Override + public void showTitle(Player player, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { + send(player, new ClientboundBundlePacket(List.of( + new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks), + new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE))), + new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE))) + ))); + } + + @Override + public void showMobHealth(Player player, LivingEntity mob, double health, double maxHealth) { + AttributeInstance attr = new AttributeInstance(Attributes.MAX_HEALTH, (a) -> {}); + attr.setBaseValue(maxHealth); + send(player, new ClientboundUpdateAttributesPacket(mob.getEntityId(), List.of(attr))); + send(player, new ClientboundSetEntityDataPacket(mob.getEntityId(), List.of(createEntityData(net.minecraft.world.entity.LivingEntity.DATA_HEALTH_ID, (float) health)))); + } + + @Override + public void showSignEditor(Player player, Location location) { // TODO: MC 1.18: once 1.18 is removed, remove 'location' arg + NetworkInterceptHelper.enable(); + Sign sign = null; + BlockPos toOpen = null; + // It actually allows 8 blocks of distance, but we limit to 7 because the client doesn't properly round down + for (int i = 0; i < 8; i++) { + Location toCheck = player.getLocation(); + toCheck.setY(toCheck.getY() - i); + if (toCheck.getBlock().getState() instanceof Sign foundSign) { + sign = foundSign; + } + else { + sign = null; + toOpen = Handler.toBlockPos(toCheck); + break; + } + } + if (sign != null) { + toOpen = Handler.toBlockPos(sign.getLocation()); + SignSide front = sign.getSide(Side.FRONT); + for (int line = 0; line < 4; line++) { + front.setLine(line, ""); + } + player.sendBlockUpdate(sign.getLocation(), sign); + } + else { + player.sendBlockChange(new LocationTag(player.getWorld(), toOpen.getX(), toOpen.getY(), toOpen.getZ()), Material.OAK_WALL_SIGN.createBlockData()); + } + DenizenNetworkManagerImpl.getNetworkManager(player).packetListener.fakeSignExpected = toOpen; + send(player, new ClientboundOpenSignEditorPacket(toOpen, true)); + } + + @Override + public void forceSpectate(Player player, Entity entity) { + send(player, new ClientboundSetCameraPacket(((CraftEntity) entity).getHandle())); + } + + public static void forceRespawnPlayerEntity(Entity entity, Player viewer) { + ChunkMap tracker = ((ServerLevel) ((CraftEntity) entity).getHandle().level()).getChunkSource().chunkMap; + ChunkMap.TrackedEntity entityTracker = tracker.entityMap.get(entity.getEntityId()); + if (entityTracker != null) { + try { + ServerEntity entry = (ServerEntity) ENTITY_TRACKER_ENTRY_GETTER.get(entityTracker); + if (entry != null) { + entry.removePairing(((CraftPlayer) viewer).getHandle()); + entry.addPairing(((CraftPlayer) viewer).getHandle()); + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + } + + @Override + public void sendRename(Player player, Entity entity, String name, boolean listMode) { + try { + if (entity.getType() == EntityType.PLAYER) { + if (listMode) { + send(player, new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, ((CraftPlayer) player).getHandle())); + } + else { + // For player entities, force a respawn packet and let the dynamic intercept correct the details + forceRespawnPlayerEntity(entity, player); + } + return; + } + List> list = List.of( + createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE)))), + createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true) + ); + send(player, new ClientboundSetEntityDataPacket(entity.getEntityId(), list)); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public static HashMap> noCollideTeamMap = new HashMap<>(); + + @Override + public void generateNoCollideTeam(Player player, UUID noCollide) { + removeNoCollideTeam(player, noCollide); + PlayerTeam team = new PlayerTeam(SidebarImpl.dummyScoreboard, Utilities.generateRandomColors(8)); + team.getPlayers().add(noCollide.toString()); + team.setCollisionRule(Team.CollisionRule.NEVER); + HashMap map = noCollideTeamMap.computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()); + map.put(noCollide, team); + send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); + } + + @Override + public void removeNoCollideTeam(Player player, UUID noCollide) { + if (noCollide == null || !player.isOnline()) { + noCollideTeamMap.remove(player.getUniqueId()); + return; + } + HashMap map = noCollideTeamMap.get(player.getUniqueId()); + if (map == null) { + return; + } + PlayerTeam team = map.remove(noCollide); + if (team != null) { + send(player, ClientboundSetPlayerTeamPacket.createRemovePacket(team)); + } + if (map.isEmpty()) { + noCollideTeamMap.remove(player.getUniqueId()); + } + } + + @Override + public void sendEntityMetadataFlagsUpdate(Player player, Entity entity) { + byte flags = ((CraftEntity) entity).getHandle().getEntityData().get(ENTITY_DATA_ACCESSOR_FLAGS); + send(player, new ClientboundSetEntityDataPacket(entity.getEntityId(), List.of(createEntityData(ENTITY_DATA_ACCESSOR_FLAGS, flags)))); + } + + @Override + public void sendEntityEffect(Player player, Entity entity, EntityEffect effect) { + send(player, new ClientboundEntityEventPacket(((CraftEntity) entity).getHandle(), effect.getData())); + } + + @Override + public int getPacketStats(Player player, boolean sent) { + DenizenNetworkManagerImpl netMan = DenizenNetworkManagerImpl.getNetworkManager(player); + return sent ? netMan.packetsSent : netMan.packetsReceived; + } + + @Override + public void setMapData(MapCanvas canvas, byte[] bytes, int x, int y, MapImage image) { + if (x > 127 || y > 127) { + return; + } + int width = Math.min(image.width, 128 - x), + height = Math.min(image.height, 128 - y); + if (x + width <= 0 || y + height <= 0) { + return; + } + try { + boolean anyChanged = false; + byte[] buffer = (byte[]) CANVAS_GET_BUFFER.invoke(canvas); + for (int x2 = x < 0 ? -x : 0; x2 < width; ++x2) { + for (int y2 = y < 0 ? -y : 0; y2 < height; ++y2) { + byte p = bytes[y2 * image.width + x2]; + if (p != MapPalette.TRANSPARENT) { + int index = (y2 + y) * 128 + (x2 + x); + if (buffer[index] != p) { + buffer[index] = p; + anyChanged = true; + } + } + } + } + if (anyChanged) { + // Flag the whole image as dirty + MapItemSavedData map = (MapItemSavedData) MAPVIEW_WORLDMAP.get(canvas.getMapView()); + map.setColorsDirty(Math.max(x, 0), Math.max(y, 0)); + map.setColorsDirty(width + x - 1, height + y - 1); + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void setNetworkManagerFor(Player player) { + DenizenNetworkManagerImpl.setNetworkManager(player); + } + + @Override + public void enableNetworkManager() { + DenizenNetworkManagerImpl.enableNetworkManager(); + } + + @Override + public void showDebugTestMarker(Player player, Location location, ColorTag color, String name, int time) { + BlockPos nmsPos = Handler.toBlockPos(location); + LocationTag displayPos = !name.isEmpty() ? LocationTag.valueOf(name, CoreUtilities.noDebugContext) : null; + send(player, new ClientboundGameTestHighlightPosPacket(nmsPos, displayPos != null ? Handler.toBlockPos(displayPos) : nmsPos)); + } + + @Override + public void clearDebugTestMarker(Player player) { + } + + @Override + public void sendBrand(Player player, String brand) { + BrandPayload payload = new BrandPayload(brand); + send(player, new ClientboundCustomPayloadPacket(payload)); + } + + @Override + public void sendCollectItemEntity(Player player, Entity taker, Entity item, int amount) { + send(player, new ClientboundTakeItemEntityPacket(item.getEntityId(), taker.getEntityId(), amount)); + } + + public Relative toNmsRelativeMovement(TeleportCommand.Relative relative) { + // TODO: 1.21.3: There seem to be more relative movement types now + return switch (relative) { + case X -> Relative.X; + case Y -> Relative.Y; + case Z -> Relative.Z; + case YAW -> Relative.Y_ROT; + case PITCH -> Relative.X_ROT; + }; + } + + @Override + public void sendRelativePositionPacket(Player player, double x, double y, double z, float yaw, float pitch, List relativeAxis) { + Set relativeMovements; + if (relativeAxis == null) { + relativeMovements = Relative.ALL; + } + else { + relativeMovements = EnumSet.noneOf(Relative.class); + for (TeleportCommand.Relative relative : relativeAxis) { + relativeMovements.add(toNmsRelativeMovement(relative)); + } + } + ClientboundPlayerPositionPacket packet = new ClientboundPlayerPositionPacket(0, new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yaw, pitch), relativeMovements); + sendAsyncSafe(player, packet); + } + + @Override + public void sendRelativeLookPacket(Player player, float yaw, float pitch) { + sendRelativePositionPacket(player, 0, 0, 0, yaw, pitch, null); + } + + @Override + public void sendEntityDataPacket(List players, Entity entity, List data) { + ClientboundSetEntityDataPacket setEntityDataPacket = new ClientboundSetEntityDataPacket(entity.getEntityId(), (List>) (Object) data); + Iterator playerIterator = players.iterator(); + while (playerIterator.hasNext()) { + Player player = playerIterator.next(); + if (!DenizenNetworkManagerImpl.getConnection(player).isConnected()) { + playerIterator.remove(); + continue; + } + sendAsyncSafe(player, setEntityDataPacket); + } + } + + public static void send(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().connection.send(packet); + } + + public static void broadcast(Packet packet) { + ((CraftServer) Bukkit.getServer()).getHandle().broadcastAll(packet); + } + + public static void sendAsyncSafe(Player player, Packet packet) { + DenizenNetworkManagerImpl.getConnection(player).channel.writeAndFlush(packet); + } + + public static SynchedEntityData.DataValue createEntityData(EntityDataAccessor accessor, T value) { + return new SynchedEntityData.DataValue<>(accessor.id(), accessor.serializer(), value); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PlayerHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PlayerHelperImpl.java new file mode 100644 index 0000000000..0760d3bbee --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PlayerHelperImpl.java @@ -0,0 +1,508 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.abstracts.ImprovedOfflinePlayer; +import com.denizenscript.denizen.nms.enums.CustomEntityType; +import com.denizenscript.denizen.nms.interfaces.PlayerHelper; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.ImprovedOfflinePlayerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.CraftFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityItemProjectileImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.AbstractListenerPlayInImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.EntityTag; +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.entity.DenizenEntityType; +import com.denizenscript.denizen.utilities.entity.FakeEntity; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.mojang.authlib.GameProfile; +import it.unimi.dsi.fastutil.ints.IntList; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; +import net.minecraft.network.protocol.game.*; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +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.ServerGamePacketListenerImpl; +import net.minecraft.server.players.NameAndId; +import net.minecraft.server.players.PlayerList; +import net.minecraft.server.players.ServerOpList; +import net.minecraft.server.players.ServerOpListEntry; +import net.minecraft.stats.ServerRecipeBook; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.TagNetworkSerialization; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Avatar; +import net.minecraft.world.entity.Leashable; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.item.ItemCooldowns; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.LevelData; +import net.minecraft.world.phys.AABB; +import org.bukkit.*; +import org.bukkit.boss.BossBar; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.boss.CraftBossBar; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Predicate; + +public class PlayerHelperImpl extends PlayerHelper { + + public static final Field ATTACK_COOLDOWN_TICKS = ReflectionHelper.getFields(LivingEntity.class).get("attackStrengthTicker", int.class); + + public static final Field FLY_TICKS = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("aboveGroundTickCount", int.class); + public static final Field VEHICLE_FLY_TICKS = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("aboveGroundVehicleTickCount", int.class); + public static final Field PASSENGERS_PACKET_PASSENGERS = ReflectionHelper.getFields(ClientboundSetPassengersPacket.class).get("passengers", int[].class); + public static final MethodHandle PLAYER_RESPAWNCONFIG_SETTER = ReflectionHelper.getFinalSetter(ServerPlayer.class, "respawnConfig", ServerPlayer.RespawnConfig.class); + public static final MethodHandle SERVER_RECIPE_BOOK_ADD_HIGHLIGHT = ReflectionHelper.getMethodHandle(ServerRecipeBook.class, "addHighlight", ResourceKey.class); + + @Override + public void stopSound(Player player, NamespacedKey sound, SoundCategory category) { + ((CraftPlayer) player).getHandle().connection.send(new ClientboundStopSoundPacket(sound == null ? null : CraftNamespacedKey.toMinecraft(sound), null)); + } + + @Override + public void deTrackEntity(Player player, Entity entity) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ChunkMap.TrackedEntity tracker = nmsPlayer.level().getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); + if (tracker == null) { + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Failed to de-track entity " + entity.getEntityId() + " for " + player.getName() + ": tracker null"); + } + return; + } + sendEntityDestroy(player, entity); + tracker.removePlayer(nmsPlayer); + } + + public record TrackerData(PlayerTag player, ServerEntity tracker) {} + + @Override + public void addFakePassenger(List players, Entity vehicle, FakeEntity fakePassenger) { + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(((CraftEntity) vehicle).getHandle()); + int[] newPassengers = Arrays.copyOf(packet.getPassengers(), packet.getPassengers().length + 1); + newPassengers[packet.getPassengers().length] = fakePassenger.id; + try { + PASSENGERS_PACKET_PASSENGERS.set(packet, newPassengers); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + for (PlayerTag player : players) { + PacketHelperImpl.send(player.getPlayerEntity(), packet); + } + } + + public record FakeEntitySynchronizer(ServerGamePacketListenerImpl target) implements ServerEntity.Synchronizer { + + @Override + public void sendToTrackingPlayers(Packet packet) { + target.send(packet); + } + + @Override + public void sendToTrackingPlayersAndSelf(Packet packet) { + sendToTrackingPlayers(packet); + } + + @Override + public void sendToTrackingPlayersFiltered(Packet packet, Predicate predicate) { + if (predicate.test(target.getPlayer())) { + sendToTrackingPlayers(packet); + } + } + + @Override + public void sendToTrackingPlayersFilteredAndSelf(Packet packet, Predicate predicate) { + sendToTrackingPlayersFiltered(packet, predicate); + } + } + + @Override + public FakeEntity sendEntitySpawn(List players, DenizenEntityType entityType, LocationTag location, ArrayList mechanisms, int customId, UUID customUUID, boolean autoTrack) { + CraftWorld world = ((CraftWorld) location.getWorld()); + net.minecraft.world.entity.Entity nmsEntity; + if (entityType.isCustom()) { + if (entityType.customEntityType == CustomEntityType.ITEM_PROJECTILE) { + ItemStack itemStack = new ItemStack(Material.STONE); + for (Mechanism mechanism : mechanisms) { + if (mechanism.matches("item") && mechanism.requireObject(ItemTag.class)) { + itemStack = mechanism.valueAsType(ItemTag.class).getItemStack(); + } + } + nmsEntity = new EntityItemProjectileImpl(world.getHandle(), location, CraftItemStack.asNMSCopy(itemStack)); + } + else if (entityType.customEntityType == CustomEntityType.FAKE_PLAYER) { + String name = null; + String skin = null; + String blob = null; + for (Mechanism mechanism : new ArrayList<>(mechanisms)) { + if (mechanism.matches("name")) { + name = mechanism.getValue().asString(); + mechanisms.remove(mechanism); + } + else if (mechanism.matches("skin")) { + skin = mechanism.getValue().asString(); + mechanisms.remove(mechanism); + } + else if (mechanism.matches("skin_blob")) { + blob = mechanism.getValue().asString(); + mechanisms.remove(mechanism); + } + if (name != null && (skin != null || blob != null)) { + break; + } + } + nmsEntity = ((CraftFakePlayerImpl) NMSHandler.customEntityHelper.spawnFakePlayer(location, name, skin, blob, false)).getHandle(); + } + else { + throw new IllegalArgumentException("entityType"); + } + } + else { + org.bukkit.entity.Entity entity = world.createEntity(location, entityType.getBukkitEntityType().getEntityClass()); + nmsEntity = ((CraftEntity) entity).getHandle(); + } + if (customUUID != null) { + nmsEntity.setId(customId); + nmsEntity.setUUID(customUUID); + } + EntityTag entity = new EntityTag(nmsEntity.getBukkitEntity()); + entity.isFake = true; + entity.isFakeValid = true; + for (Mechanism mechanism : mechanisms) { + entity.safeAdjustDuplicate(mechanism); + } + nmsEntity.unsetRemoved(); + FakeEntity fake = new FakeEntity(players, location, entity.getBukkitEntity().getEntityId()); + fake.entity = new EntityTag(entity.getBukkitEntity()); + fake.entity.isFake = true; + fake.entity.isFakeValid = true; + List trackers = new ArrayList<>(); + fake.triggerSpawnPacket = (player) -> { + ServerPlayer nmsPlayer = ((CraftPlayer) player.getPlayerEntity()).getHandle(); + ServerGamePacketListenerImpl conn = nmsPlayer.connection; + final ServerEntity tracker = new ServerEntity(world.getHandle(), nmsEntity, 1, true, new FakeEntitySynchronizer(conn), Set.of(conn)); + tracker.addPairing(nmsPlayer); + final TrackerData data = new TrackerData(player, tracker); + trackers.add(data); + if (autoTrack) { + new BukkitRunnable() { + boolean wasOnline = true; + @Override + public void run() { + if (!fake.entity.isFakeValid) { + cancel(); + return; + } + if (player.isOnline()) { + if (!wasOnline) { + tracker.addPairing(((CraftPlayer) player.getPlayerEntity()).getHandle()); + wasOnline = true; + } + tracker.sendChanges(); + } + else if (wasOnline) { + wasOnline = false; + } + } + }.runTaskTimer(Denizen.getInstance(), 1, 1); + } + }; + for (PlayerTag player : players) { + fake.triggerSpawnPacket.accept(player); + } + fake.triggerUpdatePacket = () -> { + for (TrackerData tracker : trackers) { + if (tracker.player.isOnline()) { + tracker.tracker.sendChanges(); + } + } + }; + fake.triggerDestroyPacket = () -> { + for (TrackerData tracker : trackers) { + if (tracker.player.isOnline()) { + tracker.tracker.removePairing(((CraftPlayer) tracker.player.getPlayerEntity()).getHandle()); + } + } + trackers.clear(); + }; + return fake; + } + + @Override + public void sendEntityDestroy(Player player, Entity entity) { + ((CraftPlayer) player).getHandle().connection.send(new ClientboundRemoveEntitiesPacket(entity.getEntityId())); + } + + @Override + public int getFlyKickCooldown(Player player) { + ServerGamePacketListenerImpl conn = ((CraftPlayer) player).getHandle().connection; + if (conn instanceof AbstractListenerPlayInImpl denizenListener) { + conn = denizenListener.oldListener; + } + try { + return Math.max(80 - Math.max(FLY_TICKS.getInt(conn), VEHICLE_FLY_TICKS.getInt(conn)), 0); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + return 80; + } + + @Override + public void setFlyKickCooldown(Player player, int ticks) { + ticks = 80 - ticks; + ServerGamePacketListenerImpl conn = ((CraftPlayer) player).getHandle().connection; + if (conn instanceof AbstractListenerPlayInImpl denizenListener) { + conn = denizenListener.oldListener; + } + try { + FLY_TICKS.setInt(conn, ticks); + VEHICLE_FLY_TICKS.setInt(conn, ticks); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + } + + @Override + public int ticksPassedDuringCooldown(Player player) { + try { + return ATTACK_COOLDOWN_TICKS.getInt(((CraftPlayer) player).getHandle()); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + return -1; + } + + @Override + public float getMaxAttackCooldownTicks(Player player) { + return ((CraftPlayer) player).getHandle().getCurrentItemAttackStrengthDelay() + 3; + } + + @Override + public void setAttackCooldown(Player player, int ticks) { + try { + ATTACK_COOLDOWN_TICKS.setInt(((CraftPlayer) player).getHandle(), ticks); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + + } + + @Override + public boolean hasChunkLoaded(Player player, Chunk chunk) { + return ((CraftWorld) chunk.getWorld()).getHandle().getChunkSource().chunkMap + .getPlayers(new ChunkPos(chunk.getX(), chunk.getZ()), false).stream() + .anyMatch(entityPlayer -> entityPlayer.getUUID().equals(player.getUniqueId())); + } + + @Override + public void setTemporaryOp(Player player, boolean op) { + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + NameAndId nameAndId = new NameAndId(((CraftPlayer) player).getProfile()); + ServerOpList opList = server.getPlayerList().getOps(); + if (op) { + opList.add(new ServerOpListEntry(nameAndId, server.operatorUserPermissions(), opList.canBypassPlayerLimit(nameAndId))); + } + else { + opList.remove(nameAndId); + } + player.recalculatePermissions(); + } + + @Override + public void showEndCredits(Player player) { + ((CraftPlayer) player).getHandle().wonGame = true; + ((CraftPlayer) player).getHandle().connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1f)); + } + + @Override + public ImprovedOfflinePlayer getOfflineData(UUID uuid) { + return new ImprovedOfflinePlayerImpl(uuid); + } + + @Override + public void resendRecipeDetails(Player player) { + RecipeManager recipeManager = ((CraftServer) Bukkit.getServer()).getServer().getRecipeManager(); + ClientboundUpdateRecipesPacket updatePacket = new ClientboundUpdateRecipesPacket(recipeManager.getSynchronizedItemProperties(), recipeManager.getSynchronizedStonecutterRecipes()); + ((CraftPlayer) player).getHandle().connection.send(updatePacket); + } + + @Override + public void resendDiscoveredRecipes(Player player) { + ServerRecipeBook recipeBook = ((CraftPlayer) player).getHandle().getRecipeBook(); + recipeBook.sendInitialRecipeBook(((CraftPlayer) player).getHandle()); + } + + @Override + public void quietlyAddRecipe(Player player, NamespacedKey key) { + ServerRecipeBook recipeBook = ((CraftPlayer) player).getHandle().getRecipeBook(); + RecipeHolder recipe = ItemHelperImpl.getNMSRecipe(key); + if (recipe == null) { + Debug.echoError("Cannot add recipe '" + key + "': it does not exist."); + return; + } + recipeBook.add(recipe.id()); + try { + SERVER_RECIPE_BOOK_ADD_HIGHLIGHT.invoke(recipeBook, recipe.id()); + } + catch (Throwable e) { + Debug.echoError(e); + } + } + + @Override + public byte getSkinLayers(Player player) { + return ((CraftPlayer) player).getHandle().getEntityData().get(Avatar.DATA_PLAYER_MODE_CUSTOMISATION); + } + + @Override + public void setSkinLayers(Player player, byte flags) { + ((CraftPlayer) player).getHandle().getEntityData().set(Avatar.DATA_PLAYER_MODE_CUSTOMISATION, flags); + } + + @Override + public void setBossBarTitle(BossBar bar, String title) { + ((CraftBossBar) bar).getHandle().name = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + ((CraftBossBar) bar).getHandle().broadcast(ClientboundBossEventPacket::createUpdateNamePacket); + } + + @Override + public boolean getSpawnForced(Player player) { + return ((CraftPlayer) player).getHandle().getRespawnConfig().forced(); + } + + @Override + public void setSpawnForced(Player player, boolean forced) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + try { + ServerPlayer.RespawnConfig config = nmsPlayer.getRespawnConfig(); + config = new ServerPlayer.RespawnConfig(config.respawnData(), forced); + PLAYER_RESPAWNCONFIG_SETTER.invoke(nmsPlayer, config); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public Location getBedSpawnLocation(Player player) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ServerPlayer.RespawnConfig nmsRespawnConfig = nmsPlayer.getRespawnConfig(); + if (nmsRespawnConfig == null) { + return null; + } + LevelData.RespawnData nmsRespawnData = nmsRespawnConfig.respawnData(); + Level nmsWorld = MinecraftServer.getServer().getLevel(nmsRespawnData.dimension()); + return nmsWorld != null ? new Location(nmsWorld.getWorld(), nmsRespawnData.pos().getX(), nmsRespawnData.pos().getY(), nmsRespawnData.pos().getZ(), nmsRespawnData.yaw(), nmsRespawnData.pitch()) : null; + } + + @Override + public long getLastActionTime(Player player) { + return ((CraftPlayer) player).getHandle().getLastActionTime(); + } + + @Override + public void sendPlayerInfoAddPacket(Player player, EnumSet editModes, String name, String display, UUID id, String texture, String signature, int latency, GameMode gameMode, boolean listed) { + EnumSet actions = EnumSet.noneOf(ClientboundPlayerInfoUpdatePacket.Action.class); + for (ProfileEditMode editMode : editModes) { + actions.add(switch (editMode) { + case ADD -> ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER; + case UPDATE_DISPLAY -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME; + case UPDATE_LATENCY -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY; + case UPDATE_GAME_MODE -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE; + case UPDATE_LISTED -> ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED; + }); + } + GameProfile profile = ProfileEditorImpl.createGameProfile(id, name, texture, signature); + // TODO: 1.21.3: Player list order and hat visibility support + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(display, ChatColor.WHITE)), true, player.getPlayerListOrder(), null); + PacketHelperImpl.send(player, ProfileEditorImpl.createInfoPacket(actions, List.of(entry))); + } + + @Override + public void sendPlayerInfoRemovePacket(Player player, UUID id) { + PacketHelperImpl.send(player, new ClientboundPlayerInfoRemovePacket(List.of(id))); + } + + @Override + public void sendClimbableMaterials(Player player, List materials) { + Map>, TagNetworkSerialization.NetworkPayload> packetInput = TagNetworkSerialization.serializeTagsToNetwork(((CraftServer) Bukkit.getServer()).getServer().registries()); + Map tags = ReflectionHelper.getFieldValue(TagNetworkSerialization.NetworkPayload.class, "tags", packetInput.get(BuiltInRegistries.BLOCK.key())); + IntList climbableBlocks = tags.get(BlockTags.CLIMBABLE.location()); + climbableBlocks.clear(); + for (Material material : materials) { + climbableBlocks.add(BuiltInRegistries.BLOCK.getId(CraftMagicNumbers.getBlock(material))); + } + PacketHelperImpl.send(player, new ClientboundUpdateTagsPacket(packetInput)); + } + + @Override + public void refreshPlayer(Player player) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ServerLevel nmsWorld = nmsPlayer.level(); + nmsPlayer.connection.send(new ClientboundRespawnPacket(nmsPlayer.createCommonSpawnInfo(nmsWorld), ClientboundRespawnPacket.KEEP_ALL_DATA)); + nmsPlayer.connection.internalTeleport(PositionMoveRotation.of(nmsPlayer), Set.of()); + if (nmsPlayer.isPassenger()) { + nmsPlayer.connection.send(new ClientboundSetPassengersPacket(nmsPlayer.getVehicle())); + } + if (nmsPlayer.isVehicle()) { + nmsPlayer.connection.send(new ClientboundSetPassengersPacket(nmsPlayer)); + } + AABB boundingBox = AABB.ofSize(nmsPlayer.getBoundingBox().getCenter(), 32, 32, 32); + for (net.minecraft.world.entity.Entity nmsEntity : nmsWorld.getEntitiesOfClass(net.minecraft.world.entity.Entity.class, boundingBox, nmsEntity -> nmsEntity instanceof Leashable nmsLeashable && nmsPlayer.equals(nmsLeashable.getLeashHolder()))) { + nmsPlayer.connection.send(new ClientboundSetEntityLinkPacket(nmsEntity, nmsPlayer)); + } + if (!nmsPlayer.getCooldowns().cooldowns.isEmpty()) { + int tickCount = nmsPlayer.getCooldowns().tickCount; + for (Map.Entry entry : nmsPlayer.getCooldowns().cooldowns.entrySet()) { + nmsPlayer.connection.send(new ClientboundCooldownPacket(entry.getKey(), entry.getValue().endTime - tickCount)); + } + } + nmsPlayer.connection.send(new ClientboundSetExperiencePacket(nmsPlayer.experienceProgress, nmsPlayer.totalExperience, nmsPlayer.experienceLevel)); + for (MobEffectInstance nmsEffect : nmsPlayer.getActiveEffects()) { + nmsPlayer.connection.send(new ClientboundUpdateMobEffectPacket(nmsPlayer.getId(), nmsEffect, false)); + } + nmsPlayer.onUpdateAbilities(); + PlayerList nmsPlayerList = MinecraftServer.getServer().getPlayerList(); + nmsPlayerList.sendPlayerPermissionLevel(nmsPlayer); + nmsPlayerList.sendLevelInfo(nmsPlayer, nmsWorld); + nmsPlayerList.sendAllPlayerInfo(nmsPlayer); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/WorldHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/WorldHelperImpl.java new file mode 100644 index 0000000000..ce84fabd38 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/WorldHelperImpl.java @@ -0,0 +1,103 @@ +package com.denizenscript.denizen.nms.v26_1.helpers; + +import com.denizenscript.denizen.nms.interfaces.WorldHelper; +import com.denizenscript.denizen.nms.v26_1.impl.BiomeNMSImpl; +import com.denizenscript.denizen.objects.BiomeTag; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.mojang.datafixers.util.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.players.SleepStatus; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.event.world.TimeSkipEvent; + +public class WorldHelperImpl implements WorldHelper { + + @Override + public boolean isStatic(World world) { + return ((CraftWorld) world).getHandle().isClientSide(); + } + + @Override + public void setStatic(World world, boolean isStatic) { + ServerLevel worldServer = ((CraftWorld) world).getHandle(); + ReflectionHelper.setFieldValue(net.minecraft.world.level.Level.class, "isClientSide", worldServer, isStatic); + } + + @Override + public float getLocalDifficulty(Location location) { + BlockPos pos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + DifficultyInstance scaler = ((CraftWorld) location.getWorld()).getHandle().getCurrentDifficultyAt(pos); + return scaler.getEffectiveDifficulty(); + } + + @Override + public Location getNearestBiomeLocation(Location start, BiomeTag biome) { + Pair> result = ((CraftWorld) start.getWorld()).getHandle() + .findClosestBiome3d(b -> b.is(((BiomeNMSImpl) biome.getBiome()).biomeHolder.unwrapKey().get()), new BlockPos(start.getBlockX(), start.getBlockY(), start.getBlockZ()), 6400, 32, 64); + if (result == null || result.getFirst() == null) { + return null; + } + return new Location(start.getWorld(), result.getFirst().getX(), result.getFirst().getY(), result.getFirst().getZ()); + } + + @Override + public boolean areEnoughSleeping(World world, int percentage) { + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, "sleepStatus", ((CraftWorld) world).getHandle()); + return status.areEnoughSleeping(percentage); + } + + @Override + public boolean areEnoughDeepSleeping(World world, int percentage) { + ServerLevel level = ((CraftWorld) world).getHandle(); + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, "sleepStatus", level); + return status.areEnoughDeepSleeping(percentage, level.players()); + } + + @Override + public int getSkyDarken(World world) { + return ((CraftWorld) world).getHandle().getSkyDarken(); + } + + @Override + public boolean isDay(World world) { + return ((CraftWorld) world).getHandle().isBrightOutside(); + } + + @Override + public boolean isNight(World world) { + return ((CraftWorld) world).getHandle().isDarkOutside(); + } + + @Override + public void setDayTime(World world, long time) { + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + nmsWorld.dimensionType().defaultClock().ifPresent((clock) -> nmsWorld.clockManager().setTotalTicks(clock, time, TimeSkipEvent.SkipReason.CUSTOM)); + } + + @Override + public void setGameTime(World world, long time) { + ((PrimaryLevelData) ((CraftWorld) world).getHandle().levelData).setGameTime(time); + } + + // net.minecraft.server.level.ServerLevel#wakeUpAllPlayers() + @Override + public void wakeUpAllPlayers(World world) { + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + SleepStatus status = ReflectionHelper.getFieldValue(ServerLevel.class, "sleepStatus", nmsWorld); + status.removeAllSleepers(); + nmsWorld.getPlayers(LivingEntity::isSleeping).forEach((player) -> player.stopSleepInBed(false, false)); + } + + @Override + public void clearWeather(World world) { + ((CraftWorld) world).getHandle().resetWeatherCycle(); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/BiomeNMSImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/BiomeNMSImpl.java new file mode 100644 index 0000000000..47e5afc040 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/BiomeNMSImpl.java @@ -0,0 +1,241 @@ +package com.denizenscript.denizen.nms.v26_1.impl; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.abstracts.BiomeNMS; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.RegistrationInfo; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.random.Weighted; +import net.minecraft.util.random.WeightedList; +import net.minecraft.world.attribute.EnvironmentAttribute; +import net.minecraft.world.attribute.EnvironmentAttributeMap; +import net.minecraft.world.attribute.EnvironmentAttributes; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSpecialEffects; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.EntityType; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class BiomeNMSImpl extends BiomeNMS { + + public static final MethodHandle BIOME_CLIMATESETTINGS_CONSTRUCTOR = ReflectionHelper.getConstructor(Biome.ClimateSettings.class, boolean.class, float.class, Biome.TemperatureModifier.class, float.class); + public static final MethodHandle MAPPED_REGISTRY_REGISTRATION_INFOS = ReflectionHelper.getFields(MappedRegistry.class).getGetter("registrationInfos"); + public static final MethodHandle BIOME_ATTRIBUTES_SETTER = ReflectionHelper.getFields(Biome.class).getSetter("attributes"); + + public Holder.Reference biomeHolder; + public ServerLevel world; + + public BiomeNMSImpl(ServerLevel world, NamespacedKey key) { + super(world.getWorld(), key); + this.world = world; + this.biomeHolder = getBiomeRegistry().get(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(key))).orElse(null); + } + + private MappedRegistry getBiomeRegistry() { + return (MappedRegistry) world.registryAccess().lookupOrThrow(Registries.BIOME); + } + + @Override + public DownfallType getDownfallTypeAt(Location location) { + Biome.Precipitation precipitation = biomeHolder.value().getPrecipitationAt(Handler.toBlockPos(location), world.getSeaLevel()); + return switch (precipitation) { + case RAIN -> DownfallType.RAIN; + case SNOW -> DownfallType.SNOW; + case NONE -> DownfallType.NONE; + }; + } + + @Override + public float getHumidity() { + return biomeHolder.value().climateSettings.downfall(); + } + + @Override + public float getBaseTemperature() { + return biomeHolder.value().getBaseTemperature(); + } + + @Override + public float getTemperatureAt(Location location) { + return biomeHolder.value().getTemperature(Handler.toBlockPos(location), world.getSeaLevel()); + } + + @Override + public boolean hasDownfall() { + return biomeHolder.value().hasPrecipitation(); + } + + @Override + public List getAmbientEntities() { + return getSpawnableEntities(MobCategory.AMBIENT); + } + + @Override + public List getCreatureEntities() { + return getSpawnableEntities(MobCategory.CREATURE); + } + + @Override + public List getMonsterEntities() { + return getSpawnableEntities(MobCategory.MONSTER); + } + + @Override + public List getWaterEntities() { + return getSpawnableEntities(MobCategory.WATER_CREATURE); + } + + @Override + public int getFoliageColor() { + // Check if the biome already has a default color + if (biomeHolder.value().getFoliageColor() != 0) { + return biomeHolder.value().getFoliageColor(); + } + // Based on net.minecraft.world.level.biome.Biome#getFoliageColorFromTexture() + float temperature = clampColor(getBaseTemperature()); + float humidity = clampColor(getHumidity()); + // Based on net.minecraft.world.level.FoliageColor#get() + humidity *= temperature; + int humidityValue = (int)((1.0f - humidity) * 255.0f); + int temperatureValue = (int)((1.0f - temperature) * 255.0f); + int index = temperatureValue << 8 | humidityValue; + return index >= 65536 ? 4764952 : getColor(index / 256, index % 256).asRGB(); + } + + public void setClimate(boolean hasPrecipitation, float temperature, Biome.TemperatureModifier temperatureModifier, float downfall) { + try { + Object newClimate = BIOME_CLIMATESETTINGS_CONSTRUCTOR.invoke(hasPrecipitation, temperature, temperatureModifier, downfall); + ReflectionHelper.setFieldValue(Biome.class, "climateSettings", biomeHolder.value(), newClimate); + setNetworkedRegistrationInfo(); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public void setHumidity(float humidity) { + setClimate(hasDownfall(), getBaseTemperature(), getTemperatureModifier(), humidity); + } + + @Override + public void setBaseTemperature(float baseTemperature) { + setClimate(hasDownfall(), baseTemperature, getTemperatureModifier(), getHumidity()); + } + + @Override + public void setHasDownfall(boolean hasDownfall) { + setClimate(hasDownfall, getBaseTemperature(), getTemperatureModifier(), getHumidity()); + } + + @Override + public void setFoliageColor(int color) { + BiomeSpecialEffects nmsCurrEffects = biomeHolder.value().getSpecialEffects(); + BiomeSpecialEffects nmsNewEffects = new BiomeSpecialEffects( + nmsCurrEffects.waterColor(), Optional.of(color), nmsCurrEffects.dryFoliageColorOverride(), nmsCurrEffects.grassColorOverride(), nmsCurrEffects.grassColorModifier() + ); + ReflectionHelper.setFieldValue(Biome.class, "specialEffects", biomeHolder.value(), nmsNewEffects); + setNetworkedRegistrationInfo(); + } + + @Override + public int getFogColor() { + return getEnvironmentAttribute(EnvironmentAttributes.FOG_COLOR); + } + + @Override + public void setFogColor(int color) { + setEnvironmentAttribute(EnvironmentAttributes.FOG_COLOR, color); + } + + @Override + public int getWaterFogColor() { + return getEnvironmentAttribute(EnvironmentAttributes.WATER_FOG_COLOR); + } + + @Override + public void setWaterFogColor(int color) { + setEnvironmentAttribute(EnvironmentAttributes.WATER_FOG_COLOR, color); + } + + public T getEnvironmentAttribute(EnvironmentAttribute attribute) { + return biomeHolder.value().getAttributes().applyModifier(attribute, attribute.defaultValue()); + } + + public void setEnvironmentAttribute(EnvironmentAttribute attribute, T value) { + Biome nmsBiome = biomeHolder.value(); + EnvironmentAttributeMap newAttributeMap = EnvironmentAttributeMap.builder().putAll(nmsBiome.getAttributes()).set(attribute, value).build(); + try { + BIOME_ATTRIBUTES_SETTER.invokeExact(nmsBiome, newAttributeMap); + } + catch (Throwable e) { + Debug.echoError(e); + } + setNetworkedRegistrationInfo(); + } + + private List getSpawnableEntities(MobCategory creatureType) { + MobSpawnSettings mobs = biomeHolder.value().getMobSettings(); + WeightedList typeSettingList = mobs.getMobs(creatureType); + List entityTypes = new ArrayList<>(); + if (typeSettingList == null) { + return entityTypes; + } + for (Weighted meta : typeSettingList.unwrap()) { + entityTypes.add(CraftEntityType.minecraftToBukkit(meta.value().type())); + } + return entityTypes; + } + + @Override + public void setTo(Block block) { + if (((CraftWorld) block.getWorld()).getHandle() != this.world) { + NMSHandler.instance.getBiomeNMS(block.getWorld(), getKey()).setTo(block); + return; + } + // Based on CraftWorld source + BlockPos pos = new BlockPos(block.getX(), 0, block.getZ()); + if (world.hasChunkAt(pos)) { + LevelChunk chunk = world.getChunkAt(pos); + if (chunk != null) { + chunk.setBiome(block.getX() >> 2, block.getY() >> 2, block.getZ() >> 2, biomeHolder); + chunk.markUnsaved(); + } + } + } + + public Biome.TemperatureModifier getTemperatureModifier() { + return biomeHolder.value().climateSettings.temperatureModifier(); + } + + private void setNetworkedRegistrationInfo() { + try { + Map, RegistrationInfo> registrationInfos = (Map, RegistrationInfo>) MAPPED_REGISTRY_REGISTRATION_INFOS.invokeExact(getBiomeRegistry()); + registrationInfos.put(biomeHolder.key(), RegistrationInfo.BUILT_IN); + } + catch (Throwable e) { + Debug.echoError("Failed to set biome registration info, changes may not be synced correctly."); + Debug.echoError(e); + } + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ImprovedOfflinePlayerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ImprovedOfflinePlayerImpl.java new file mode 100644 index 0000000000..dfed25aac1 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ImprovedOfflinePlayerImpl.java @@ -0,0 +1,169 @@ +package com.denizenscript.denizen.nms.v26_1.impl; + +import com.denizenscript.denizen.nms.abstracts.ImprovedOfflinePlayer; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.helpers.NBTAdapter; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.mojang.authlib.GameProfile; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.nbt.NbtIo; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ParticleStatus; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.ItemStackWithSlot; +import net.minecraft.world.entity.EntityEquipment; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.ai.attributes.AttributeInstance; +import net.minecraft.world.entity.ai.attributes.AttributeMap; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.ai.attributes.DefaultAttributes; +import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.level.storage.ValueOutput; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.UUID; +import java.util.function.Consumer; + +public class ImprovedOfflinePlayerImpl extends ImprovedOfflinePlayer { + + public ImprovedOfflinePlayerImpl(UUID playeruuid) { + super(playeruuid); + } + + public static class OfflinePlayerInventory extends net.minecraft.world.entity.player.Inventory { + + public OfflinePlayerInventory(net.minecraft.world.entity.player.Player entityhuman) { + super(entityhuman, new EntityEquipment()); // TODO: 1.21.5: is the new Equipment right here? + } + + @Override + public InventoryHolder getOwner() { + return null; + } + } + + public static class OfflineCraftInventoryPlayer extends CraftInventoryPlayer { + + public OfflineCraftInventoryPlayer(net.minecraft.world.entity.player.Inventory inventory) { + super(inventory); + } + + @Override + public HumanEntity getHolder() { + return null; + } + } + + public static ServerPlayer fakeNmsPlayer; + + public static ServerPlayer getFakeNmsPlayer() { + if (fakeNmsPlayer == null) { + MinecraftServer server = ((CraftServer)Bukkit.getServer()).getServer(); + World world = Bukkit.getWorlds().getFirst(); + GameProfile fakeProfile = new GameProfile(new UUID(0, 0xABC123), "fakeplayer"); + ClientInformation fakeClientInfo = new ClientInformation("en", 0, ChatVisiblity.HIDDEN, false, 0, HumanoidArm.LEFT, true, false, ParticleStatus.MINIMAL); + fakeNmsPlayer = new ServerPlayer(server, ((CraftWorld) world).getHandle(), fakeProfile, fakeClientInfo); + } + return fakeNmsPlayer; + } + + public void editData(Consumer editor) { + this.compound = NBTAdapter.toAPI(Handler.useValueOutput(NBTAdapter.toNMS(this.compound), editor)); + markModified(); + } + + @Override + public org.bukkit.inventory.PlayerInventory getInventory() { + if (inventory == null) { + net.minecraft.world.entity.player.Inventory newInv = new OfflinePlayerInventory(getFakeNmsPlayer()); + Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> newInv.load(valueInput.listOrEmpty("Inventory", ItemStackWithSlot.CODEC))); + inventory = new OfflineCraftInventoryPlayer(newInv); + } + return inventory; + } + + @Override + public void setInventory(org.bukkit.inventory.PlayerInventory inventory) { + CraftInventoryPlayer inv = (CraftInventoryPlayer) inventory; + editData(valueOutput -> inv.getInventory().save(valueOutput.list("Inventory", ItemStackWithSlot.CODEC))); + } + + @Override + public Inventory getEnderChest() { + if (enderchest == null) { + PlayerEnderChestContainer nmsEnderChest = new PlayerEnderChestContainer(getFakeNmsPlayer()); + Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> nmsEnderChest.fromSlots(valueInput.listOrEmpty("EnderItems", ItemStackWithSlot.CODEC))); + enderchest = new CraftInventory(nmsEnderChest); + } + return enderchest; + } + + @Override + public void setEnderChest(Inventory inventory) { + editData(valueOutput -> ((PlayerEnderChestContainer) ((CraftInventory) inventory).getInventory()).storeAsSlots(valueOutput.list("EnderItems", ItemStackWithSlot.CODEC))); + } + + @Override + public double getMaxHealth() { + AttributeInstance maxHealth = getAttributes().getInstance(Attributes.MAX_HEALTH); + return maxHealth == null ? Attributes.MAX_HEALTH.value().getDefaultValue() : maxHealth.getValue(); + } + + @Override + public void setMaxHealth(double input) { + AttributeMap attributes = getAttributes(); + AttributeInstance maxHealth = attributes.getInstance(Attributes.MAX_HEALTH); + maxHealth.setBaseValue(input); + setAttributes(attributes); + } + + private AttributeMap getAttributes() { + AttributeMap amb = new AttributeMap(DefaultAttributes.getSupplier(net.minecraft.world.entity.EntityType.PLAYER)); + Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> valueInput.read("attributes", AttributeInstance.Packed.LIST_CODEC).ifPresent(amb::apply)); + return amb; + } + + public void setAttributes(AttributeMap attributes) { + editData(valueOutput -> valueOutput.store("attributes", AttributeInstance.Packed.LIST_CODEC, attributes.pack())); + } + + @Override + protected boolean loadPlayerData(UUID uuid) { + try { + this.player = uuid; + this.file = new File(MinecraftServer.getServer().playerDataStorage.getPlayerDir(), this.player + ".dat"); + if (this.file.exists()) { + this.compound = NBTAdapter.toAPI(NbtIo.readCompressed(new FileInputStream(this.file), NbtAccounter.unlimitedHeap())); + return true; + } + } + catch (Exception e) { + Debug.echoError(e); + } + return false; + } + + @Override + public void saveInternal(CompoundBinaryTag compound) { + try { + NbtIo.writeCompressed(NBTAdapter.toNMS(compound), new FileOutputStream(this.file)); + } + catch (Exception e) { + Debug.echoError(e); + } + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ProfileEditorImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ProfileEditorImpl.java new file mode 100644 index 0000000000..d620ff984f --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ProfileEditorImpl.java @@ -0,0 +1,168 @@ +package com.denizenscript.denizen.nms.v26_1.impl; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.abstracts.ProfileEditor; +import com.denizenscript.denizen.nms.util.PlayerProfile; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.collect.ImmutableMultimap; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.datafixers.util.Either; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerRespawnEvent; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.*; + +public class ProfileEditorImpl extends ProfileEditor { + + @Override + protected void updatePlayer(final Player player, final boolean isSkinChanging) { + final ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + final UUID uuid = player.getUniqueId(); + ClientboundPlayerInfoRemovePacket removePlayerInfoPacket = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + ClientboundPlayerInfoUpdatePacket addPlayerInfoPacket = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(nmsPlayer)); + for (Player otherPlayer : Bukkit.getServer().getOnlinePlayers()) { + PacketHelperImpl.send(otherPlayer, removePlayerInfoPacket); + PacketHelperImpl.send(otherPlayer, addPlayerInfoPacket); + } + for (Player otherPlayer : NMSHandler.entityHelper.getPlayersThatSee(player)) { + if (!otherPlayer.getUniqueId().equals(uuid)) { + PacketHelperImpl.forceRespawnPlayerEntity(player, otherPlayer); + } + } + if (isSkinChanging) { + ((CraftServer) Bukkit.getServer()).getHandle().respawn(nmsPlayer, true, Entity.RemovalReason.CHANGED_DIMENSION, PlayerRespawnEvent.RespawnReason.PLUGIN); + } + else { + NMSHandler.playerHelper.refreshPlayer(player); + } + player.updateInventory(); + } + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundPlayerInfoUpdatePacket.class, ProfileEditorImpl::processPlayerInfoUpdatePacket); + } + + public static ClientboundPlayerInfoUpdatePacket processPlayerInfoUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundPlayerInfoUpdatePacket playerInfoUpdatePacket) { + if (ProfileEditor.mirrorUUIDs.isEmpty() && !RenameCommand.hasAnyDynamicRenames() && fakeProfiles.isEmpty()) { + return playerInfoUpdatePacket; + } + EnumSet actions = playerInfoUpdatePacket.actions(); + if (!actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER) && !actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) { + return playerInfoUpdatePacket; + } + boolean any = false; + for (ClientboundPlayerInfoUpdatePacket.Entry entry : playerInfoUpdatePacket.entries()) { + if (shouldChange(entry)) { + any = true; + break; + } + } + if (!any) { + return playerInfoUpdatePacket; + } + GameProfile ownProfile = networkManager.player.getGameProfile(); + List modifiedEntries = new ArrayList<>(playerInfoUpdatePacket.entries().size()); + for (ClientboundPlayerInfoUpdatePacket.Entry entry : playerInfoUpdatePacket.entries()) { + if (!shouldChange(entry)) { + modifiedEntries.add(entry); + continue; + } + String rename = RenameCommand.getCustomNameFor(entry.profileId(), networkManager.player.getBukkitEntity(), false); + GameProfile baseProfile = fakeProfiles.containsKey(entry.profileId()) ? getGameProfile(fakeProfiles.get(entry.profileId())) : entry.profile(); + PropertyMap modifiedProperties; + if (ProfileEditor.mirrorUUIDs.contains(entry.profileId())) { + modifiedProperties = ownProfile.properties(); + } + else { + // On Paper 1.19+, we use Paper's PlayerProfile API instead of this system + modifiedProperties = Denizen.supportsPaper ? entry.profile().properties() : baseProfile.properties(); + } + GameProfile modifiedProfile = new GameProfile(baseProfile.id(), rename != null ? (rename.length() > 16 ? rename.substring(0, 16) : rename) : baseProfile.name(), modifiedProperties); + String listRename = RenameCommand.getCustomNameFor(entry.profileId(), networkManager.player.getBukkitEntity(), true); + Component displayName = listRename != null ? Handler.componentToNMS(FormattedTextHelper.parse(listRename, ChatColor.WHITE)) : entry.displayName(); + ClientboundPlayerInfoUpdatePacket.Entry modifiedEntry = new ClientboundPlayerInfoUpdatePacket.Entry(entry.profileId(), modifiedProfile, entry.listed(), entry.latency(), entry.gameMode(), displayName, entry.showHat(), entry.listOrder(), entry.chatSession()); + modifiedEntries.add(modifiedEntry); + } + return createInfoPacket(actions, modifiedEntries); + } + + public static boolean shouldChange(ClientboundPlayerInfoUpdatePacket.Entry entry) { + return ProfileEditor.mirrorUUIDs.contains(entry.profileId()) || RenameCommand.customNames.containsKey(entry.profileId()) || fakeProfiles.containsKey(entry.profileId()); + } + + public static final Field ClientboundPlayerInfoUpdatePacket_entries = ReflectionHelper.getFields(ClientboundPlayerInfoUpdatePacket.class).getFirstOfType(List.class); + + public static ClientboundPlayerInfoUpdatePacket createInfoPacket(EnumSet actions, List entries) { + ClientboundPlayerInfoUpdatePacket playerInfoUpdatePacket = new ClientboundPlayerInfoUpdatePacket(actions, List.of()); + try { + ClientboundPlayerInfoUpdatePacket_entries.set(playerInfoUpdatePacket, entries); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return playerInfoUpdatePacket; + } + + public static GameProfile createGameProfile(UUID uuid, String name, String texture, String signature) { + return new GameProfile( + uuid != null ? uuid : NIL_UUID, name != null ? name : EMPTY_NAME, + texture != null ? new PropertyMap(ImmutableMultimap.of("textures", new Property("textures", texture, signature))) : PropertyMap.EMPTY + ); + } + + public static GameProfile getGameProfileNoProperties(PlayerProfile playerProfile) { + return createGameProfile(playerProfile.getUniqueId(), playerProfile.getName(), null, null); + } + + public static GameProfile getGameProfile(PlayerProfile playerProfile) { + return createGameProfile(playerProfile.getUniqueId(), playerProfile.getName(), playerProfile.getTexture(), playerProfile.getTextureSignature()); + } + + public static final MethodHandle RESOLVABLEPROFILE_UNPACK = ReflectionHelper.getMethodHandle(ResolvableProfile.class, "unpack"); + public static final MethodHandle RESOLVABLEPROFILE_PARTIAL_ID = ReflectionHelper + .getFields(ReflectionHelper.getClassOrThrow("net.minecraft.world.item.component.ResolvableProfile$Partial")) + .getGetter("id", Optional.class); + + public static UUID getUUID(ResolvableProfile resolvableProfile) { + try { + Either unpacked = (Either) RESOLVABLEPROFILE_UNPACK.invokeExact(resolvableProfile); + return unpacked.map(GameProfile::id, + partial -> { + try { + Optional uuid = (Optional) RESOLVABLEPROFILE_PARTIAL_ID.invoke(partial); + return uuid.orElse(null); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + } + ); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/SidebarImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/SidebarImpl.java new file mode 100644 index 0000000000..0e08145f36 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/SidebarImpl.java @@ -0,0 +1,103 @@ +package com.denizenscript.denizen.nms.v26_1.impl; + +import com.denizenscript.denizen.nms.abstracts.Sidebar; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.numbers.StyledFormat; +import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; +import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket; +import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket; +import net.minecraft.network.protocol.game.ClientboundSetScorePacket; +import net.minecraft.world.scores.DisplaySlot; +import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.PlayerTeam; +import net.minecraft.world.scores.Scoreboard; +import net.minecraft.world.scores.criteria.ObjectiveCriteria; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class SidebarImpl extends Sidebar { + + // TODO: 1.20.3: the scoreboard system saw significant changes, there is likely a better way to do this now + + public static Scoreboard dummyScoreboard = new Scoreboard(); + public static ObjectiveCriteria dummyCriteria; + + static { + try { + Constructor constructor = ObjectiveCriteria.class.getDeclaredConstructor(String.class); + constructor.setAccessible(true); + dummyCriteria = constructor.newInstance("dummy"); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public Objective obj1; + public Objective obj2; + + public SidebarImpl(Player player) { + super(player); + Component chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + this.obj1 = new Objective(dummyScoreboard, "dummy_1", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER, false, StyledFormat.SIDEBAR_DEFAULT); + this.obj2 = new Objective(dummyScoreboard, "dummy_2", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER, false, StyledFormat.SIDEBAR_DEFAULT); + } + + @Override + protected void setDisplayName(String title) { + if (this.obj1 != null) { + Component chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + this.obj1.setDisplayName(chatComponentTitle); + this.obj2.setDisplayName(chatComponentTitle); + } + } + + public List generatedTeams = new ArrayList<>(); + + @Override + public void sendUpdate() { + List oldTeams = generatedTeams; + generatedTeams = new ArrayList<>(); + PacketHelperImpl.send(player, new ClientboundSetObjectivePacket(this.obj1, 0)); + String[] ids = getIds(); + for (int i = 0; i < this.lines.length; i++) { + String line = this.lines[i]; + if (line == null) { + break; + } + String lineId = ids[i]; + PlayerTeam team = new PlayerTeam(dummyScoreboard, lineId); + team.getPlayers().add(lineId); + team.setPlayerPrefix(Handler.componentToNMS(FormattedTextHelper.parse(line, ChatColor.WHITE))); + generatedTeams.add(team); + PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); + PacketHelperImpl.send(player, new ClientboundSetScorePacket(lineId, obj1.getName(), this.scores[i], Optional.empty(), Optional.of(StyledFormat.SIDEBAR_DEFAULT))); + } + PacketHelperImpl.send(player, new ClientboundSetDisplayObjectivePacket(DisplaySlot.SIDEBAR, this.obj1)); + PacketHelperImpl.send(player, new ClientboundSetObjectivePacket(this.obj2, 1)); + Objective temp = this.obj2; + this.obj2 = this.obj1; + this.obj1 = temp; + for (PlayerTeam team : oldTeams) { + PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createRemovePacket(team)); + } + } + + @Override + public void remove() { + for (PlayerTeam team : generatedTeams) { + PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createRemovePacket(team)); + } + generatedTeams.clear(); + PacketHelperImpl.send(player, new ClientboundSetObjectivePacket(this.obj2, 1)); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/blocks/BlockLightImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/blocks/BlockLightImpl.java new file mode 100644 index 0000000000..e64e9483fb --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/blocks/BlockLightImpl.java @@ -0,0 +1,263 @@ +package com.denizenscript.denizen.nms.v26_1.impl.blocks; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.abstracts.BlockLight; +import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.lighting.LayerLightEventListener; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.util.Vector; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.List; + +public class BlockLightImpl extends BlockLight { + + public static final Class LIGHTENGINETHREADED_TASKTYPE = Arrays.stream(ThreadedLevelLightEngine.class.getDeclaredClasses()).filter(c -> c.isEnum()).findFirst().get(); // TaskType + public static final Object LIGHTENGINETHREADED_TASKTYPE_PRE; + + static { + Object preObj = null; + try { + preObj = ReflectionHelper.getFields(LIGHTENGINETHREADED_TASKTYPE).get("PRE_UPDATE").get(null); + } + catch (Throwable ex) { + ex.printStackTrace(); + } + LIGHTENGINETHREADED_TASKTYPE_PRE = preObj; + } + + public static final MethodHandle LIGHTENGINETHREADED_QUEUERUNNABLE = ReflectionHelper.getMethodHandle(ThreadedLevelLightEngine.class, "addTask", + int.class, int.class, LIGHTENGINETHREADED_TASKTYPE, Runnable.class); + + public static void enqueueRunnable(LevelChunk chunk, Runnable runnable) { + LevelLightEngine lightEngine = chunk.getLevel().getChunkSource().getLightEngine(); + if (lightEngine instanceof ThreadedLevelLightEngine) { + ChunkPos coord = chunk.getPos(); + try { + LIGHTENGINETHREADED_QUEUERUNNABLE.invoke(lightEngine, coord.x(), coord.z(), LIGHTENGINETHREADED_TASKTYPE_PRE, runnable); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + else { + runnable.run(); + } + } + + private BlockLightImpl(Location location, long ticks) { + super(location, ticks); + } + + public static BlockLight createLight(Location location, int lightLevel, long ticks) { + location = location.getBlock().getLocation(); + BlockLight blockLight; + if (lightsByLocation.containsKey(location)) { + blockLight = lightsByLocation.get(location); + if (blockLight.removeTask != null) { + blockLight.removeTask.cancel(); + blockLight.removeTask = null; + } + if (blockLight.updateTask != null) { + blockLight.updateTask.cancel(); + blockLight.updateTask = null; + } + blockLight.removeLater(ticks); + } + else { + blockLight = new BlockLightImpl(location, ticks); + lightsByLocation.put(location, blockLight); + if (!lightsByChunk.containsKey(blockLight.chunkCoord)) { + lightsByChunk.put(blockLight.chunkCoord, new ArrayList<>()); + } + lightsByChunk.get(blockLight.chunkCoord).add(blockLight); + } + blockLight.intendedLevel = lightLevel; + blockLight.update(lightLevel, true); + return blockLight; + } + + public static void checkIfLightsBrokenByPacket(ClientboundBlockUpdatePacket packet, Level world) { + try { + BlockPos pos = packet.getPos(); + int chunkX = pos.getX() >> 4; + int chunkZ = pos.getZ() >> 4; + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> { + LevelChunk chunk = world.getChunk(chunkX, chunkZ); + boolean any = false; + for (Vector vec : RELATIVE_CHUNKS) { + ChunkAccess other = world.getChunk(chunkX + vec.getBlockX(), chunkZ + vec.getBlockZ(), ChunkStatus.FULL, false); + if (other instanceof LevelChunk) { + List lights = lightsByChunk.get(new ChunkCoordinate(new CraftChunk((LevelChunk) other))); + if (lights != null) { + any = true; + for (BlockLight light : lights) { + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> light.update(light.intendedLevel, false), 1); + } + } + } + } + if (any) { + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> sendNearbyChunkUpdates(chunk), 3); + } + }, 1); + } + catch (Exception ex) { + Debug.echoError(ex); + } + } + + public static void checkIfLightsBrokenByPacket(ClientboundLightUpdatePacket packet, Level world) { + if (doNotCheck) { + return; + } + try { + int cX = packet.getX(); + int cZ = packet.getZ(); + BitSet bitMask = packet.getLightData().getBlockYMask(); + List blockData = packet.getLightData().getBlockUpdates(); + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> { + ChunkAccess chk = world.getChunk(cX, cZ, ChunkStatus.FULL, false); + if (!(chk instanceof LevelChunk)) { + return; + } + List lights = lightsByChunk.get(new ChunkCoordinate(new CraftChunk((LevelChunk) chk))); + if (lights == null) { + return; + } + boolean any = false; + for (BlockLight light : lights) { + if (((BlockLightImpl) light).checkIfChangedBy(bitMask, blockData)) { + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> light.update(light.intendedLevel, false), 1); + any = true; + } + } + if (any) { + Bukkit.getScheduler().scheduleSyncDelayedTask(NMSHandler.getJavaPlugin(), () -> sendNearbyChunkUpdates((LevelChunk) chk), 3); + } + }, 1); + } + catch (Exception ex) { + Debug.echoError(ex); + } + } + + public static boolean doNotCheck = false; + + public boolean checkIfChangedBy(BitSet bitmask, List data) { + Location blockLoc = block.getLocation(); + int layer = (blockLoc.getBlockY() >> 4) + 1; + if (!bitmask.get(layer)) { + return false; + } + int found = 0; + for (int i = 0; i < 16; i++) { + if (bitmask.get(i)) { + if (i == layer) { + byte[] blocks = data.get(found); + DataLayer arr = new DataLayer(blocks); + int x = blockLoc.getBlockX() - (chunkCoord.x << 4); + int y = blockLoc.getBlockY() % 16; + int z = blockLoc.getBlockZ() - (chunkCoord.z << 4); + int level = arr.get(x, y, z); + return intendedLevel != level; + } + found++; + } + } + return false; + } + + public static void runResetFor(final LevelChunk chunk, final BlockPos pos) { + Runnable runnable = () -> { + LevelLightEngine lightEngine = chunk.getLevel().getChunkSource().getLightEngine(); + LayerLightEventListener engineBlock = lightEngine.getLayerListener(LightLayer.BLOCK); + engineBlock.checkBlock(pos); + }; + enqueueRunnable(chunk, runnable); + } + + public static void runSetFor(final LevelChunk chunk, final BlockPos pos, final int level) { + Runnable runnable = () -> { + LevelLightEngine lightEngine = chunk.getLevel().getChunkSource().getLightEngine(); + LayerLightEventListener engineBlock = lightEngine.getLayerListener(LightLayer.BLOCK); + // engineBlock.onBlockEmissionIncrease(pos, level); // TODO: 1.20: ? + }; + enqueueRunnable(chunk, runnable); + } + + @Override + public void reset(boolean updateChunk) { + runResetFor((LevelChunk) ((CraftChunk) getChunk()).getHandle(ChunkStatus.FULL), ((CraftBlock) block).getPosition()); + if (updateChunk) { + // This runnable cast is necessary despite what your IDE may claim + updateTask = Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), (Runnable) this::sendNearbyChunkUpdates, 1); + } + } + + @Override + public void update(int lightLevel, boolean updateChunk) { + runResetFor((LevelChunk) ((CraftChunk) getChunk()).getHandle(ChunkStatus.FULL), ((CraftBlock) block).getPosition()); + updateTask = Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), () -> { + updateTask = null; + runSetFor((LevelChunk) ((CraftChunk) chunk).getHandle(ChunkStatus.FULL), ((CraftBlock) block).getPosition(), lightLevel); + if (updateChunk) { + // This runnable cast is necessary despite what your IDE may claim + updateTask = Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), (Runnable) this::sendNearbyChunkUpdates, 1); + } + }, 1); + } + + public static final Vector[] RELATIVE_CHUNKS = new Vector[] { + new Vector(0, 0, 0), + new Vector(-1, 0, 0), new Vector(1, 0, 0), new Vector(0, 0, -1), new Vector(0, 0, 1), + new Vector(-1, 0, -1), new Vector(-1, 0, 1), new Vector(1, 0, -1), new Vector(1, 0, 1) + }; + + public void sendNearbyChunkUpdates() { + sendNearbyChunkUpdates((LevelChunk) ((CraftChunk) getChunk()).getHandle(ChunkStatus.FULL)); + } + + public static void sendNearbyChunkUpdates(LevelChunk chunk) { + ChunkPos pos = chunk.getPos(); + for (Vector vec : RELATIVE_CHUNKS) { + ChunkAccess other = chunk.getLevel().getChunk(pos.x() + vec.getBlockX(), pos.z() + vec.getBlockZ(), ChunkStatus.FULL, false); + if (other instanceof LevelChunk) { + sendSingleChunkUpdate((LevelChunk) other); + } + } + } + + public static void sendSingleChunkUpdate(LevelChunk chunk) { + // TODO: 1.20: ? + /* + doNotCheck = true; + LevelLightEngine lightEngine = chunk.getLevel().getChunkSource().getLightEngine(); + ChunkPos pos = chunk.getPos(); + //ClientboundLightUpdatePacket packet = new ClientboundLightUpdatePacket(pos, lightEngine, null, null, true); // TODO: 1.16: should 'trust edges' be true here? + ((ServerChunkCache) chunk.getLevel().getChunkSource()).chunkMap.getPlayers(pos, false).forEach((player) -> { + player.connection.send(packet); + }); + doNotCheck = false;*/ + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakeArrowImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakeArrowImpl.java new file mode 100644 index 0000000000..160f12a001 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakeArrowImpl.java @@ -0,0 +1,26 @@ +package com.denizenscript.denizen.nms.v26_1.impl.entities; + +import com.denizenscript.denizen.nms.interfaces.FakeArrow; +import net.minecraft.world.entity.projectile.arrow.AbstractArrow; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftAbstractArrow; + +public class CraftFakeArrowImpl extends CraftAbstractArrow implements FakeArrow { + + public CraftFakeArrowImpl(CraftServer craftServer, AbstractArrow entityArrow) { + super(craftServer, entityArrow); + } + + @Override + public void remove() { + if (getPassenger() != null) { + return; + } + super.remove(); + } + + @Override + public String getEntityTypeName() { + return "FAKE_ARROW"; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakePlayerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakePlayerImpl.java new file mode 100644 index 0000000000..79f8121011 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakePlayerImpl.java @@ -0,0 +1,66 @@ +package com.denizenscript.denizen.nms.v26_1.impl.entities; + +import com.denizenscript.denizen.nms.interfaces.FakePlayer; +import com.denizenscript.denizen.nms.NMSHandler; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; + +import java.util.List; +import java.util.Set; + +public class CraftFakePlayerImpl extends CraftPlayer implements FakePlayer { + + private final CraftServer server; + public String fullName; + + public CraftFakePlayerImpl(CraftServer server, EntityFakePlayerImpl entity) { + super(server, entity); + this.server = server; + setMetadata("NPC", new FixedMetadataValue(NMSHandler.getJavaPlugin(), true)); + } + + @Override + public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { + this.server.getEntityMetadata().setMetadata(this, metadataKey, newMetadataValue); + } + + @Override + public List getMetadata(String metadataKey) { + return this.server.getEntityMetadata().getMetadata(this, metadataKey); + } + + @Override + public boolean hasMetadata(String metadataKey) { + return this.server.getEntityMetadata().hasMetadata(this, metadataKey); + } + + @Override + public void removeMetadata(String metadataKey, Plugin owningPlugin) { + this.server.getEntityMetadata().removeMetadata(this, metadataKey, owningPlugin); + } + + @Override + public String getEntityTypeName() { + return "FAKE_PLAYER"; + } + + @Override + public String getFullName() { + return fullName; + } + + @Override + public Block getTargetBlock(Set transparent, int maxDistance) { + return null; + } + + @Override + public List getLastTwoTargetBlocks(Set transparent, int maxDistance) { + return null; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftItemProjectileImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftItemProjectileImpl.java new file mode 100644 index 0000000000..da41f2da0c --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftItemProjectileImpl.java @@ -0,0 +1,117 @@ +package com.denizenscript.denizen.nms.v26_1.impl.entities; + +import com.denizenscript.denizen.nms.interfaces.ItemProjectile; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.ProjectileSource; + +import java.lang.invoke.MethodHandle; +import java.util.UUID; + +public class CraftItemProjectileImpl extends CraftEntity implements ItemProjectile { + + private boolean doesBounce; + + public CraftItemProjectileImpl(CraftServer server, EntityItemProjectileImpl entity) { + super(server, entity); + MethodHandle handle = ReflectionHelper.getFinalSetterForFirstOfType(CraftEntity.class, EntityType.class); + if (handle != null) { + try { + handle.invoke(this, EntityType.ITEM); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + } + + @Override + public EntityItemProjectileImpl getHandle() { + return (EntityItemProjectileImpl) super.getHandle(); + } + + @Override + public String getEntityTypeName() { + return getType().name(); + } + + @Override + public ItemStack getItemStack() { + return CraftItemStack.asBukkitCopy(getHandle().getItemStack()); + } + + @Override + public void setItemStack(ItemStack itemStack) { + getHandle().setItemStack(CraftItemStack.asNMSCopy(itemStack)); + } + + @Override + public int getPickupDelay() { + return 0; + } + + @Override + public void setPickupDelay(int i) { + // Do nothing + } + + @Override + public void setUnlimitedLifetime(boolean b) { + // Do nothing + } + + @Override + public boolean isUnlimitedLifetime() { + return false; + } + + @Override + public void setOwner(UUID uuid) { + // Do nothing + } + + @Override + public UUID getOwner() { + return null; + } + + @Override + public void setThrower(UUID uuid) { + // Do nothing + } + + @Override + public UUID getThrower() { + return null; + } + + @Override + public ProjectileSource getShooter() { + return getHandle().projectileSource; + } + + @Override + public void setShooter(ProjectileSource projectileSource) { + if (projectileSource instanceof CraftEntity) { + getHandle().setOwner(((CraftEntity) projectileSource).getHandle()); + } + else { + getHandle().projectileSource = projectileSource; + } + } + + @Override + public boolean doesBounce() { + return doesBounce; + } + + @Override + public void setBounce(boolean doesBounce) { + this.doesBounce = doesBounce; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakeArrowImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakeArrowImpl.java new file mode 100644 index 0000000000..01b789f238 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakeArrowImpl.java @@ -0,0 +1,43 @@ +package com.denizenscript.denizen.nms.v26_1.impl.entities; + +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.world.entity.projectile.arrow.SpectralArrow; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.event.entity.CreatureSpawnEvent; + +public class EntityFakeArrowImpl extends SpectralArrow { + + public EntityFakeArrowImpl(CraftWorld craftWorld, Location location) { + super(net.minecraft.world.entity.EntityType.SPECTRAL_ARROW, craftWorld.getHandle()); + try { + Handler.ENTITY_BUKKITYENTITY.set(this, new CraftFakeArrowImpl((CraftServer) Bukkit.getServer(), this)); + } + catch (Exception ex) { + Debug.echoError(ex); + } + setPosRaw(location.getX(), location.getY(), location.getZ()); + setRot(location.getYaw(), location.getPitch()); + level().addFreshEntity(this, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + + @Override + public void tick() { + // Do nothing + } + + @Override + protected ItemStack getPickupItem() { + return new ItemStack(Items.ARROW); + } + + @Override + public CraftFakeArrowImpl getBukkitEntity() { + return (CraftFakeArrowImpl) super.getBukkitEntity(); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakePlayerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakePlayerImpl.java new file mode 100644 index 0000000000..d81df1ffa7 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakePlayerImpl.java @@ -0,0 +1,43 @@ +package com.denizenscript.denizen.nms.v26_1.impl.entities; + +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.network.fakes.FakeNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.fakes.FakePlayerConnectionImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.mojang.authlib.GameProfile; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.world.entity.player.Player; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.event.entity.CreatureSpawnEvent; + +public class EntityFakePlayerImpl extends ServerPlayer { + + public EntityFakePlayerImpl(MinecraftServer minecraftserver, ServerLevel worldserver, GameProfile gameprofile, ClientInformation clientInfo, boolean doAdd) { + super(minecraftserver, worldserver, gameprofile, clientInfo); + try { + Handler.ENTITY_BUKKITYENTITY.set(this, new CraftFakePlayerImpl((CraftServer) Bukkit.getServer(), this)); + net.minecraft.network.Connection networkManager = new FakeNetworkManagerImpl(PacketFlow.CLIENTBOUND); + connection = new FakePlayerConnectionImpl(minecraftserver, networkManager, this, new CommonListenerCookie(gameprofile, 0, clientInfo, false)); + DenizenNetworkManagerImpl.Connection_packetListener.set(networkManager, connection); + } + catch (Exception ex) { + Debug.echoError(ex); + } + getEntityData().set(Player.DATA_PLAYER_MODE_CUSTOMISATION, (byte) 127); + if (doAdd) { + worldserver.addFreshEntity(this, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + } + + @Override + public CraftFakePlayerImpl getBukkitEntity() { + return (CraftFakePlayerImpl) super.getBukkitEntity(); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityItemProjectileImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityItemProjectileImpl.java new file mode 100644 index 0000000000..e385265301 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityItemProjectileImpl.java @@ -0,0 +1,97 @@ +package com.denizenscript.denizen.nms.v26_1.impl.entities; + +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.base.Preconditions; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.projectile.ThrowableProjectile; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.BlockHitResult; +import org.bukkit.Location; + +import java.lang.invoke.MethodHandle; + +public class EntityItemProjectileImpl extends ThrowableProjectile { + + public static MethodHandle setBukkitEntityMethod = ReflectionHelper.getFinalSetter(Entity.class, "bukkitEntity"); + + public static final EntityDataAccessor ITEM; + + static { + EntityDataAccessor watcher = null; + try { + watcher = (EntityDataAccessor) ReflectionHelper.getFields(ItemEntity.class).get("DATA_ITEM").get(null); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + ITEM = watcher; + } + + public EntityItemProjectileImpl(Level world, Location location, ItemStack item) { + super((net.minecraft.world.entity.EntityType) net.minecraft.world.entity.EntityType.ITEM, world); + try { + setBukkitEntityMethod.invoke(this, new CraftItemProjectileImpl(((ServerLevel) world).getServer().server, this)); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + setPosRaw(location.getX(), location.getY(), location.getZ()); + setRot(location.getYaw(), location.getPitch()); + setItemStack(item); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(ITEM, ItemStack.EMPTY); + } + + public ItemStack getItemStack() { + return this.getEntityData().get(ITEM); + } + + public void setItemStack(ItemStack itemstack) { + Preconditions.checkArgument(!itemstack.isEmpty(), "Cannot drop air"); + this.getEntityData().set(ITEM, itemstack); + this.getEntityData().markDirty(ITEM); + } + + @Override + protected void onHitBlock(BlockHitResult movingobjectpositionblock) { + super.onHitBlock(movingobjectpositionblock); + remove(RemovalReason.KILLED); + } + + @Override + public boolean save(ValueOutput nmsValueOutput) { + if (!this.getItemStack().isEmpty()) { + nmsValueOutput.store("Item", ItemStack.CODEC, this.getItemStack()); + } + super.save(nmsValueOutput); + return true; + } + + @Override + public void load(ValueInput nmsValueInput) { + ItemStack nmsItemStack = nmsValueInput.read("Item", ItemStack.CODEC).orElse(ItemStack.EMPTY); + if (nmsItemStack.isEmpty()) { + this.remove(RemovalReason.KILLED); + } + else { + this.setItemStack(nmsItemStack); + } + super.load(nmsValueInput); + } + + @Override + public CraftItemProjectileImpl getBukkitEntity() { + return (CraftItemProjectileImpl) super.getBukkitEntity(); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeChannelImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeChannelImpl.java new file mode 100644 index 0000000000..e265656f2e --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeChannelImpl.java @@ -0,0 +1,80 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; + +import io.netty.channel.*; + +import java.net.SocketAddress; + +public class FakeChannelImpl extends AbstractChannel { + + private final ChannelConfig config = new DefaultChannelConfig(this); + + protected FakeChannelImpl(Channel parent) { + super(parent); + } + + @Override + public ChannelConfig config() { + config.setAutoRead(true); + return config; + } + + @Override + protected AbstractUnsafe newUnsafe() { + return null; + } + + @Override + protected boolean isCompatible(EventLoop eventLoop) { + return false; + } + + @Override + protected SocketAddress localAddress0() { + return null; + } + + @Override + protected SocketAddress remoteAddress0() { + return null; + } + + @Override + protected void doBind(SocketAddress socketAddress) throws Exception { + + } + + @Override + protected void doDisconnect() throws Exception { + + } + + @Override + protected void doClose() throws Exception { + + } + + @Override + protected void doBeginRead() throws Exception { + + } + + @Override + protected void doWrite(ChannelOutboundBuffer channelOutboundBuffer) throws Exception { + + } + + @Override + public boolean isOpen() { + return false; + } + + @Override + public boolean isActive() { + return false; + } + + @Override + public ChannelMetadata metadata() { + return new ChannelMetadata(true); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeNetworkManagerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeNetworkManagerImpl.java new file mode 100644 index 0000000000..a94b4367aa --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeNetworkManagerImpl.java @@ -0,0 +1,16 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; + +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.PacketFlow; + +import java.net.SocketAddress; + +public class FakeNetworkManagerImpl extends Connection { + + public FakeNetworkManagerImpl(PacketFlow enumprotocoldirection) { + super(enumprotocoldirection); + channel = new FakeChannelImpl(null); + address = new SocketAddress() { + }; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakePlayerConnectionImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakePlayerConnectionImpl.java new file mode 100644 index 0000000000..373e74ada5 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakePlayerConnectionImpl.java @@ -0,0 +1,20 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; + +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; + +public class FakePlayerConnectionImpl extends ServerGamePacketListenerImpl { + + public FakePlayerConnectionImpl(MinecraftServer minecraftserver, Connection networkmanager, ServerPlayer entityplayer, CommonListenerCookie cookie) { + super(minecraftserver, networkmanager, entityplayer, cookie); + } + + @Override + public void send(Packet packet) { + // Do nothing + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/AbstractListenerPlayInImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/AbstractListenerPlayInImpl.java new file mode 100644 index 0000000000..6d5d5a2b48 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/AbstractListenerPlayInImpl.java @@ -0,0 +1,670 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; + +import com.denizenscript.denizen.events.player.PlayerSendPacketScriptEvent; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.mojang.authlib.GameProfile; +import io.netty.channel.ChannelFutureListener; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; +import net.minecraft.network.ConnectionProtocol; +import net.minecraft.network.DisconnectionDetails; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.PlayerChatMessage; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.*; +import net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.ping.ServerboundPingRequestPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerCommonPacketListenerImpl; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.Relative; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.event.player.PlayerTeleportEvent; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.net.SocketAddress; +import java.util.Set; + +public class AbstractListenerPlayInImpl extends ServerGamePacketListenerImpl { + + public static final Field ServerGamePacketListenerImpl_chunkSender = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("chunkSender"); + + public static final MethodHandle SERVER_COMMON_PACKET_LISTENER_IMPL_CREATE_COOKIE = ReflectionHelper.getMethodHandle(ServerCommonPacketListenerImpl.class, "createCookie", ClientInformation.class); + + public static CommonListenerCookie createCookie(ServerPlayer nmsPlayer) { + try { + return (CommonListenerCookie) SERVER_COMMON_PACKET_LISTENER_IMPL_CREATE_COOKIE.invoke(nmsPlayer.connection, nmsPlayer.clientInformation()); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public final ServerGamePacketListenerImpl oldListener; + public final DenizenNetworkManagerImpl denizenNetworkManager; + + public AbstractListenerPlayInImpl(DenizenNetworkManagerImpl networkManager, ServerPlayer entityPlayer, ServerGamePacketListenerImpl oldListener) { + super(MinecraftServer.getServer(), networkManager, entityPlayer, createCookie(entityPlayer)); + this.oldListener = oldListener; + this.denizenNetworkManager = networkManager; + try { + ServerGamePacketListenerImpl_chunkSender.set(this, oldListener.chunkSender); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + } + } + + @Override + public void disconnect(Component ichatbasecomponent) { + oldListener.disconnect(ichatbasecomponent); + } + + @Override + public void disconnect(DisconnectionDetails disconnectiondetails) { + oldListener.disconnect(disconnectiondetails); + } + + @Override + public void kickPlayer(Component reason) { + oldListener.kickPlayer(reason); + } + + @Override + public void teleport(double d0, double d1, double d2, float f, float f1) { + oldListener.teleport(d0, d1, d2, f, f1); + } + + @Override + public boolean teleport(double d0, double d1, double d2, float f, float f1, PlayerTeleportEvent.TeleportCause cause) { + return oldListener.teleport(d0, d1, d2, f, f1, cause); + } + + @Override + public void teleport(PositionMoveRotation positionmoverotation, Set set) { + oldListener.teleport(positionmoverotation, set); + } + + @Override + public boolean teleport(PositionMoveRotation positionmoverotation, Set set, PlayerTeleportEvent.TeleportCause cause) { + return oldListener.teleport(positionmoverotation, set, cause); + } + + @Override + public void teleport(Location dest) { + oldListener.teleport(dest); + } + + @Override + public void internalTeleport(PositionMoveRotation positionmoverotation, Set set) { + oldListener.internalTeleport(positionmoverotation, set); + } + + @Override + public CraftPlayer getCraftPlayer() { + return oldListener.getCraftPlayer(); + } + + @Override + public void tick() { + oldListener.tick(); + } + + @Override + public void resetPosition() { + oldListener.resetPosition(); + } + + @Override + public boolean isAcceptingMessages() { + return oldListener.isAcceptingMessages(); + } + + @Override + public boolean shouldHandleMessage(Packet packet) { + return oldListener.shouldHandleMessage(packet); + } + + @Override + public void fillCrashReport(CrashReport var0) { + oldListener.fillCrashReport(var0); + } + + @Override + public void fillListenerSpecificCrashDetails(CrashReport var0, CrashReportCategory var1) { + oldListener.fillListenerSpecificCrashDetails(var0, var1); + } + + @Override + public GameProfile getOwner() { + return oldListener.getOwner(); + } + + @Override + public int latency() { + return oldListener.latency(); + } + + @Override + public void onDisconnect(DisconnectionDetails disconnectionDetails) { + oldListener.onDisconnect(disconnectionDetails); + } + + @Override + public void ackBlockChangesUpTo(int i) { + oldListener.ackBlockChangesUpTo(i); + } + + @Override + public void send(Packet packet) { + oldListener.send(packet); + } + + @Override + public void send(Packet packet, ChannelFutureListener channelfuturelistener) { + oldListener.send(packet, channelfuturelistener); + } + + public static Field AWAITING_POS_FIELD = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("awaitingPositionFromClient", Vec3.class); + public static Field AWAITING_TELEPORT_FIELD = ReflectionHelper.getFields(ServerGamePacketListenerImpl.class).get("awaitingTeleport", int.class); + + public void debugPacketOutput(Packet packet) { + try { + if (packet instanceof ServerboundMovePlayerPacket) { + ServerboundMovePlayerPacket movePacket = (ServerboundMovePlayerPacket) packet; + DenizenNetworkManagerImpl.doPacketOutput("Packet ServerboundMovePlayerPacket sent from " + player.getScoreboardName() + " with XYZ=" + + movePacket.x + ", " + movePacket.y + ", " + movePacket.z + ", yRot=" + movePacket.yRot + ", xRot=" + movePacket.xRot + + ", onGround=" + movePacket.isOnGround() + ", hasPos=" + movePacket.hasPos + ", hasRot=" + movePacket.hasRot); + } + else if (packet instanceof ServerboundAcceptTeleportationPacket) { + Vec3 awaitPos = (Vec3) AWAITING_POS_FIELD.get(oldListener); + int awaitTeleportId = AWAITING_TELEPORT_FIELD.getInt(oldListener); + ServerboundAcceptTeleportationPacket acceptPacket = (ServerboundAcceptTeleportationPacket) packet; + DenizenNetworkManagerImpl.doPacketOutput("Packet ServerboundAcceptTeleportationPacket sent from " + player.getScoreboardName() + + " with ID=" + acceptPacket.getId() + ", awaitingTeleport=" + awaitTeleportId + ", awaitPos=" + awaitPos); + } + else { + DenizenNetworkManagerImpl.doPacketOutput("Packet: " + packet.getClass().getCanonicalName() + " sent from " + player.getScoreboardName()); + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public boolean handlePacketIn(Packet packet) { + denizenNetworkManager.packetsReceived++; + if (NMSHandler.debugPackets) { + debugPacketOutput(packet); + } + if (PlayerSendPacketScriptEvent.instance.eventData.isEnabled) { + if (PlayerSendPacketScriptEvent.fireFor(player.getBukkitEntity(), packet)) { + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Denied packet-in " + packet.getClass().getCanonicalName() + " from " + player.getScoreboardName() + " due to event"); + } + return true; + } + } + return false; + } + + @Override + public void handleChatAck(ServerboundChatAckPacket serverboundchatackpacket) { + oldListener.handleChatAck(serverboundchatackpacket); + } + + @Override + public void handlePlayerInput(ServerboundPlayerInputPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlayerInput(packet); + } + + @Override + public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleMoveVehicle(packet); + } + + @Override + public void handleAcceptTeleportPacket(ServerboundAcceptTeleportationPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleAcceptTeleportPacket(packet); + } + + @Override + public void handleRecipeBookSeenRecipePacket(ServerboundRecipeBookSeenRecipePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleRecipeBookSeenRecipePacket(packet); + } + + @Override + public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleRecipeBookChangeSettingsPacket(packet); + } + + @Override + public void handleSeenAdvancements(ServerboundSeenAdvancementsPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSeenAdvancements(packet); + } + + @Override + public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleCustomCommandSuggestions(packet); + } + + @Override + public void handleSetCommandBlock(ServerboundSetCommandBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetCommandBlock(packet); + } + + @Override + public void handleSetCommandMinecart(ServerboundSetCommandMinecartPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetCommandMinecart(packet); + } + + @Override + public void handleAcceptPlayerLoad(ServerboundPlayerLoadedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleAcceptPlayerLoad(packet); + } + + @Override + public void handlePickItemFromBlock(ServerboundPickItemFromBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePickItemFromBlock(packet); + } + + @Override + public void handlePickItemFromEntity(ServerboundPickItemFromEntityPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePickItemFromEntity(packet); + } + + @Override + public void handleRenameItem(ServerboundRenameItemPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleRenameItem(packet); + } + + @Override + public void handleSetBeaconPacket(ServerboundSetBeaconPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetBeaconPacket(packet); + } + + @Override + public void handleSetStructureBlock(ServerboundSetStructureBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetStructureBlock(packet); + } + + @Override + public void handleSetTestBlock(ServerboundSetTestBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetTestBlock(packet); + } + + @Override + public void handleTestInstanceBlockAction(ServerboundTestInstanceBlockActionPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleTestInstanceBlockAction(packet); + } + + @Override + public void handleSetJigsawBlock(ServerboundSetJigsawBlockPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetJigsawBlock(packet); + } + + @Override + public void handleJigsawGenerate(ServerboundJigsawGeneratePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleJigsawGenerate(packet); + } + + @Override + public void handleSelectTrade(ServerboundSelectTradePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSelectTrade(packet); + } + + @Override + public void handleEditBook(ServerboundEditBookPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleEditBook(packet); + } + + @Override + public void handleMovePlayer(ServerboundMovePlayerPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleMovePlayer(packet); + } + + @Override + public void handlePlayerAction(ServerboundPlayerActionPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlayerAction(packet); + } + + @Override + public void handleUseItemOn(ServerboundUseItemOnPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleUseItemOn(packet); + } + + @Override + public void handleUseItem(ServerboundUseItemPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleUseItem(packet); + } + + @Override + public void handleTeleportToEntityPacket(ServerboundTeleportToEntityPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleTeleportToEntityPacket(packet); + } + + @Override + public void handleResourcePackResponse(ServerboundResourcePackPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleResourcePackResponse(packet); + } + + @Override + public void suspendFlushing() { + oldListener.suspendFlushing(); + } + + @Override + public void resumeFlushing() { + oldListener.resumeFlushing(); + } + + @Override + public void handlePaddleBoat(ServerboundPaddleBoatPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePaddleBoat(packet); + } + + @Override + public void handlePong(ServerboundPongPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePong(packet); + } + + @Override + public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetCarriedItem(packet); + } + + @Override + public void handleChat(ServerboundChatPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChat(packet); + } + + @Override + public void handleChatCommand(ServerboundChatCommandPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChatCommand(packet); + } + + @Override + public void chat(String s, PlayerChatMessage original, boolean async) { + oldListener.chat(s, original, async); + } + + @Override + public ConnectionProtocol protocol() { + return oldListener == null ? ConnectionProtocol.PLAY : oldListener.protocol(); + } + + @Override + public void handleAnimate(ServerboundSwingPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleAnimate(packet); + } + + @Override + public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlayerCommand(packet); + } + + @Override + public void sendPlayerChatMessage(PlayerChatMessage playerchatmessage, ChatType.Bound chatmessagetype_a) { + oldListener.sendPlayerChatMessage(playerchatmessage, chatmessagetype_a); + } + + @Override + public void sendDisguisedChatMessage(Component ichatbasecomponent, ChatType.Bound chatmessagetype_a) { + oldListener.sendDisguisedChatMessage(ichatbasecomponent, chatmessagetype_a); + } + + @Override + public SocketAddress getRemoteAddress() { + return oldListener.getRemoteAddress(); + } + + @Override + public SocketAddress getRawAddress() { + return oldListener.getRawAddress(); + } + + @Override + public void switchToConfig() { + oldListener.switchToConfig(); + } + + @Override + public void handleInteract(ServerboundInteractPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleInteract(packet); + } + + @Override + public void handleClientCommand(ServerboundClientCommandPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleClientCommand(packet); + } + + @Override + public void handleContainerClose(ServerboundContainerClosePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleContainerClose(packet); + } + + @Override + public void handleContainerClick(ServerboundContainerClickPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleContainerClick(packet); + } + + @Override + public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlaceRecipe(packet); + } + + @Override + public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleContainerButtonClick(packet); + } + + @Override + public void handleSetCreativeModeSlot(ServerboundSetCreativeModeSlotPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSetCreativeModeSlot(packet); + } + + @Override + public void handleSignUpdate(ServerboundSignUpdatePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSignUpdate(packet); + } + + @Override + public void handleKeepAlive(ServerboundKeepAlivePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleKeepAlive(packet); + } + + @Override + public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePlayerAbilities(packet); + } + + @Override + public void handleClientInformation(ServerboundClientInformationPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleClientInformation(packet); + } + + @Override + public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleCustomPayload(packet); + } + + @Override + public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChangeDifficulty(packet); + } + + @Override + public void handleLockDifficulty(ServerboundLockDifficultyPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleLockDifficulty(packet); + } + + @Override + public void handleChatSessionUpdate(ServerboundChatSessionUpdatePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChatSessionUpdate(packet); + } + + @Override + public void handleConfigurationAcknowledged(ServerboundConfigurationAcknowledgedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleConfigurationAcknowledged(packet); + } + + @Override + public void handleChunkBatchReceived(ServerboundChunkBatchReceivedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChunkBatchReceived(packet); + } + + @Override + public void handleBlockEntityTagQuery(ServerboundBlockEntityTagQueryPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleBlockEntityTagQuery(packet); + } + + @Override + public void handleBundleItemSelectedPacket(ServerboundSelectBundleItemPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleBundleItemSelectedPacket(packet); + } + + @Override + public void handleClientTickEnd(ServerboundClientTickEndPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleClientTickEnd(packet); + } + + @Override + public boolean hasInfiniteMaterials() { + return oldListener.hasInfiniteMaterials(); + } + + @Override + public void handleContainerSlotStateChanged(ServerboundContainerSlotStateChangedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleContainerSlotStateChanged(packet); + } + + @Override + public void handleDebugSubscriptionRequest(ServerboundDebugSubscriptionRequestPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleDebugSubscriptionRequest(packet); + } + + @Override + public void handleEntityTagQuery(ServerboundEntityTagQueryPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleEntityTagQuery(packet); + } + + @Override + public void handlePingRequest(ServerboundPingRequestPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handlePingRequest(packet); + } + + @Override + public void handleSignedChatCommand(ServerboundChatCommandSignedPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleSignedChatCommand(packet); + } + + @Override + public void handleChangeGameMode(ServerboundChangeGameModePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleChangeGameMode(packet); + } + + @Override + public void handleCustomClickAction(ServerboundCustomClickActionPacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleCustomClickAction(packet); + } + + @Override + public void handleCookieResponse(ServerboundCookieResponsePacket packet) { + if (handlePacketIn(packet)) { return; } + oldListener.handleCookieResponse(packet); + } + + @Override + public ServerPlayer getPlayer() { + return oldListener.getPlayer(); + } + + @Override + public PacketFlow flow() { + return oldListener == null ? PacketFlow.SERVERBOUND : oldListener.flow(); + } + + @Override + public void onPacketError(Packet var0, Exception var1) throws ReportedException { + oldListener.onPacketError(var0, var1); + } + + @Override + public DisconnectionDetails createDisconnectionInfo(Component var0, Throwable var1) { + return oldListener.createDisconnectionInfo(var0, var1); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java new file mode 100644 index 0000000000..4023acd8d5 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -0,0 +1,579 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; + +import com.denizenscript.denizen.events.player.PlayerReceivesPacketScriptEvent; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet.*; +import com.denizenscript.denizen.utilities.Settings; +import com.denizenscript.denizen.utilities.packets.NetworkInterceptCodeGen; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import net.minecraft.network.*; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.login.ClientLoginPacketListener; +import net.minecraft.network.protocol.status.ClientStatusPacketListener; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerCommonPacketListenerImpl; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.util.debugchart.LocalSampleLogger; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import javax.crypto.Cipher; +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public class DenizenNetworkManagerImpl extends Connection { + + public static > T copyPacket(T original, StreamCodec packetCodec) { + try { + RegistryFriendlyByteBuf copier = new RegistryFriendlyByteBuf(Unpooled.buffer(), CraftRegistry.getMinecraftRegistry()); + packetCodec.encode(copier, original); + return packetCodec.decode(copier); + } + catch (Throwable ex) { + Debug.echoError(ex); + return null; + } + } + + @FunctionalInterface + public interface PacketHandler> { + Packet handlePacket(DenizenNetworkManagerImpl networkManager, T packet) throws Exception; + } + + public static final Map>, List>> packetHandlers = new HashMap<>(); + + public static > void registerPacketHandler(Class packetClass, PacketHandler handler) { + packetHandlers.computeIfAbsent(packetClass, k -> new ArrayList<>()).add(handler); + } + + public static > void registerPacketHandler(Class packetClass, BiConsumer handler) { + registerPacketHandler(packetClass, (networkManager, packet) -> { + handler.accept(networkManager, packet); + return packet; + }); + } + + public final Connection oldManager; + public final DenizenPacketListenerImpl packetListener; + public final ServerPlayer player; + public int packetsSent, packetsReceived; + + public DenizenNetworkManagerImpl(ServerPlayer entityPlayer, Connection oldManager) { + super(getProtocolDirection(oldManager)); + this.oldManager = oldManager; + this.channel = oldManager.channel; + this.player = entityPlayer; + packetListener = (DenizenPacketListenerImpl) NetworkInterceptCodeGen.generateAppropriateInterceptor(this, entityPlayer, DenizenPacketListenerImpl.class, AbstractListenerPlayInImpl.class, ServerGamePacketListenerImpl.class); + if (!(oldManager.getPacketListener() instanceof ServerConfigurationPacketListener)) { + setListener(packetListener); + } + } + + public void setListener(PacketListener listener) { + try { + Connection_packetListener.set(oldManager, listener); + } + catch (IllegalAccessException e) { + Debug.echoError(e); + throw new RuntimeException("Failed to set packet listener due to reflection error", e); + } + } + + public static Connection getConnection(ServerPlayer player) { + try { + return (Connection) ServerGamePacketListener_ConnectionField.get(player.connection); + } + catch (Throwable ex) { + Debug.echoError(ex); + throw new RuntimeException("Failed to get connection from player due to reflection error", ex); + } + } + + public static Connection getConnection(Player player) { + return getConnection(((CraftPlayer) player).getHandle()); + } + + public static DenizenNetworkManagerImpl getNetworkManager(ServerPlayer player) { + return (DenizenNetworkManagerImpl) getConnection(player); + } + + public static DenizenNetworkManagerImpl getNetworkManager(Player player) { + return getNetworkManager(((CraftPlayer) player).getHandle()); + } + + public static void setNetworkManager(Player player) { + ServerPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + ServerGamePacketListenerImpl playerConnection = entityPlayer.connection; + setNetworkManager(playerConnection, new DenizenNetworkManagerImpl(entityPlayer, getConnection(entityPlayer))); + } + + public static void enableNetworkManager() { + for (World w : Bukkit.getWorlds()) { + for (ChunkMap.TrackedEntity tracker : ((CraftWorld) w).getHandle().getChunkSource().chunkMap.entityMap.values()) { + ArrayList connections = new ArrayList<>(tracker.seenBy); + tracker.seenBy.clear(); + for (ServerPlayerConnection connection : connections) { + tracker.seenBy.add(connection.getPlayer().connection); + } + } + } + } + + @Override + public int hashCode() { + return oldManager.hashCode(); + } + + @Override + public boolean equals(Object c2) { + return oldManager.equals(c2); + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + oldManager.channelRegistered(ctx); + } + + @Override + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { + oldManager.channelUnregistered(ctx); + } + + @Override + public void channelActive(ChannelHandlerContext channelhandlercontext) throws Exception { + oldManager.channelActive(channelhandlercontext); + } + + @Override + public void channelInactive(ChannelHandlerContext channelhandlercontext) { + oldManager.channelInactive(channelhandlercontext); + } + + @Override + public boolean isSharable() { + return oldManager.isSharable(); + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + oldManager.handlerAdded(ctx); + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + oldManager.handlerRemoved(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) { + oldManager.exceptionCaught(channelhandlercontext, throwable); + } + + @Override + public void setupInboundProtocol(ProtocolInfo protocolinfo, T t0) { + oldManager.setupInboundProtocol(protocolinfo, t0); + } + + @Override + public void setupOutboundProtocol(ProtocolInfo protocolinfo) { + oldManager.setupOutboundProtocol(protocolinfo); + } + + @Override + protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet packet) { + if (oldManager.channel.isOpen()) { + try { + packet.handle(this.packetListener); + } + catch (Exception e) { + // Do nothing + } + } + } + + @Override + public void setListenerForServerboundHandshake(PacketListener packetlistener) { + oldManager.setListenerForServerboundHandshake(packetlistener); + } + + @Override + public void initiateServerboundStatusConnection(String s, int i, ClientStatusPacketListener packetstatusoutlistener) { + oldManager.initiateServerboundStatusConnection(s, i, packetstatusoutlistener); + } + + @Override + public void initiateServerboundPlayConnection(String s, int i, ClientLoginPacketListener packetloginoutlistener) { + oldManager.initiateServerboundPlayConnection(s, i, packetloginoutlistener); + } + + @Override + public void initiateServerboundPlayConnection(String s, int i, ProtocolInfo protocolinfo, ProtocolInfo protocolinfo1, C c0, boolean flag) { + oldManager.initiateServerboundPlayConnection(s, i, protocolinfo, protocolinfo1, c0, flag); + } + + @Override + public void send(Packet packet) { + send(packet, null); + } + + public static void doPacketOutput(String text) { + if (!NMSHandler.debugPackets) { + return; + } + if (NMSHandler.debugPacketFilter == null || NMSHandler.debugPacketFilter.trim().isEmpty() + || CoreUtilities.toLowerCase(text).contains(NMSHandler.debugPacketFilter)) { + Debug.log(text); + } + } + + public void debugOutputPacket(Packet packet) { + if (packet instanceof ClientboundSetEntityDataPacket) { + StringBuilder output = new StringBuilder(128); + output.append("Packet: ClientboundSetEntityDataPacket sent to ").append(player.getScoreboardName()).append(" for entity ID: ").append(((ClientboundSetEntityDataPacket) packet).id()).append(": "); + List> list = ((ClientboundSetEntityDataPacket) packet).packedItems(); + if (list == null) { + output.append("None"); + } + else { + for (SynchedEntityData.DataValue data : list) { + output.append('[').append(data.id()).append(": ").append(data.value()).append("], "); + } + } + doPacketOutput(output.toString()); + } + else if (packet instanceof ClientboundSetEntityMotionPacket) { + ClientboundSetEntityMotionPacket velPacket = (ClientboundSetEntityMotionPacket) packet; + doPacketOutput("Packet: ClientboundSetEntityMotionPacket sent to " + player.getScoreboardName() + " for entity ID: " + velPacket.id() + ": " + velPacket.movement()); + } + else if (packet instanceof ClientboundAddEntityPacket) { + ClientboundAddEntityPacket addEntityPacket = (ClientboundAddEntityPacket) packet; + doPacketOutput("Packet: ClientboundAddEntityPacket sent to " + player.getScoreboardName() + " for entity ID: " + addEntityPacket.getId() + ": " + "uuid: " + addEntityPacket.getUUID() + + ", type: " + addEntityPacket.getType() + ", at: " + addEntityPacket.getX() + "," + addEntityPacket.getY() + "," + addEntityPacket.getZ() + ", data: " + addEntityPacket.getData()); + } + else if (packet instanceof ClientboundMapItemDataPacket) { + ClientboundMapItemDataPacket mapPacket = (ClientboundMapItemDataPacket) packet; + doPacketOutput("Packet: ClientboundMapItemDataPacket sent to " + player.getScoreboardName() + " for map ID: " + mapPacket.mapId() + ", scale: " + mapPacket.scale() + ", locked: " + mapPacket.locked()); + } + else if (packet instanceof ClientboundRemoveEntitiesPacket) { + ClientboundRemoveEntitiesPacket removePacket = (ClientboundRemoveEntitiesPacket) packet; + doPacketOutput("Packet: ClientboundRemoveEntitiesPacket sent to " + player.getScoreboardName() + " for entities: " + removePacket.getEntityIds().stream().map(Object::toString).collect(Collectors.joining(", "))); + } + else if (packet instanceof ClientboundPlayerInfoUpdatePacket) { + ClientboundPlayerInfoUpdatePacket playerInfoPacket = (ClientboundPlayerInfoUpdatePacket) packet; + doPacketOutput("Packet: ClientboundPlayerInfoPacket sent to " + player.getScoreboardName() + " of types " + playerInfoPacket.actions() + " for player profiles: " + + playerInfoPacket.entries().stream().map(p -> "mode=" + p.gameMode() + "/latency=" + p.latency() + "/display=" + p.displayName() + "/name=" + p.profile().name() + "/id=" + p.profile().id() + "/" + + p.profile().properties().asMap().entrySet().stream().map(e -> e.getKey() + "=" + e.getValue().stream().map(v -> v.value() + ";" + v.signature()).collect(Collectors.joining(";;;"))).collect(Collectors.joining("/"))).collect(Collectors.joining(", "))); + } + else { + doPacketOutput("Packet: " + packet.getClass().getCanonicalName() + " sent to " + player.getScoreboardName()); + } + } + + @Override + public void send(Packet packet, ChannelFutureListener channelFutureListener) { + send(packet, channelFutureListener, true); + } + + @Override + public void send(Packet packet, @Nullable ChannelFutureListener channelFutureListener, boolean flush) { + if (!Bukkit.isPrimaryThread()) { + if (Settings.cache_warnOnAsyncPackets + && !(packet instanceof ClientboundSystemChatPacket) && !(packet instanceof ClientboundPlayerChatPacket) // Vanilla supports an async chat system, though it's normally disabled, some plugins use this as justification for sending messages async + && !(packet instanceof ClientboundCommandSuggestionsPacket)) { // Async tab complete is wholly unsupported in Spigot (and will cause an exception), however Paper explicitly adds async support (for unclear reasons), so let it through too + Debug.echoError("Warning: packet sent off main thread! This is completely unsupported behavior! Denizen network interceptor ignoring packet to avoid crash. Packet class: " + + packet.getClass().getCanonicalName() + " sent to " + player.getScoreboardName() + " identify the sender of the packet from the stack trace:"); + try { + throw new RuntimeException("Trace"); + } + catch (Exception ex) { + Debug.echoError(ex); + } + } + oldManager.send(packet, channelFutureListener, flush); + return; + } + if (NMSHandler.debugPackets) { + debugOutputPacket(packet); + } + packetsSent++; + if (packet instanceof ClientboundBundlePacket bundlePacket) { + List> processedPackets = new ArrayList<>(); + boolean anyChange = false; + for (Packet _subPacket : bundlePacket.subPackets()) { + // Bundle packets with non-game packets shouldn't ever be sent while the Denizen interceptor is active + Packet subPacket = (Packet) _subPacket; + Packet processed = processPacketHandlersFor(subPacket); + anyChange = anyChange || processed != subPacket; + if (processed != null) { + processedPackets.add(processed); + } + } + if (processedPackets.isEmpty()) { + return; + } + if (anyChange) { + packet = new ClientboundBundlePacket(processedPackets); + } + } + else { + Packet processed = processPacketHandlersFor((Packet) packet); + if (processed == null) { + return; + } + packet = processed; + } + oldManager.send(packet, channelFutureListener, flush); + } + + @Override + public void runOnceConnected(Consumer consumer) { + oldManager.runOnceConnected(consumer); + } + + @Override + public void flushChannel() { + oldManager.flushChannel(); + } + + public Packet processPacketHandlersFor(Packet packet) { + if (packet == null) { + return null; + } + List> packetHandlers = DenizenNetworkManagerImpl.packetHandlers.get(packet.getClass()); + if (packetHandlers != null) { + for (PacketHandler _packetHandler : packetHandlers) { + PacketHandler> packetHandler = (PacketHandler>) _packetHandler; + Packet processed; + try { + processed = packetHandler.handlePacket(this, packet); + } + catch (Exception ex) { + Debug.echoError("Packet handler for " + packet.getClass().getCanonicalName() + " threw an exception:"); + Debug.echoError(ex); + continue; + } + if (processed == null) { + if (NMSHandler.debugPackets) { + doPacketOutput("DENIED PACKET - " + packet.getClass().getCanonicalName() + " DENIED FROM SEND TO " + player.getScoreboardName()); + } + return null; + } + packet = processed; + } + } + if (PlayerReceivesPacketScriptEvent.instance.eventData.isEnabled & PlayerReceivesPacketScriptEvent.fireFor(player.getBukkitEntity(), packet)) { + if (NMSHandler.debugPackets) { + doPacketOutput("DENIED PACKET - " + packet.getClass().getCanonicalName() + " DENIED FROM SEND TO " + player.getScoreboardName() + " due to event"); + } + return null; + } + return packet; + } + + static { + ActionBarEventPacketHandlers.registerHandlers(); + AttachPacketHandlers.registerHandlers(); + BlockLightPacketHandlers.registerHandlers(); + DenizenPacketHandlerPacketHandlers.registerHandlers(); + EntityMetadataPacketHandlers.registerHandlers(); + DisguisePacketHandlers.registerHandlers(); + FakeBlocksPacketHandlers.registerHandlers(); + FakeEquipmentPacketHandlers.registerHandlers(); + FakePlayerPacketHandlers.registerHandlers(); + HiddenEntitiesPacketHandlers.registerHandlers(); + HideParticlesPacketHandlers.registerHandlers(); + PlayerHearsSoundEventPacketHandlers.registerHandlers(); + ProfileEditorImpl.registerHandlers(); + TablistUpdateEventPacketHandlers.registerHandlers(); + } + + @Override + public void tick() { + oldManager.tick(); + } + + @Override + public SocketAddress getRemoteAddress() { + return oldManager.getRemoteAddress(); + } + + @Override + public String getLoggableAddress(boolean flag) { + return oldManager.getLoggableAddress(flag); + } + + @Override + public void disconnect(Component ichatbasecomponent) { + if (!player.getBukkitEntity().isOnline()) { // Workaround Paper duplicate quit event issue + return; + } + oldManager.disconnect(ichatbasecomponent); + } + + @Override + public void disconnect(DisconnectionDetails disconnectiondetails) { + oldManager.disconnect(disconnectiondetails); + } + + @Override + public boolean isMemoryConnection() { + return oldManager != null && oldManager.isMemoryConnection(); + } + + @Override + public PacketFlow getReceiving() { + return oldManager.getReceiving(); + } + + @Override + public PacketFlow getSending() { + return oldManager.getSending(); + } + + @Override + public void configurePacketHandler(ChannelPipeline channelpipeline) { + oldManager.configurePacketHandler(channelpipeline); + } + + @Override + public void setEncryptionKey(Cipher cipher, Cipher cipher1) { + oldManager.setEncryptionKey(cipher, cipher1); + } + + @Override + public boolean isEncrypted() { + return oldManager.isEncrypted(); + } + + @Override + public boolean isConnected() { + return oldManager.isConnected(); + } + + @Override + public boolean isConnecting() { + return oldManager.isConnecting(); + } + + @Override + public PacketListener getPacketListener() { + return oldManager.getPacketListener(); + } + + @Override + public DisconnectionDetails getDisconnectionDetails() { + return oldManager.getDisconnectionDetails(); + } + + @Override + public void setReadOnly() { + oldManager.setReadOnly(); + } + + @Override + public void setupCompression(int i, boolean b) { + oldManager.setupCompression(i, b); + } + + @Override + public void handleDisconnection() { + oldManager.handleDisconnection(); + } + + @Override + public float getAverageReceivedPackets() { + return oldManager.getAverageReceivedPackets(); + } + + @Override + public float getAverageSentPackets() { + return oldManager.getAverageSentPackets(); + } + + @Override + public void setBandwidthLogger(LocalSampleLogger localsamplelogger) { + oldManager.setBandwidthLogger(localsamplelogger); + } + + ////////////////////////////////// + //// Reflection Methods/Fields + /////////// + + private static final Field protocolDirectionField = ReflectionHelper.getFields(Connection.class).get("receiving", PacketFlow.class); + public static final Field Connection_packetListener = ReflectionHelper.getFields(Connection.class).get("packetListener", PacketListener.class); + private static final Field ServerGamePacketListener_ConnectionField = ReflectionHelper.getFields(ServerCommonPacketListenerImpl.class).get("connection"); + private static final MethodHandle ServerGamePacketListener_ConnectionSetter = ReflectionHelper.getFinalSetter(ServerCommonPacketListenerImpl.class, "connection"); + + private static PacketFlow getProtocolDirection(Connection networkManager) { + PacketFlow direction = null; + try { + direction = (PacketFlow) protocolDirectionField.get(networkManager); + } + catch (Exception e) { + Debug.echoError(e); + } + return direction; + } + + private static void setNetworkManager(ServerGamePacketListenerImpl playerConnection, Connection networkManager) { + try { + ServerGamePacketListener_ConnectionSetter.invoke(playerConnection, networkManager); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + @Override + public boolean acceptInboundMessage(Object msg) throws Exception { + return oldManager.acceptInboundMessage(msg); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + oldManager.channelRead(ctx, msg); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + oldManager.channelReadComplete(ctx); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + oldManager.userEventTriggered(ctx, evt); + } + + @Override + public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { + oldManager.channelWritabilityChanged(ctx); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenPacketListenerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenPacketListenerImpl.java new file mode 100644 index 0000000000..224b0c76ba --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenPacketListenerImpl.java @@ -0,0 +1,121 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; + +import com.denizenscript.denizen.events.player.PlayerChangesSignScriptEvent; +import com.denizenscript.denizen.events.player.PlayerSteersEntityScriptEvent; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketInResourcePackStatusImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketInSteerVehicleImpl; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.objects.MaterialTag; +import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; +import com.denizenscript.denizen.utilities.packets.DenizenPacketHandler; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.ServerboundResourcePackPacket; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.event.block.SignChangeEvent; + +public class DenizenPacketListenerImpl extends AbstractListenerPlayInImpl { + + public BlockPos fakeSignExpected; + + public DenizenPacketListenerImpl(DenizenNetworkManagerImpl networkManager, ServerPlayer entityPlayer) { + super(networkManager, entityPlayer, entityPlayer.connection); + } + + @Override + public void handlePlayerInput(final ServerboundPlayerInputPacket packet) { + if (!PlayerSteersEntityScriptEvent.instance.eventData.isEnabled) { + super.handlePlayerInput(packet); + return; + } + DenizenPacketHandler.instance.receivePacket(player.getBukkitEntity(), new PacketInSteerVehicleImpl(packet), () -> super.handlePlayerInput(packet)); + } + + @Override + public void handleResourcePackResponse(ServerboundResourcePackPacket packet) { + DenizenPacketHandler.instance.receivePacket(player.getBukkitEntity(), new PacketInResourcePackStatusImpl(packet)); + super.handleResourcePackResponse(packet); + } + + @Override + public void handleUseItem(ServerboundUseItemPacket packet) { + DenizenPacketHandler.instance.receivePlacePacket(player.getBukkitEntity()); + super.handleUseItem(packet); + } + + @Override + public void handlePlayerAction(ServerboundPlayerActionPacket packet) { + DenizenPacketHandler.instance.receiveDigPacket(player.getBukkitEntity()); + super.handlePlayerAction(packet); + } + + @Override + public void handleAnimate(ServerboundSwingPacket packet) { + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(player.getUUID(), getCraftPlayer()); + if (override != null && (override.hand != null || override.offhand != null)) { + player.getBukkitEntity().updateInventory(); + } + super.handleAnimate(packet); + } + + @Override + public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(player.getUUID(), getCraftPlayer()); + if (override != null && override.hand != null) { + Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), player.getBukkitEntity()::updateInventory, 2); + } + super.handleSetCarriedItem(packet); + } + + @Override + public void handleContainerClick(ServerboundContainerClickPacket packet) { + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(player.getUUID(), getCraftPlayer()); + if (override != null && packet.containerId() == 0) { + Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), player.getBukkitEntity()::updateInventory, 1); + } + super.handleContainerClick(packet); + } + + @Override + public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { + if (NMSHandler.debugPackets) { + Debug.log("Custom packet payload: " + packet.payload().type().id().toString() + " sent from " + player.getScoreboardName()); + } + super.handleCustomPayload(packet); + } + + @Override + public void handleSignUpdate(ServerboundSignUpdatePacket packet) { + if (fakeSignExpected != null && packet.getPos().equals(fakeSignExpected)) { + LocationTag loc = new LocationTag(player.getBukkitEntity().getWorld(), fakeSignExpected.getX(), fakeSignExpected.getY(), fakeSignExpected.getZ()); + this.connection.send(new ClientboundBlockUpdatePacket(player.level(), fakeSignExpected)); + PlayerChangesSignScriptEvent evt = (PlayerChangesSignScriptEvent) PlayerChangesSignScriptEvent.instance.clone(); + evt.material = new MaterialTag(org.bukkit.Material.OAK_WALL_SIGN); + evt.location = new LocationTag(player.getBukkitEntity().getLocation()); + evt.event = new SignChangeEvent(CraftBlock.at(player.level(), fakeSignExpected), player.getBukkitEntity(), packet.getLines()); + fakeSignExpected = null; + evt.fire(evt.event); + } + super.handleSignUpdate(packet); + } + + @Override + public void handleMovePlayer(ServerboundMovePlayerPacket packet) { + if (DenizenPacketHandler.forceNoclip.contains(player.getUUID())) { + player.noPhysics = true; + } + super.handleMovePlayer(packet); + } + + // For compatibility with other plugins using Reflection weirdly... + @Override + public void send(Packet packet) { + super.send(packet); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java new file mode 100644 index 0000000000..11a61644f0 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java @@ -0,0 +1,167 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; + +import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.blocks.FakeBlock; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import io.netty.buffer.Unpooled; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.Strategy; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlockStates; +import org.bukkit.craftbukkit.block.data.CraftBlockData; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FakeBlockHelper { + + public static Field CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getFirstOfType(List.class); + public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); + public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); + public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; + public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get("packedXZ"); + public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get("y"); + public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); + public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 2).findFirst().get(); + + public static BlockState getNMSState(FakeBlock block) { + return ((CraftBlockData) block.material.getModernData()).getState(); + } + + public static boolean anyBlocksInSection(List blocks, int y) { + int minY = y << 4; + int maxY = (y << 4) + 16; + for (FakeBlock block : blocks) { + int blockY = block.location.getBlockY(); + if (blockY >= minY && blockY < maxY) { + return true; + } + } + return false; + } + + public static Field PAPER_CHUNK_READY; + public static boolean tryPaperPatch = true; + + public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket newPacket, ClientboundLevelChunkWithLightPacket oldPacket) { + if (!Denizen.supportsPaper || !tryPaperPatch) { + return; + } + try { + if (PAPER_CHUNK_READY == null) { + PAPER_CHUNK_READY = ReflectionHelper.getFields(ClientboundLevelChunkWithLightPacket.class).get("ready"); + } + } + catch (Throwable ex) { + tryPaperPatch = false; + Debug.echoError("Paper packet patch failed:"); + Debug.echoError(ex); + return; + } + try { + PAPER_CHUNK_READY.setBoolean(newPacket, true); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + } + + public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalPacket, int chunkX, int chunkZ, List blocks) { + try { + ClientboundLevelChunkWithLightPacket duplicateCorePacket = DenizenNetworkManagerImpl.copyPacket(originalPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(duplicateCorePacket, originalPacket); + RegistryFriendlyByteBuf copier = new RegistryFriendlyByteBuf(Unpooled.buffer(), CraftRegistry.getMinecraftRegistry()); + originalPacket.getChunkData().write(copier); + ClientboundLevelChunkPacketData packet = new ClientboundLevelChunkPacketData(copier, chunkX, chunkZ); + FriendlyByteBuf serial = originalPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf outputSerial = new FriendlyByteBuf(Unpooled.buffer(serial.readableBytes())); + List blockEntities = new ArrayList((List) CHUNKDATA_BLOCK_ENTITIES.get(originalPacket.getChunkData())); + CHUNKDATA_BLOCK_ENTITIES.set(packet, blockEntities); + for (int i = 0; i < blockEntities.size(); i++) { + Object blockEnt = blockEntities.get(i); + int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); + int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int x = (chunkX << 4) + ((xz >> 4) & 15); + int z = (chunkZ << 4) + (xz & 15); + for (FakeBlock block : blocks) { + LocationTag loc = block.location; + if (loc.getBlockX() == x && loc.getBlockY() == y && loc.getBlockZ() == z && block.material != null) { + BlockEntity newBlockEnt = CraftBlockStates.createNewTileEntity(block.material.getMaterial()); + Object newData = CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR.invoke(xz, y, newBlockEnt.getType(), newBlockEnt.getUpdateTag(CraftRegistry.getMinecraftRegistry())); + blockEntities.set(i, newData); + break; + } + } + } + int worldMinY = world.getMinHeight(); + int worldMaxY = world.getMaxHeight(); + int minChunkY = worldMinY >> 4; + int maxChunkY = worldMaxY >> 4; + Registry biomeRegistry = ((CraftWorld) world).getHandle().registryAccess().lookupOrThrow(Registries.BIOME); + for (int y = minChunkY; y < maxChunkY; y++) { + int blockCount = serial.readShort(); + // reflected constructors as workaround for spigot remapper bug - Mojang "IdMap" became Spigot "IRegistry" but should be "Registry" + PalettedContainer states = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); + states.read(serial); + PalettedContainer biomes = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry)); + biomes.read(serial); + if (anyBlocksInSection(blocks, y)) { + int minY = y << 4; + int maxY = (y << 4) + 16; + for (FakeBlock block : blocks) { + int blockY = block.location.getBlockY(); + if (blockY >= minY && blockY < maxY && block.material != null) { + int blockX = block.location.getBlockX(); + int blockZ = block.location.getBlockZ(); + blockX -= (blockX >> 4) * 16; + blockY -= (blockY >> 4) * 16; + blockZ -= (blockZ >> 4) * 16; + BlockState oldState = states.get(blockX, blockY, blockZ); + BlockState newState = getNMSState(block); + if (oldState.isAir() && !newState.isAir()) { + blockCount++; + } + else if (newState.isAir() && !oldState.isAir()) { + blockCount--; + } + states.set(blockX, blockY, blockZ, newState); + } + } + } + outputSerial.writeShort(blockCount); + states.write(outputSerial); + biomes.write(outputSerial); + } + byte[] outputBytes = outputSerial.array(); + CHUNKDATA_BUFFER_SETTER.invoke(packet, outputBytes); + CHUNKPACKET_CHUNKDATA_SETTER.invoke(duplicateCorePacket, packet); + return duplicateCorePacket; + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return null; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/ActionBarEventPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/ActionBarEventPacketHandlers.java new file mode 100644 index 0000000000..c1f641f7b5 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/ActionBarEventPacketHandlers.java @@ -0,0 +1,39 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.events.player.PlayerReceivesActionbarScriptEvent; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.objects.core.ElementTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import org.bukkit.craftbukkit.util.CraftChatMessage; + +public class ActionBarEventPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetActionBarTextPacket.class, ActionBarEventPacketHandlers::processActionbarPacket); + } + + public static ClientboundSetActionBarTextPacket processActionbarPacket(DenizenNetworkManagerImpl networkManager, ClientboundSetActionBarTextPacket actionbarPacket) { + PlayerReceivesActionbarScriptEvent event = PlayerReceivesActionbarScriptEvent.instance; + if (!event.loaded) { + return actionbarPacket; + } + event.reset(); + Component actionbarText = actionbarPacket.text(); + event.message = new ElementTag(FormattedTextHelper.stringify(Handler.componentToSpigot(actionbarText)), true); + event.rawJson = new ElementTag(CraftChatMessage.toJSON(actionbarText), true); + event.system = new ElementTag(false); + event.player = PlayerTag.mirrorBukkitPlayer(networkManager.player.getBukkitEntity()); + event = (PlayerReceivesActionbarScriptEvent) event.triggerNow(); + if (event.cancelled) { + return null; + } + if (event.modified) { + return new ClientboundSetActionBarTextPacket(Handler.componentToNMS(event.altMessageDetermination)); + } + return actionbarPacket; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/AttachPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/AttachPacketHandlers.java new file mode 100644 index 0000000000..b1dc7adaf2 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/AttachPacketHandlers.java @@ -0,0 +1,307 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; +import com.denizenscript.denizencore.utilities.CoreConfiguration; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.phys.Vec3; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftVector; +import org.bukkit.util.Vector; + +import java.lang.reflect.Field; +import java.util.Set; + +public class AttachPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundMoveEntityPacket.class, AttachPacketHandlers::processAttachToForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundRotateHeadPacket.class, AttachPacketHandlers::processAttachToForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEntityMotionPacket.class, AttachPacketHandlers::processAttachToForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundTeleportEntityPacket.class, AttachPacketHandlers::processAttachToForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundRemoveEntitiesPacket.class, AttachPacketHandlers::processAttachToForPacket); + } + + public static Field POS_X_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("xa", short.class); + public static Field POS_Y_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("ya", short.class); + public static Field POS_Z_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("za", short.class); + public static Field YAW_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("yRot", byte.class); + public static Field PITCH_PACKENT = ReflectionHelper.getFields(ClientboundMoveEntityPacket.class).get("xRot", byte.class); + + public static Vector VECTOR_ZERO = new Vector(0, 0, 0); + + public static void tryProcessMovePacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundMoveEntityPacket packet, Entity e) throws IllegalAccessException { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + ClientboundMoveEntityPacket pNew; + int newId = att.attached.getBukkitEntity().getEntityId(); + if (packet instanceof ClientboundMoveEntityPacket.Pos) { + pNew = new ClientboundMoveEntityPacket.Pos(newId, packet.getXa(), packet.getYa(), packet.getZa(), packet.isOnGround()); + } + else if (packet instanceof ClientboundMoveEntityPacket.Rot) { + pNew = new ClientboundMoveEntityPacket.Rot(newId, Mth.packDegrees(packet.getYRot()), Mth.packDegrees(packet.getXRot()), packet.isOnGround()); + } + else if (packet instanceof ClientboundMoveEntityPacket.PosRot) { + pNew = new ClientboundMoveEntityPacket.PosRot(newId, packet.getXa(), packet.getYa(), packet.getZa(), Mth.packDegrees(packet.getYRot()), Mth.packDegrees(packet.getXRot()), packet.isOnGround()); + } + else { + if (CoreConfiguration.debugVerbose) { + Debug.echoError("Impossible move-entity packet class: " + packet.getClass().getCanonicalName()); + } + return; + } + if (att.positionalOffset != null) { + boolean isRotate = packet instanceof ClientboundMoveEntityPacket.PosRot || packet instanceof ClientboundMoveEntityPacket.Rot; + float yaw, pitch; + if (att.noRotate) { + Entity attachedEntity = ((CraftEntity) att.attached.getBukkitEntity()).getHandle(); + yaw = attachedEntity.getYRot(); + pitch = attachedEntity.getXRot(); + } + else if (isRotate) { + yaw = packet.getYRot(); + pitch = packet.getXRot(); + } + else { + yaw = e.getYRot(); + pitch = e.getXRot(); + } + if (att.noPitch) { + pitch = ((CraftEntity) att.attached.getBukkitEntity()).getHandle().getXRot(); + } + float newYaw = yaw; + if (isRotate) { + newYaw = EntityAttachmentHelper.normalizeAngle(newYaw + att.positionalOffset.getYaw()); + pitch = EntityAttachmentHelper.normalizeAngle(pitch + att.positionalOffset.getPitch()); + } + Vector goalPosition = att.fixedForOffset(new Vector(e.getX(), e.getY(), e.getZ()), e.getYRot(), e.getXRot()); + Vector oldPos = att.visiblePositions.get(networkManager.player.getUUID()); + boolean forceTele = false; + if (oldPos == null) { + oldPos = att.attached.getLocation().toVector(); + forceTele = true; + } + Vector moveNeeded = goalPosition.clone().subtract(oldPos); + att.visiblePositions.put(networkManager.player.getUUID(), goalPosition.clone()); + int offX = (int) (moveNeeded.getX() * (32 * 128)); + int offY = (int) (moveNeeded.getY() * (32 * 128)); + int offZ = (int) (moveNeeded.getZ() * (32 * 128)); + if ((isRotate && att.offsetRelative) || forceTele || offX < Short.MIN_VALUE || offX > Short.MAX_VALUE + || offY < Short.MIN_VALUE || offY > Short.MAX_VALUE + || offZ < Short.MIN_VALUE || offZ > Short.MAX_VALUE) { + ClientboundTeleportEntityPacket newTeleportPacket = new ClientboundTeleportEntityPacket( + att.attached.getBukkitEntity().getEntityId(), + new PositionMoveRotation(CraftVector.toNMS(goalPosition), Vec3.ZERO, newYaw, pitch), + Set.of(), + e.onGround() + ); + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Move-Tele Packet: " + newTeleportPacket.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName() + " with original yaw " + yaw + " adapted to " + newYaw); + } + networkManager.oldManager.send(newTeleportPacket); + } + else { + POS_X_PACKENT.setShort(pNew, (short) Mth.clamp(offX, Short.MIN_VALUE, Short.MAX_VALUE)); + POS_Y_PACKENT.setShort(pNew, (short) Mth.clamp(offY, Short.MIN_VALUE, Short.MAX_VALUE)); + POS_Z_PACKENT.setShort(pNew, (short) Mth.clamp(offZ, Short.MIN_VALUE, Short.MAX_VALUE)); + if (isRotate) { + YAW_PACKENT.setByte(pNew, EntityAttachmentHelper.compressAngle(yaw)); + PITCH_PACKENT.setByte(pNew, EntityAttachmentHelper.compressAngle(pitch)); + } + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Move Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName() + " with original yaw " + yaw + " adapted to " + newYaw); + } + networkManager.oldManager.send(pNew); + } + } + else { + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Replica-Move Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName()); + } + networkManager.oldManager.send(pNew); + } + } + } + } + if (e.passengers != null && !e.passengers.isEmpty()) { + for (Entity ent : e.passengers) { + tryProcessMovePacketForAttach(networkManager, packet, ent); + } + } + } + + public static void tryProcessRotateHeadPacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundRotateHeadPacket packet, Entity e) throws IllegalAccessException { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + float yaw = packet.getYHeadRot(); + Entity attachedEntity = ((CraftEntity) att.attached.getBukkitEntity()).getHandle(); + if (att.positionalOffset != null) { + if (att.noRotate) { + yaw = attachedEntity.getYRot(); + } + yaw = EntityAttachmentHelper.normalizeAngle(yaw + att.positionalOffset.getYaw()); + } + ClientboundRotateHeadPacket pNew = new ClientboundRotateHeadPacket(attachedEntity, EntityAttachmentHelper.compressAngle(yaw)); + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Head Rotation Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName()); + } + networkManager.oldManager.send(pNew); + } + } + } + if (e.passengers != null && !e.passengers.isEmpty()) { + for (Entity ent : e.passengers) { + tryProcessRotateHeadPacketForAttach(networkManager, packet, ent); + } + } + } + + public static void tryProcessVelocityPacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundSetEntityMotionPacket packet, Entity e) { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + ClientboundSetEntityMotionPacket pNew = new ClientboundSetEntityMotionPacket(att.attached.getBukkitEntity().getEntityId(), packet.movement()); + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Velocity Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + " sent to " + networkManager.player.getScoreboardName()); + } + networkManager.oldManager.send(pNew); + } + } + } + if (e.passengers != null && !e.passengers.isEmpty()) { + for (Entity ent : e.passengers) { + tryProcessVelocityPacketForAttach(networkManager, packet, ent); + } + } + } + + public static void tryProcessTeleportPacketForAttach(DenizenNetworkManagerImpl networkManager, ClientboundTeleportEntityPacket packet, Entity e, Vector relative) throws IllegalAccessException { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + ClientboundTeleportEntityPacket pNew; + Vector resultPos = CraftVector.toBukkit(packet.change().position()).add(relative); + if (att.positionalOffset != null) { + resultPos = att.fixedForOffset(resultPos, e.getYRot(), e.getXRot()); + float yaw, pitch; + if (att.noRotate) { + Entity attachedEntity = ((CraftEntity) att.attached.getBukkitEntity()).getHandle(); + yaw = attachedEntity.getYRot(); + pitch = attachedEntity.getXRot(); + } + else { + yaw = packet.change().yRot(); + pitch = packet.change().xRot(); + } + if (att.noPitch) { + pitch = ((CraftEntity) att.attached.getBukkitEntity()).getHandle().getXRot(); + } + float newYaw = EntityAttachmentHelper.normalizeAngle(yaw + att.positionalOffset.getYaw()); + pitch = EntityAttachmentHelper.normalizeAngle(pitch + att.positionalOffset.getPitch()); + pNew = new ClientboundTeleportEntityPacket( + att.attached.getBukkitEntity().getEntityId(), + new PositionMoveRotation(CraftVector.toNMS(resultPos), packet.change().deltaMovement(), newYaw, pitch), + packet.relatives(), + packet.onGround() + ); + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("Attach Teleport Packet: " + pNew.getClass().getCanonicalName() + " for " + att.attached.getUUID() + + " sent to " + networkManager.player.getScoreboardName() + " with raw yaw " + yaw + " adapted to " + newYaw); + } + } + else { + pNew = new ClientboundTeleportEntityPacket(att.attached.getBukkitEntity().getEntityId(), packet.change(), packet.relatives(), packet.onGround()); + } + att.visiblePositions.put(networkManager.player.getUUID(), resultPos.clone()); + networkManager.oldManager.send(pNew); + } + } + } + if (e.passengers != null && !e.passengers.isEmpty()) { + for (Entity ent : e.passengers) { + tryProcessTeleportPacketForAttach(networkManager, packet, ent, new Vector(ent.getX() - e.getX(), ent.getY() - e.getY(), ent.getZ() - e.getZ())); + } + } + } + + public static Packet processAttachToForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (EntityAttachmentHelper.toEntityToData.isEmpty()) { + return packet; + } + try { + if (packet instanceof ClientboundMoveEntityPacket moveEntityPacket) { + Entity e = moveEntityPacket.getEntity(networkManager.player.level()); + if (e == null) { + return packet; + } + if (!e.isPassenger()) { + tryProcessMovePacketForAttach(networkManager, moveEntityPacket, e); + } + return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; + } + else if (packet instanceof ClientboundRotateHeadPacket rotateHeadPacket) { + Entity e = rotateHeadPacket.getEntity(networkManager.player.level()); + if (e == null) { + return packet; + } + tryProcessRotateHeadPacketForAttach(networkManager, rotateHeadPacket, e); + return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; + } + else if (packet instanceof ClientboundSetEntityMotionPacket setEntityMotionPacket) { + int ider = setEntityMotionPacket.id(); + Entity e = networkManager.player.level().getEntity(ider); + if (e == null) { + return packet; + } + tryProcessVelocityPacketForAttach(networkManager, setEntityMotionPacket, e); + return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; + } + else if (packet instanceof ClientboundTeleportEntityPacket teleportEntityPacket) { + int ider = teleportEntityPacket.id(); + Entity e = networkManager.player.level().getEntity(ider); + if (e == null) { + return packet; + } + tryProcessTeleportPacketForAttach(networkManager, teleportEntityPacket, e, VECTOR_ZERO); + return EntityAttachmentHelper.denyOriginalPacketSend(networkManager.player.getUUID(), e.getUUID()) ? null : packet; + } + else if (packet instanceof ClientboundRemoveEntitiesPacket removeEntitiesPacket) { + for (int id : removeEntitiesPacket.getEntityIds()) { + Entity e = networkManager.player.level().getEntity(id); + if (e != null) { + EntityAttachmentHelper.EntityAttachedToMap attList = EntityAttachmentHelper.toEntityToData.get(e.getUUID()); + if (attList != null) { + for (EntityAttachmentHelper.PlayerAttachMap attMap : attList.attachedToMap.values()) { + EntityAttachmentHelper.AttachmentData att = attMap.getAttachment(networkManager.player.getUUID()); + if (attMap.attached.isValid() && att != null) { + att.visiblePositions.remove(networkManager.player.getUUID()); + } + } + } + } + } + } + } + catch (Exception ex) { + Debug.echoError(ex); + } + return packet; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/BlockLightPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/BlockLightPacketHandlers.java new file mode 100644 index 0000000000..0a6f0257bc --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/BlockLightPacketHandlers.java @@ -0,0 +1,27 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.abstracts.BlockLight; +import com.denizenscript.denizen.nms.v26_1.impl.blocks.BlockLightImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; + +public class BlockLightPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLightUpdatePacket.class, BlockLightPacketHandlers::processLightUpdatePacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, BlockLightPacketHandlers::processBlockUpdatePacket); + } + + public static void processLightUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundLightUpdatePacket lightUpdatePacket) { + if (!BlockLight.lightsByChunk.isEmpty()) { + BlockLightImpl.checkIfLightsBrokenByPacket(lightUpdatePacket, networkManager.player.level()); + } + } + + public static void processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { + if (!BlockLight.lightsByChunk.isEmpty()) { + BlockLightImpl.checkIfLightsBrokenByPacket(blockUpdatePacket, networkManager.player.level()); + } + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java new file mode 100644 index 0000000000..43f76611ee --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java @@ -0,0 +1,47 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.events.player.PlayerReceivesMessageScriptEvent; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketOutChatImpl; +import com.denizenscript.denizen.utilities.packets.DenizenPacketHandler; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; + +public class DenizenPacketHandlerPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSystemChatPacket.class, DenizenPacketHandlerPacketHandlers::processPacketHandlerForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundPlayerChatPacket.class, DenizenPacketHandlerPacketHandlers::processPacketHandlerForPacket); + } + + public static Packet processPacketHandlerForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (DenizenPacketHandler.instance.shouldInterceptChatPacket()) { + PacketOutChatImpl packetHelper = null; + boolean isActionbar = false; + if (packet instanceof ClientboundSystemChatPacket chatPacket) { + isActionbar = chatPacket.overlay(); + packetHelper = new PacketOutChatImpl(chatPacket); + if (packetHelper.rawJson == null) { // Makes no sense but this can be null in weird edge cases + return packet; + } + } + else if (packet instanceof ClientboundPlayerChatPacket playerChatPacket) { + packetHelper = new PacketOutChatImpl(playerChatPacket); + } + if (packetHelper != null) { + PlayerReceivesMessageScriptEvent result = DenizenPacketHandler.instance.sendPacket(networkManager.player.getBukkitEntity(), packetHelper); + if (result != null) { + if (result.cancelled) { + return null; + } + if (result.modified) { + return new ClientboundSystemChatPacket(result.altMessageDetermination, isActionbar); + } + } + } + } + return packet; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DisguisePacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DisguisePacketHandlers.java new file mode 100644 index 0000000000..12f13d8070 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DisguisePacketHandlers.java @@ -0,0 +1,160 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; +import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; +import com.denizenscript.denizen.utilities.entity.FakeEntity; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.level.Level; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.ToIntFunction; + +public class DisguisePacketHandlers { + + public static void registerHandlers() { + registerPacketHandler(ClientboundSetEntityDataPacket.class, ClientboundSetEntityDataPacket::id, DisguisePacketHandlers::processEntityDataPacket); + registerPacketHandler(ClientboundUpdateAttributesPacket.class, ClientboundUpdateAttributesPacket::getEntityId, DisguisePacketHandlers::processAttributesPacket); + registerPacketHandler(ClientboundAddEntityPacket.class, ClientboundAddEntityPacket::getId, DisguisePacketHandlers::sendDisguiseForPacket); + registerPacketHandler(ClientboundTeleportEntityPacket.class, ClientboundTeleportEntityPacket::id, DisguisePacketHandlers::processTeleportPacket); + registerPacketHandler(ClientboundMoveEntityPacket.Rot.class, ClientboundMoveEntityPacket::getEntity, DisguisePacketHandlers::processMoveEntityRotPacket); + registerPacketHandler(ClientboundMoveEntityPacket.PosRot.class, ClientboundMoveEntityPacket::getEntity, DisguisePacketHandlers::processMoveEntityPosRotPacket); + } + + private static boolean antiDuplicate = false; + + public static > void registerPacketHandler(Class packetType, ToIntFunction idGetter, DisguisePacketHandler handler) { + registerPacketHandler(packetType, (packet, level) -> level.getEntity(idGetter.applyAsInt(packet)), handler); + } + + public static > void registerPacketHandler(Class packetType, BiFunction entityGetter, DisguisePacketHandler handler) { + DenizenNetworkManagerImpl.registerPacketHandler(packetType, (networkManager, packet) -> { + if (DisguiseCommand.disguises.isEmpty() || antiDuplicate) { + return packet; + } + Entity entity = entityGetter.apply(packet, networkManager.player.level()); + if (entity == null) { + return packet; + } + Map playerMap = DisguiseCommand.disguises.get(entity.getUUID()); + if (playerMap == null) { + return packet; + } + DisguiseCommand.TrackedDisguise disguise = playerMap.get(networkManager.player.getUUID()); + if (disguise == null) { + disguise = playerMap.get(null); + } + if (disguise == null || !disguise.isActive) { + return packet; + } + if (NMSHandler.debugPackets) { + DenizenNetworkManagerImpl.doPacketOutput("DISGUISED packet " + packet.getClass().getName() + " for entity " + entity.getId() + " to player " + networkManager.player.getScoreboardName()); + } + try { + return handler.handle(networkManager, packet, disguise); + } + catch (Exception e) { + antiDuplicate = false; + throw e; // "pass it" to the generic exception handling + } + }); + } + + @FunctionalInterface + public interface DisguisePacketHandler> { + + T handle(DenizenNetworkManagerImpl networkManager, T packet, DisguiseCommand.TrackedDisguise disguise) throws Exception; + } + + public static ClientboundSetEntityDataPacket processEntityDataPacket(DenizenNetworkManagerImpl networkManager, ClientboundSetEntityDataPacket entityDataPacket, DisguiseCommand.TrackedDisguise disguise) { + if (entityDataPacket.id() == networkManager.player.getId()) { + if (!disguise.shouldFake) { + return entityDataPacket; + } + for (SynchedEntityData.DataValue dataValue : entityDataPacket.packedItems()) { + if (dataValue.id() == 0) { // Entity flags + List> newData = new ArrayList<>(entityDataPacket.packedItems()); + newData.remove(dataValue); + byte flags = (byte) dataValue.value(); + flags |= 0x20; // Invisible flag + newData.add(PacketHelperImpl.createEntityData(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS, flags)); + return new ClientboundSetEntityDataPacket(entityDataPacket.id(), newData); + } + } + } + else { + List> data = ((CraftEntity) disguise.toOthers.entity.entity).getHandle().getEntityData().getNonDefaultValues(); + return data != null ? new ClientboundSetEntityDataPacket(entityDataPacket.id(), data) : null; + } + return entityDataPacket; + } + + public static ClientboundUpdateAttributesPacket processAttributesPacket(DenizenNetworkManagerImpl networkManager, ClientboundUpdateAttributesPacket attributesPacket, DisguiseCommand.TrackedDisguise disguise) { + FakeEntity fake = attributesPacket.getEntityId() == networkManager.player.getId() ? disguise.fakeToSelf : disguise.toOthers; + return fake == null || fake.entity.entity instanceof LivingEntity ? attributesPacket : null; // Non-living entities don't have attributes + } + + public static ClientboundTeleportEntityPacket processTeleportPacket(DenizenNetworkManagerImpl networkManager, ClientboundTeleportEntityPacket teleportEntityPacket, DisguiseCommand.TrackedDisguise disguise) throws IllegalAccessException { + if (disguise.as.getBukkitEntityType() == EntityType.ENDER_DRAGON) { + PositionMoveRotation oldChange = teleportEntityPacket.change(); + return new ClientboundTeleportEntityPacket( + teleportEntityPacket.id(), + new PositionMoveRotation(oldChange.position(), oldChange.deltaMovement(), EntityAttachmentHelper.normalizeAngle(oldChange.yRot() + 180), oldChange.xRot()), + teleportEntityPacket.relatives(), + teleportEntityPacket.onGround() + ); + } + return sendDisguiseForPacket(networkManager, teleportEntityPacket, disguise); + } + + + public static ClientboundMoveEntityPacket.Rot processMoveEntityRotPacket(DenizenNetworkManagerImpl networkManager, ClientboundMoveEntityPacket.Rot rotPacket, DisguiseCommand.TrackedDisguise disguise) { + if (disguise.as.getBukkitEntityType() == EntityType.ENDER_DRAGON) { + return new ClientboundMoveEntityPacket.Rot( + disguise.entity.getBukkitEntity().getEntityId(), + EntityAttachmentHelper.compressAngle(rotPacket.getYRot() + 180), + Mth.packDegrees(rotPacket.getXRot()), + rotPacket.isOnGround() + ); + } + return sendDisguiseForPacket(networkManager, rotPacket, disguise); + } + + + public static ClientboundMoveEntityPacket.PosRot processMoveEntityPosRotPacket(DenizenNetworkManagerImpl networkManager, ClientboundMoveEntityPacket.PosRot posRotPacket, DisguiseCommand.TrackedDisguise disguise) { + if (disguise.as.getBukkitEntityType() == EntityType.ENDER_DRAGON) { + return new ClientboundMoveEntityPacket.PosRot( + disguise.entity.getBukkitEntity().getEntityId(), + posRotPacket.getXa(), + posRotPacket.getYa(), + posRotPacket.getZa(), + EntityAttachmentHelper.compressAngle(posRotPacket.getYRot() + 180), + Mth.packDegrees(posRotPacket.getXRot()), + posRotPacket.isOnGround() + ); + } + return sendDisguiseForPacket(networkManager, posRotPacket, disguise); + } + + public static > T sendDisguiseForPacket(DenizenNetworkManagerImpl networkManager, T packet, DisguiseCommand.TrackedDisguise disguise) { + antiDuplicate = true; + disguise.sendTo(List.of(new PlayerTag(networkManager.player.getUUID()))); + antiDuplicate = false; + return null; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/EntityMetadataPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/EntityMetadataPacketHandlers.java new file mode 100644 index 0000000000..f0b1cf4b7f --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/EntityMetadataPacketHandlers.java @@ -0,0 +1,92 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.scripts.commands.entity.GlowCommand; +import com.denizenscript.denizen.scripts.commands.entity.InvisibleCommand; +import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; +import com.denizenscript.denizen.scripts.commands.entity.SneakCommand; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class EntityMetadataPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEntityDataPacket.class, EntityMetadataPacketHandlers::processMetadataChangesForPacket); + } + + public static ClientboundSetEntityDataPacket getModifiedMetadataFor(DenizenNetworkManagerImpl networkManager, ClientboundSetEntityDataPacket metadataPacket) { + if (!RenameCommand.hasAnyDynamicRenames() && SneakCommand.forceSetSneak.isEmpty() && InvisibleCommand.helper.noOverrides() && GlowCommand.helper.noOverrides()) { + return null; + } + try { + Entity entity = networkManager.player.level().getEntity(metadataPacket.id()); + if (entity == null) { + return null; // If it doesn't exist on-server, it's definitely not relevant, so move on + } + String nameToApply = RenameCommand.getCustomNameFor(entity.getUUID(), networkManager.player.getBukkitEntity(), false); + Boolean forceSneak = SneakCommand.shouldSneak(entity.getUUID(), networkManager.player.getUUID()); + Boolean isInvisible = InvisibleCommand.helper.getState(entity.getBukkitEntity(), networkManager.player.getUUID(), true); + Boolean isGlowing = GlowCommand.helper.getState(entity.getBukkitEntity(), networkManager.player.getUUID(), true); + boolean shouldModifyFlags = isInvisible != null || forceSneak != null || isGlowing != null; + if (nameToApply == null && !shouldModifyFlags) { + return null; + } + List> data = new ArrayList<>(metadataPacket.packedItems().size()); + Byte currentFlags = null; + for (SynchedEntityData.DataValue dataValue : metadataPacket.packedItems()) { + if (dataValue.id() == 0 && shouldModifyFlags) { // 0: Entity Flags + currentFlags = (Byte) dataValue.value(); + } + else if (nameToApply == null || (dataValue.id() != 2 && dataValue.id() != 3)) { // 2 and 3: Custom name and custom name visible + data.add(dataValue); + } + } + if (shouldModifyFlags) { + byte flags = currentFlags == null ? entity.getEntityData().get(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS) : currentFlags; + flags = applyEntityDataFlag(flags, forceSneak, 0x02); + flags = applyEntityDataFlag(flags, isInvisible, 0x20); + flags = applyEntityDataFlag(flags, isGlowing, 0x40); + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS, flags)); + } + if (nameToApply != null) { + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(nameToApply, ChatColor.WHITE))))); + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true)); + } + return new ClientboundSetEntityDataPacket(metadataPacket.id(), data); + } + catch (Throwable ex) { + Debug.echoError(ex); + return null; + } + } + + public static byte applyEntityDataFlag(byte currentFlags, Boolean value, int flag) { + if (value == null) { + return currentFlags; + } + return (byte) (value ? currentFlags | flag : currentFlags & ~flag); + } + + public static Packet processMetadataChangesForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (!(packet instanceof ClientboundSetEntityDataPacket entityDataPacket)) { + return packet; + } + ClientboundSetEntityDataPacket altPacket = getModifiedMetadataFor(networkManager, entityDataPacket); + if (altPacket == null) { + return packet; + } + return altPacket; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java new file mode 100644 index 0000000000..0144bcfa08 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -0,0 +1,111 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.FakeBlockHelper; +import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; +import com.denizenscript.denizen.utilities.blocks.FakeBlock; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.world.level.block.state.BlockState; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.List; + +public class FakeBlocksPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelChunkWithLightPacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSectionBlocksUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + } + + public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("sectionPos", SectionPos.class); + public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("positions", short[].class); + public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("states", BlockState[].class); + + public static Packet processShowFakeForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (FakeBlock.blocks.isEmpty()) { + return packet; + } + try { + if (packet instanceof ClientboundLevelChunkWithLightPacket) { + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return packet; + } + int chunkX = ((ClientboundLevelChunkWithLightPacket) packet).getX(); + int chunkZ = ((ClientboundLevelChunkWithLightPacket) packet).getZ(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); + List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); + if (blocks == null || blocks.isEmpty()) { + return packet; + } + ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks); + return newPacket; + } + else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return sectionBlocksUpdatePacket; + } + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionBlocksUpdatePacket); + ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); + if (!map.byChunk.containsKey(coordinateDenizen)) { + return sectionBlocksUpdatePacket; + } + ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionBlocksUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); + BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); + short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); + BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); + OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); + BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); + for (int i = 0; i < offsetArray.length; i++) { + short offset = offsetArray[i]; + BlockPos pos = coord.relativeToBlockPos(offset); + location.setX(pos.getX()); + location.setY(pos.getY()); + location.setZ(pos.getZ()); + FakeBlock block = map.byLocation.get(location); + if (block != null) { + dataArray[i] = FakeBlockHelper.getNMSState(block); + } + } + return newPacket; + } + else if (packet instanceof ClientboundBlockUpdatePacket) { + BlockPos pos = ((ClientboundBlockUpdatePacket) packet).getPos(); + LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); + if (block != null) { + ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(((ClientboundBlockUpdatePacket) packet).getPos(), FakeBlockHelper.getNMSState(block)); + return newPacket; + } + } + else if (packet instanceof ClientboundBlockChangedAckPacket) { + // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. + /* + ClientboundBlockChangedAckPacket origPack = (ClientboundBlockChangedAckPacket) packet; + BlockPos pos = origPack.pos(); + LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); + if (block != null) { + ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(origPack.pos(), FakeBlockHelper.getNMSState(block), origPack.action(), false); + oldManager.send(newPacket, genericfuturelistener); + return true; + }*/ + } + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return packet; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java new file mode 100644 index 0000000000..9471624704 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java @@ -0,0 +1,138 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; +import com.mojang.datafixers.util.Pair; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.inventory.CraftItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class FakeEquipmentPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEquipmentPacket.class, FakeEquipmentPacketHandlers::processSetEquipmentPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundEntityEventPacket.class, FakeEquipmentPacketHandlers::processEntityEventPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundContainerSetContentPacket.class, FakeEquipmentPacketHandlers::processContainerSetContentPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundContainerSetSlotPacket.class, FakeEquipmentPacketHandlers::processContainerSetSlotPacket); + } + + public static ClientboundSetEquipmentPacket processSetEquipmentPacket(DenizenNetworkManagerImpl networkManager, ClientboundSetEquipmentPacket setEquipmentPacket) { + if (FakeEquipCommand.overrides.isEmpty()) { + return setEquipmentPacket; + } + Entity entity = networkManager.player.level().getEntity(setEquipmentPacket.getEntity()); + if (entity == null) { + return setEquipmentPacket; + } + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(entity.getUUID(), networkManager.player.getBukkitEntity()); + if (override == null) { + return setEquipmentPacket; + } + List> equipment = new ArrayList<>(setEquipmentPacket.getSlots()); + for (int i = 0; i < equipment.size(); i++) { + Pair pair = equipment.get(i); + ItemStack use = switch (pair.getFirst()) { + case MAINHAND -> override.hand == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.hand.getItemStack()); + case OFFHAND -> override.offhand == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.offhand.getItemStack()); + case CHEST -> override.chest == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.chest.getItemStack()); + case HEAD -> override.head == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.head.getItemStack()); + case LEGS -> override.legs == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.legs.getItemStack()); + case FEET -> override.boots == null ? pair.getSecond() : CraftItemStack.asNMSCopy(override.boots.getItemStack()); + case BODY -> pair.getSecond(); // TODO: 1.20.6: is this actually used here? do we want to allow overriding it? + case SADDLE -> pair.getSecond(); // TODO: 1.21.5: same as above + }; + equipment.set(i, new Pair<>(pair.getFirst(), use)); + } + return new ClientboundSetEquipmentPacket(setEquipmentPacket.getEntity(), equipment); + } + + public static Packet processEntityEventPacket(DenizenNetworkManagerImpl networkManager, ClientboundEntityEventPacket entityEventPacket) { + if (FakeEquipCommand.overrides.isEmpty()) { + return entityEventPacket; + } + if (entityEventPacket.getEventId() != 55) { + return entityEventPacket; + } + if (!(entityEventPacket.getEntity(networkManager.player.level()) instanceof LivingEntity livingEntity)) { + return entityEventPacket; + } + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(livingEntity.getUUID(), networkManager.player.getBukkitEntity()); + if (override == null || (override.hand == null && override.offhand == null)) { + return entityEventPacket; + } + ItemStack hand = override.hand != null ? CraftItemStack.asNMSCopy(override.hand.getItemStack()) : livingEntity.getMainHandItem(); + ItemStack offhand = override.offhand != null ? CraftItemStack.asNMSCopy(override.offhand.getItemStack()) : livingEntity.getOffhandItem(); + return new ClientboundSetEquipmentPacket(livingEntity.getId(), List.of(new Pair<>(EquipmentSlot.MAINHAND, hand), new Pair<>(EquipmentSlot.OFFHAND, offhand))); + } + + public static ClientboundContainerSetContentPacket processContainerSetContentPacket(DenizenNetworkManagerImpl networkManager, ClientboundContainerSetContentPacket setContentPacket) { + if (FakeEquipCommand.overrides.isEmpty()) { + return setContentPacket; + } + if (setContentPacket.containerId() != 0) { + return setContentPacket; + } + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(networkManager.player.getUUID(), networkManager.player.getBukkitEntity()); + if (override == null) { + return setContentPacket; + } + List items = setContentPacket.items(); + if (override.head != null) { + items.set(5, CraftItemStack.asNMSCopy(override.head.getItemStack())); + } + if (override.chest != null) { + items.set(6, CraftItemStack.asNMSCopy(override.chest.getItemStack())); + } + if (override.legs != null) { + items.set(7, CraftItemStack.asNMSCopy(override.legs.getItemStack())); + } + if (override.boots != null) { + items.set(8, CraftItemStack.asNMSCopy(override.boots.getItemStack())); + } + if (override.offhand != null) { + items.set(45, CraftItemStack.asNMSCopy(override.offhand.getItemStack())); + } + if (override.hand != null) { + items.set(getMainHandSlot(networkManager.player), CraftItemStack.asNMSCopy(override.hand.getItemStack())); + } + return new ClientboundContainerSetContentPacket(setContentPacket.containerId(), setContentPacket.stateId(), items, setContentPacket.carriedItem()); + } + + public static ClientboundContainerSetSlotPacket processContainerSetSlotPacket(DenizenNetworkManagerImpl networkManager, ClientboundContainerSetSlotPacket setSlotPacket) { + if (FakeEquipCommand.overrides.isEmpty()) { + return setSlotPacket; + } + if (setSlotPacket.getContainerId() != 0) { + return setSlotPacket; + } + FakeEquipCommand.EquipmentOverride override = FakeEquipCommand.getOverrideFor(networkManager.player.getUUID(), networkManager.player.getBukkitEntity()); + if (override == null) { + return setSlotPacket; + } + ItemTag item = switch (setSlotPacket.getSlot()) { + case 5 -> override.head; + case 6 -> override.chest; + case 7 -> override.legs; + case 8 -> override.boots; + case 45 -> override.offhand; + default -> setSlotPacket.getSlot() == getMainHandSlot(networkManager.player) ? override.hand : null; + }; + if (item == null) { + return setSlotPacket; + } + return new ClientboundContainerSetSlotPacket(setSlotPacket.getContainerId(), setSlotPacket.getStateId(), setSlotPacket.getSlot(), CraftItemStack.asNMSCopy(item.getItemStack())); + } + + public static int getMainHandSlot(ServerPlayer player) { + return player.getInventory().getSelectedSlot() + 36; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakePlayerPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakePlayerPacketHandlers.java new file mode 100644 index 0000000000..ac5c76ae4f --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakePlayerPacketHandlers.java @@ -0,0 +1,29 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +/* +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.v1_20.impl.entities.EntityFakePlayerImpl; +import com.denizenscript.denizen.nms.v1_20.impl.network.handlers.DenizenNetworkManagerImpl; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import org.bukkit.Bukkit; + +import java.util.List; +*/ + +public class FakePlayerPacketHandlers { + + public static void registerHandlers() { + // TODO: 1.20.2: Replace this. + //DenizenNetworkManagerImpl.registerPacketHandler(ClientboundAddPlayerPacket.class, FakePlayerPacketHandlers::processAddPlayerPacket); + } + + /* + public static void processAddPlayerPacket(DenizenNetworkManagerImpl networkManager, ClientboundAddPlayerPacket addPlayerPacket) { + if (networkManager.player.level().getEntity(addPlayerPacket.getEntityId()) instanceof EntityFakePlayerImpl fakePlayer) { + networkManager.send(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, fakePlayer)); + Bukkit.getScheduler().runTaskLater(NMSHandler.getJavaPlugin(), + () -> networkManager.send(new ClientboundPlayerInfoRemovePacket(List.of(fakePlayer.getUUID()))), 5); + } + }*/ +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java new file mode 100644 index 0000000000..d905b22d07 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java @@ -0,0 +1,69 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.utilities.entity.HideEntitiesHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; + +public class HiddenEntitiesPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundAddEntityPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + //DenizenNetworkManagerImpl.registerPacketHandler(ClientboundAddExperienceOrbPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundMoveEntityPacket.Rot.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundMoveEntityPacket.Pos.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundMoveEntityPacket.PosRot.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEntityDataPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSetEntityMotionPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundTeleportEntityPacket.class, HiddenEntitiesPacketHandlers::processHiddenEntitiesForPacket); + } + + public static boolean isHidden(ServerPlayer player, Entity entity) { + return entity != null && HideEntitiesHelper.playerShouldHide(player.getBukkitEntity().getUniqueId(), entity.getBukkitEntity()); + } + + public static Packet processHiddenEntitiesForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (!HideEntitiesHelper.hasAnyHides()) { + return packet; + } + try { + int ider = -1; + Entity e = null; + if (packet instanceof ClientboundAddEntityPacket) { + ider = ((ClientboundAddEntityPacket) packet).getId(); + } + //TODO: 1.21.5: check this packet list + /* + else if (packet instanceof ClientboundAddExperienceOrbPacket) { + ider = ((ClientboundAddExperienceOrbPacket) packet).getId(); + }*/ + else if (packet instanceof ClientboundMoveEntityPacket) { + e = ((ClientboundMoveEntityPacket) packet).getEntity(networkManager.player.level()); + } + else if (packet instanceof ClientboundSetEntityDataPacket) { + ider = ((ClientboundSetEntityDataPacket) packet).id(); + } + else if (packet instanceof ClientboundSetEntityMotionPacket) { + ider = ((ClientboundSetEntityMotionPacket) packet).id(); + } + else if (packet instanceof ClientboundTeleportEntityPacket) { + ider = ((ClientboundTeleportEntityPacket) packet).id(); + } + if (e == null && ider != -1) { + e = networkManager.player.level().getEntity(ider); + } + if (e != null) { + if (isHidden(networkManager.player, e)) { + return null; + } + } + } + catch (Exception ex) { + Debug.echoError(ex); + } + return packet; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HideParticlesPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HideParticlesPacketHandlers.java new file mode 100644 index 0000000000..70c64da27b --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HideParticlesPacketHandlers.java @@ -0,0 +1,31 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.utilities.packets.HideParticles; +import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; +import org.bukkit.Particle; +import org.bukkit.craftbukkit.CraftParticle; + +import java.util.Set; + +public class HideParticlesPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelParticlesPacket.class, HideParticlesPacketHandlers::processParticlesPacket); + } + + public static ClientboundLevelParticlesPacket processParticlesPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelParticlesPacket particlesPacket) { + if (HideParticles.hidden.isEmpty()) { + return particlesPacket; + } + Set hidden = HideParticles.hidden.get(networkManager.player.getUUID()); + if (hidden == null) { + return particlesPacket; + } + Particle bukkitParticle = CraftParticle.minecraftToBukkit(particlesPacket.getParticle().getType()); + if (hidden.contains(bukkitParticle)) { + return null; + } + return particlesPacket; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java new file mode 100644 index 0000000000..f26a97ad7e --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java @@ -0,0 +1,39 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.events.player.PlayerHearsSoundScriptEvent; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.world.entity.Entity; +import org.bukkit.Location; + +public class PlayerHearsSoundEventPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSoundPacket.class, PlayerHearsSoundEventPacketHandlers::processSoundPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSoundEntityPacket.class, PlayerHearsSoundEventPacketHandlers::processSoundPacket); + } + + public static Packet processSoundPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (!PlayerHearsSoundScriptEvent.instance.eventData.isEnabled) { + return packet; + } + if (packet instanceof ClientboundSoundPacket) { + ClientboundSoundPacket spacket = (ClientboundSoundPacket) packet; + return PlayerHearsSoundScriptEvent.instance.run(networkManager.player.getBukkitEntity(), spacket.getSound().value().location().getPath(), spacket.getSource().name(), + false, null, new Location(networkManager.player.getBukkitEntity().getWorld(), spacket.getX(), spacket.getY(), spacket.getZ()), spacket.getVolume(), spacket.getPitch()) ? null : packet; + } + else if (packet instanceof ClientboundSoundEntityPacket) { + ClientboundSoundEntityPacket spacket = (ClientboundSoundEntityPacket) packet; + Entity entity = networkManager.player.level().getEntity(spacket.getId()); + if (entity == null) { + return packet; + } + return PlayerHearsSoundScriptEvent.instance.run(networkManager.player.getBukkitEntity(), spacket.getSound().value().location().getPath(), spacket.getSource().name(), + false, entity.getBukkitEntity(), null, spacket.getVolume(), spacket.getPitch()) ? null : packet; + } + return packet; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java new file mode 100644 index 0000000000..cd436d5d26 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java @@ -0,0 +1,126 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; + +import com.denizenscript.denizen.events.player.PlayerReceivesTablistUpdateScriptEvent; +import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.google.common.base.Joiner; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.md_5.bungee.api.ChatColor; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.world.level.GameType; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +public class TablistUpdateEventPacketHandlers { + + public static void registerHandlers() { + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundPlayerInfoUpdatePacket.class, TablistUpdateEventPacketHandlers::processTablistPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundPlayerInfoRemovePacket.class, TablistUpdateEventPacketHandlers::processTablistPacket); + } + + public static boolean tablistBreakOnlyOnce = false; + + // TODO: properly rebundle the packet instead of splitting it up + public static Packet processTablistPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + if (!PlayerReceivesTablistUpdateScriptEvent.instance.eventData.isEnabled) { + return packet; + } + if (packet instanceof ClientboundPlayerInfoUpdatePacket) { + ClientboundPlayerInfoUpdatePacket infoPacket = (ClientboundPlayerInfoUpdatePacket) packet; + String mode = ""; + for (ClientboundPlayerInfoUpdatePacket.Action action : infoPacket.actions()) { + switch (action) { + case ADD_PLAYER: + mode = "add"; + break; + case UPDATE_LATENCY: + mode = mode.isEmpty() ? "update_latency" : mode + "|update_latency"; + break; + case UPDATE_GAME_MODE: + mode = mode.isEmpty() ? "update_gamemode" : mode + "|update_gamemode"; + break; + case UPDATE_DISPLAY_NAME: + mode = mode.isEmpty() ? "update_display" : mode + "|update_display"; + break; + case UPDATE_LISTED: + mode = mode.isEmpty() ? "update_listed" : mode + "|update_listed"; + break; + case INITIALIZE_CHAT: + mode = mode.isEmpty() ? "initialize_chat" : mode + "|initialize_chat"; + default: + break; + } + } + if (mode.isEmpty()) { + if (!tablistBreakOnlyOnce) { + tablistBreakOnlyOnce = true; + Debug.echoError("Tablist packet processing failed: unknown action " + Joiner.on(", ").join(infoPacket.actions())); + } + return packet; + } + boolean isOverriding = false; + for (ClientboundPlayerInfoUpdatePacket.Entry update : infoPacket.entries()) { + GameProfile profile = update.profile(); + String texture = null, signature = null; + if (profile.properties().containsKey("textures")) { + Property property = profile.properties().get("textures").stream().findFirst().get(); + texture = property.value(); + signature = property.signature(); + } + String modeText = update.gameMode() == null ? null : update.gameMode().name(); + PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData(mode, profile.id(), update.listed(), profile.name(), + update.displayName() == null ? null : FormattedTextHelper.stringify(Handler.componentToSpigot(update.displayName())), modeText, texture, signature, update.latency()); + PlayerReceivesTablistUpdateScriptEvent.fire(networkManager.player.getBukkitEntity(), data); + if (data.modified) { + if (!isOverriding) { + isOverriding = true; + for (ClientboundPlayerInfoUpdatePacket.Entry priorUpdate : infoPacket.entries()) { + if (priorUpdate == update) { + break; + } + networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(priorUpdate))); + } + } + if (!data.cancelled) { + GameProfile newProfile = ProfileEditorImpl.createGameProfile(data.id, data.name, data.texture, data.signature); + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(newProfile.id(), newProfile, data.isListed, data.latency, data.gamemode == null ? null : GameType.byName(CoreUtilities.toLowerCase(data.gamemode)), + data.display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(data.display, ChatColor.WHITE)), update.showHat(), update.listOrder(), update.chatSession()); + networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(entry))); + } + } + else if (isOverriding) { + networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(update))); + } + } + return isOverriding ? null : packet; + } + else if (packet instanceof ClientboundPlayerInfoRemovePacket) { + ClientboundPlayerInfoRemovePacket removePacket = (ClientboundPlayerInfoRemovePacket) packet; + boolean modified = false; + List altIds = new ArrayList<>(((ClientboundPlayerInfoRemovePacket) packet).profileIds()); + for (UUID id : ((ClientboundPlayerInfoRemovePacket) packet).profileIds()) { + PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData("remove", id, false, null, null, null, null, null, 0); + PlayerReceivesTablistUpdateScriptEvent.fire(networkManager.player.getBukkitEntity(), data); + if (data.modified && data.cancelled) { + modified = true; + altIds.remove(id); + } + } + if (modified) { + return new ClientboundPlayerInfoRemovePacket(altIds); + } + } + return packet; + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInResourcePackStatusImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInResourcePackStatusImpl.java new file mode 100644 index 0000000000..64a80bad64 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInResourcePackStatusImpl.java @@ -0,0 +1,18 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.packets; + +import com.denizenscript.denizen.nms.interfaces.packets.PacketInResourcePackStatus; +import net.minecraft.network.protocol.common.ServerboundResourcePackPacket; + +public class PacketInResourcePackStatusImpl implements PacketInResourcePackStatus { + + private ServerboundResourcePackPacket internal; + + public PacketInResourcePackStatusImpl(ServerboundResourcePackPacket internal) { + this.internal = internal; + } + + @Override + public String getStatus() { + return internal.action().name(); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInSteerVehicleImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInSteerVehicleImpl.java new file mode 100644 index 0000000000..fb041134f3 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInSteerVehicleImpl.java @@ -0,0 +1,33 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.packets; + +import com.denizenscript.denizen.nms.interfaces.packets.PacketInSteerVehicle; +import net.minecraft.network.protocol.game.ServerboundPlayerInputPacket; + +public class PacketInSteerVehicleImpl implements PacketInSteerVehicle { + + private ServerboundPlayerInputPacket internal; + + public PacketInSteerVehicleImpl(ServerboundPlayerInputPacket internal) { + this.internal = internal; + } + + @Override + public float getLeftwardInput() { + return internal.input().left() ? 1 : 0; + } + + @Override + public float getForwardInput() { + return internal.input().forward() ? 1 : 0; + } + + @Override + public boolean getJumpInput() { + return internal.input().jump(); + } + + @Override + public boolean getDismountInput() { + return internal.input().shift(); + } +} diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketOutChatImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketOutChatImpl.java new file mode 100644 index 0000000000..ed5445a201 --- /dev/null +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketOutChatImpl.java @@ -0,0 +1,50 @@ +package com.denizenscript.denizen.nms.v26_1.impl.network.packets; + +import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; +import com.denizenscript.denizen.utilities.FormattedTextHelper; +import net.md_5.bungee.chat.ComponentSerializer; +import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import org.bukkit.craftbukkit.util.CraftChatMessage; + +public class PacketOutChatImpl extends PacketOutChat { + + public ClientboundPlayerChatPacket playerPacket; + public ClientboundSystemChatPacket systemPacket; + public String message; + public String rawJson; + public boolean isOverlayActionbar; + + public PacketOutChatImpl(ClientboundSystemChatPacket internal) { + systemPacket = internal; + rawJson = CraftChatMessage.toJSON(internal.content()); + message = FormattedTextHelper.stringify(FormattedTextHelper.parseJson(rawJson)); + isOverlayActionbar = internal.overlay(); + } + + public PacketOutChatImpl(ClientboundPlayerChatPacket internal) { + playerPacket = internal; + rawJson = ComponentSerializer.toString(internal.body().content()); + message = FormattedTextHelper.stringify(FormattedTextHelper.parseJson(rawJson)); + } + + @Override + public boolean isSystem() { + return systemPacket != null; + } + + @Override + public boolean isActionbar() { + return isOverlayActionbar; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public String getRawJson() { + return rawJson; + } +} From d1bb339ba2057815e345dad187ecfdf7bba04550 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 17 Jun 2026 19:05:33 +0100 Subject: [PATCH 104/169] 26.2 part 2: bump depends and denizen version --- README.md | 4 ++-- dist/pom.xml | 8 +++++++- paper/pom.xml | 4 ++-- plugin/pom.xml | 4 ++-- pom.xml | 5 +++-- v1_17/pom.xml | 2 +- v1_18/pom.xml | 2 +- v1_19/pom.xml | 2 +- v1_20/pom.xml | 2 +- v1_21/pom.xml | 2 +- v26_1/pom.xml | 2 +- v26_2/pom.xml | 8 ++++---- .../java/com/denizenscript/denizen/nms/v26_2/Handler.java | 2 +- 13 files changed, 27 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index a005cc2163..26fe7dd9f3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.3.2**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, and 26.1.2! +**Version 1.3.3**: Compatible with Spigot 1.17.1, 1.18.2, 1.19.4, 1.20.6, 1.21.11, 26.1.2, and 26.2! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html @@ -45,7 +45,7 @@ An implementation of the Denizen Scripting Language for Spigot servers, with str com.denizenscript denizen - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT jar provided diff --git a/dist/pom.xml b/dist/pom.xml index 5ed619f97c..30c3e001e9 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -5,7 +5,7 @@ com.denizenscript denizen-parent - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT 4.0.0 @@ -66,6 +66,12 @@ ${project.parent.version} compile + + com.denizenscript + denizen-v26_2 + ${project.parent.version} + compile + com.denizenscript denizen-paper diff --git a/paper/pom.xml b/paper/pom.xml index 68371fe434..ce0e1978cf 100644 --- a/paper/pom.xml +++ b/paper/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-paper - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT @@ -25,7 +25,7 @@ io.papermc.paper paper-api - [26.1.2.build,) + [26.2.build,) provided diff --git a/plugin/pom.xml b/plugin/pom.xml index 44a4c6cd9c..b9ba8f0938 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -5,7 +5,7 @@ com.denizenscript denizen - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT Denizen Scriptable Minecraft and Citizens2 @@ -30,7 +30,7 @@ org.spigotmc spigot-api - 26.1.2-R0.1-SNAPSHOT + 26.2-R0.1-SNAPSHOT jar provided diff --git a/pom.xml b/pom.xml index 70b1bda368..1320cdd25b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,18 +6,19 @@ com.denizenscript denizen-parent pom - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT UTF-8 Unknown CUSTOM - 1.3.2 + 1.3.3 plugin paper + v26_2 v26_1 v1_21 v1_20 diff --git a/v1_17/pom.xml b/v1_17/pom.xml index 38e34558a0..29e4b05219 100644 --- a/v1_17/pom.xml +++ b/v1_17/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_17 - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT diff --git a/v1_18/pom.xml b/v1_18/pom.xml index 83179366f0..574ee03cbb 100644 --- a/v1_18/pom.xml +++ b/v1_18/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_18 - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT diff --git a/v1_19/pom.xml b/v1_19/pom.xml index 98ae81ac0b..53df243ebb 100644 --- a/v1_19/pom.xml +++ b/v1_19/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_19 - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT diff --git a/v1_20/pom.xml b/v1_20/pom.xml index 282b840be6..d3bc7a89cc 100644 --- a/v1_20/pom.xml +++ b/v1_20/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_20 - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT diff --git a/v1_21/pom.xml b/v1_21/pom.xml index 58b14d7cc1..d5e04a0315 100644 --- a/v1_21/pom.xml +++ b/v1_21/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v1_21 - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT diff --git a/v26_1/pom.xml b/v26_1/pom.xml index dc374277d1..0fdd1d1f36 100644 --- a/v26_1/pom.xml +++ b/v26_1/pom.xml @@ -6,7 +6,7 @@ com.denizenscript denizen-v26_1 - 1.3.2-SNAPSHOT + 1.3.3-SNAPSHOT diff --git a/v26_2/pom.xml b/v26_2/pom.xml index dc374277d1..6b101c92c8 100644 --- a/v26_2/pom.xml +++ b/v26_2/pom.xml @@ -5,8 +5,8 @@ 4.0.0 com.denizenscript - denizen-v26_1 - 1.3.2-SNAPSHOT + denizen-v26_2 + 1.3.3-SNAPSHOT @@ -19,13 +19,13 @@ org.spigotmc spigot-api - 26.1.2-R0.1-SNAPSHOT + 26.2-R0.1-SNAPSHOT provided org.spigotmc spigot - 26.1.2-R0.1-SNAPSHOT + 26.2-R0.1-SNAPSHOT provided diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java index 17c27ce687..a22b2d4b1f 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java @@ -162,7 +162,7 @@ public void undisableAsyncCatcher() { @Override public boolean isExactServerVersionMatch() { - return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("26.1.2") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e8ece90188c951d866bd2fffc52c803e"); + return Denizen.supportsPaper ? SharedConstants.getCurrentVersion().id().equals("26.2") : CraftMagicNumbers.INSTANCE.getMappingsVersion().equals("e8ece90188c951d866bd2fffc52c803e"); } @Override From 889cc47bf4a6f8f523f9eb6a28254f2dbb322134 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:02:34 +0100 Subject: [PATCH 105/169] 26.2 part 3: initial code updates --- .../denizenscript/denizen/nms/NMSVersion.java | 3 +- .../denizen/nms/v26_2/Handler.java | 12 ++--- .../v26_2/helpers/AdvancementHelperImpl.java | 7 +-- .../v26_2/helpers/AnimationHelperImpl.java | 2 +- .../nms/v26_2/helpers/BlockHelperImpl.java | 6 +-- .../nms/v26_2/helpers/ChunkHelperImpl.java | 4 +- .../v26_2/helpers/CustomEntityHelperImpl.java | 12 ++--- .../v26_2/helpers/EnchantmentHelperImpl.java | 2 +- .../v26_2/helpers/EntityDataNameMapper.java | 3 +- .../nms/v26_2/helpers/EntityHelperImpl.java | 6 +-- .../nms/v26_2/helpers/FishingHelperImpl.java | 4 +- .../nms/v26_2/helpers/ItemHelperImpl.java | 45 ++++++++++++------- .../denizen/nms/v26_2/helpers/NBTAdapter.java | 2 +- .../nms/v26_2/helpers/PacketHelperImpl.java | 17 +++---- .../nms/v26_2/helpers/PlayerHelperImpl.java | 16 +++---- .../nms/v26_2/helpers/WorldHelperImpl.java | 4 +- .../denizen/nms/v26_2/impl/BiomeNMSImpl.java | 4 +- .../v26_2/impl/ImprovedOfflinePlayerImpl.java | 11 ++--- .../nms/v26_2/impl/ProfileEditorImpl.java | 8 ++-- .../denizen/nms/v26_2/impl/SidebarImpl.java | 6 +-- .../nms/v26_2/impl/blocks/BlockLightImpl.java | 2 +- .../impl/entities/CraftFakeArrowImpl.java | 2 +- .../impl/entities/CraftFakePlayerImpl.java | 2 +- .../entities/CraftItemProjectileImpl.java | 5 ++- .../impl/entities/EntityFakeArrowImpl.java | 7 +-- .../impl/entities/EntityFakePlayerImpl.java | 10 ++--- .../entities/EntityItemProjectileImpl.java | 5 ++- .../impl/network/fakes/FakeChannelImpl.java | 2 +- .../network/fakes/FakeNetworkManagerImpl.java | 2 +- .../fakes/FakePlayerConnectionImpl.java | 2 +- .../handlers/AbstractListenerPlayInImpl.java | 2 +- .../handlers/DenizenNetworkManagerImpl.java | 20 +++++---- .../handlers/DenizenPacketListenerImpl.java | 6 +-- .../network/handlers/FakeBlockHelper.java | 2 +- .../packet/ActionBarEventPacketHandlers.java | 6 +-- .../handlers/packet/AttachPacketHandlers.java | 4 +- .../packet/BlockLightPacketHandlers.java | 6 +-- .../DenizenPacketHandlerPacketHandlers.java | 6 +-- .../packet/DisguisePacketHandlers.java | 6 +-- .../packet/EntityMetadataPacketHandlers.java | 8 ++-- .../packet/FakeBlocksPacketHandlers.java | 6 +-- .../packet/FakeEquipmentPacketHandlers.java | 4 +- .../packet/FakePlayerPacketHandlers.java | 2 +- .../packet/HiddenEntitiesPacketHandlers.java | 4 +- .../packet/HideParticlesPacketHandlers.java | 4 +- .../PlayerHearsSoundEventPacketHandlers.java | 4 +- .../TablistUpdateEventPacketHandlers.java | 8 ++-- .../PacketInResourcePackStatusImpl.java | 2 +- .../packets/PacketInSteerVehicleImpl.java | 2 +- .../network/packets/PacketOutChatImpl.java | 2 +- 50 files changed, 169 insertions(+), 148 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/nms/NMSVersion.java b/plugin/src/main/java/com/denizenscript/denizen/nms/NMSVersion.java index 3445604ad2..22a7edece8 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/nms/NMSVersion.java +++ b/plugin/src/main/java/com/denizenscript/denizen/nms/NMSVersion.java @@ -8,7 +8,8 @@ public enum NMSVersion { v1_19("1.19"), v1_20("1.20"), v1_21("1.21"), - v26_1("26.1"); + v26_1("26.1"), + v26_2("26.2"); final String minecraftVersion; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java index a22b2d4b1f..780a147c80 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/Handler.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1; +package com.denizenscript.denizen.nms.v26_2; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.NMSHandler; @@ -7,11 +7,11 @@ 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.v26_1.helpers.*; -import com.denizenscript.denizen.nms.v26_1.impl.BiomeNMSImpl; -import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; -import com.denizenscript.denizen.nms.v26_1.impl.SidebarImpl; -import com.denizenscript.denizen.nms.v26_1.impl.blocks.BlockLightImpl; +import com.denizenscript.denizen.nms.v26_2.helpers.*; +import com.denizenscript.denizen.nms.v26_2.impl.BiomeNMSImpl; +import com.denizenscript.denizen.nms.v26_2.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_2.impl.SidebarImpl; +import com.denizenscript.denizen.nms.v26_2.impl.blocks.BlockLightImpl; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AdvancementHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AdvancementHelperImpl.java index a7e50ed538..ef82c56eda 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AdvancementHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AdvancementHelperImpl.java @@ -1,12 +1,13 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.interfaces.AdvancementHelper; -import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_2.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.advancements.triggers.Criterion; +import net.minecraft.advancements.triggers.ImpossibleTrigger; import net.minecraft.core.ClientAsset; import net.minecraft.network.protocol.game.ClientboundUpdateAdvancementsPacket; import net.minecraft.resources.Identifier; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AnimationHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AnimationHelperImpl.java index 2c12daf4ba..6965a1b5d5 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AnimationHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/AnimationHelperImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.abstracts.AnimationHelper; import net.minecraft.world.entity.Entity; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/BlockHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/BlockHelperImpl.java index 3a39a8215c..68455e6c28 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/BlockHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/BlockHelperImpl.java @@ -1,9 +1,9 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.interfaces.BlockHelper; import com.denizenscript.denizen.nms.util.PlayerProfile; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.impl.ProfileEditorImpl; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.utilities.ReflectionHelper; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ChunkHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ChunkHelperImpl.java index b203e0a2b5..ac482bf852 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ChunkHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ChunkHelperImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.abstracts.BiomeNMS; import com.denizenscript.denizen.nms.interfaces.ChunkHelper; -import com.denizenscript.denizen.nms.v26_1.impl.BiomeNMSImpl; +import com.denizenscript.denizen.nms.v26_2.impl.BiomeNMSImpl; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/CustomEntityHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/CustomEntityHelperImpl.java index 9905e036ef..dc3aa0498b 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/CustomEntityHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/CustomEntityHelperImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.interfaces.CustomEntityHelper; @@ -6,11 +6,11 @@ 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.v26_1.impl.ProfileEditorImpl; -import com.denizenscript.denizen.nms.v26_1.impl.entities.CraftFakePlayerImpl; -import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityFakeArrowImpl; -import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityFakePlayerImpl; -import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityItemProjectileImpl; +import com.denizenscript.denizen.nms.v26_2.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_2.impl.entities.CraftFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.entities.EntityFakeArrowImpl; +import com.denizenscript.denizen.nms.v26_2.impl.entities.EntityFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.entities.EntityItemProjectileImpl; import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.Debug; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EnchantmentHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EnchantmentHelperImpl.java index ae556afc23..3b7b92c38d 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EnchantmentHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EnchantmentHelperImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.interfaces.EnchantmentHelper; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityDataNameMapper.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityDataNameMapper.java index 8ce7da8054..d3b0209856 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityDataNameMapper.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityDataNameMapper.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizencore.objects.ArgumentHelper; @@ -41,6 +41,7 @@ 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.cubemob.Slime; import net.minecraft.world.entity.monster.hoglin.Hoglin; import net.minecraft.world.entity.monster.illager.Pillager; import net.minecraft.world.entity.monster.illager.SpellcasterIllager; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityHelperImpl.java index ac3e95b7b5..0223d4b183 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/EntityHelperImpl.java @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.interfaces.EntityHelper; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.properties.entity.EntityState; import com.denizenscript.denizen.utilities.Utilities; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/FishingHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/FishingHelperImpl.java index f6630b5a3c..acb94b9f09 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/FishingHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/FishingHelperImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.interfaces.FishingHelper; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -63,7 +63,7 @@ public org.bukkit.inventory.ItemStack getResult(FishHook fishHook, CatchType cat case FISH -> catchRandomFish(nmsHook); default -> null; }; - return result != null ? CraftItemStack.asBukkitCopy(result) : null; + return result != null ? ItemHelperImpl.asBukkitCopy(result) : null; } public ItemStack getRandomReward(FishingHook nmsHook, ResourceKey key) { diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java index 8312001b82..6abf550fff 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.interfaces.ItemHelper; import com.denizenscript.denizen.nms.util.PlayerProfile; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.impl.ProfileEditorImpl; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.properties.item.ItemComponentsPatch; import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; @@ -24,8 +24,8 @@ import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.md_5.bungee.api.ChatColor; -import net.minecraft.advancements.criterion.BlockPredicate; -import net.minecraft.advancements.criterion.DataComponentMatchers; +import net.minecraft.advancements.predicates.BlockPredicate; +import net.minecraft.advancements.predicates.DataComponentMatchers; import net.minecraft.core.*; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentPatch; @@ -117,6 +117,17 @@ public static ItemStackTemplate asNMSTemplate(ItemStack item) { } } + public static final MethodHandle CRAFT_ITEM_STACK_AS_BUKKIT_COPY = ReflectionHelper.getMethodHandle(CraftItemStack.class, "asBukkitCopy", net.minecraft.world.item.ItemStack.class); + + public static ItemStack asBukkitCopy(net.minecraft.world.item.ItemStack nmsItem) { + try { + return (ItemStack) CRAFT_ITEM_STACK_AS_BUKKIT_COPY.invokeExact(nmsItem); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + public static final Field RecipeManager_featureFlagSet = ReflectionHelper.getFields(RecipeManager.class).getFirstOfType(FeatureFlagSet.class); public void setMaxStackSize(Material material, int size) { @@ -374,14 +385,14 @@ public ItemStack setSkullSkin(ItemStack itemStack, PlayerProfile playerProfile) GameProfile gameProfile = ProfileEditorImpl.getGameProfile(playerProfile); net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); nmsItemStack.set(DataComponents.PROFILE, ResolvableProfile.createResolved(gameProfile)); - return CraftItemStack.asBukkitCopy(nmsItemStack); + return asBukkitCopy(nmsItemStack); } @Override public ItemStack addNbtData(ItemStack itemStack, String key, BinaryTag value) { net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); nmsItemStack.update(DataComponents.CUSTOM_DATA, CustomData.EMPTY, customData -> customData.update(nmsCompoundTag -> nmsCompoundTag.put(key, NBTAdapter.toNMS(value)))); - return CraftItemStack.asBukkitCopy(nmsItemStack); + return asBukkitCopy(nmsItemStack); } // TODO: 1.20.6: this now needs to serialize components into NBT every single time, should probably only return custom NBT data with specialized methods for other usages @@ -398,7 +409,7 @@ public CompoundBinaryTag getNbtData(ItemStack itemStack) { // TODO: 1.20.6: same as getNbtData, ideally needs to only set custom NBT data and have specialized methods for other usages @Override public ItemStack setNbtData(ItemStack itemStack, CompoundBinaryTag compoundTag) { - return CraftItemStack.asBukkitCopy(parseNmsItem(NBTAdapter.toNMS(compoundTag))); + return asBukkitCopy(parseNmsItem(NBTAdapter.toNMS(compoundTag))); } @Override @@ -416,7 +427,7 @@ public ItemStack setCustomData(ItemStack item, CompoundBinaryTag data) { else { nmsItemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(NBTAdapter.toNMS(data))); } - return CraftItemStack.asBukkitCopy(nmsItemStack); + return asBukkitCopy(nmsItemStack); } public static final int DATA_VERSION_1_20_4 = 3700; @@ -431,7 +442,7 @@ public ItemStack setPartialOldNbt(ItemStack item, CompoundBinaryTag oldTag) { CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, nmsOldTag), DATA_VERSION_1_20_4, currentDataVersion).getValue(); CompoundTag nmsCurrentTag = serializeNmsItem(CraftItemStack.asNMSCopy(item)); CompoundTag nmsMergedTag = nmsCurrentTag.merge(nmsUpdatedTag); - return CraftItemStack.asBukkitCopy(parseNmsItem(nmsMergedTag)); + return asBukkitCopy(parseNmsItem(nmsMergedTag)); } @Override @@ -451,7 +462,7 @@ public ItemStack setEntityData(ItemStack item, CompoundBinaryTag entityNbt, Enti nmsEntityNbt.remove("id"); nmsItemStack.set(DataComponents.ENTITY_DATA, TypedEntityData.of(CraftEntityType.bukkitToMinecraft(entityType), nmsEntityNbt)); } - return CraftItemStack.asBukkitCopy(nmsItemStack); + return asBukkitCopy(nmsItemStack); } @Override @@ -498,7 +509,7 @@ public ItemStack setRawComponentsPatch(ItemStack item, MapTag rawComponentsMap, DataComponentPatch.CODEC.parse(registryOps, nmsRawComponents) .ifError(error -> errorHandler.accept(error.message())) .ifSuccess(nmsItemStack::applyComponents); - return CraftItemStack.asBukkitCopy(nmsItemStack); + return asBukkitCopy(nmsItemStack); } public static final Field AdventureModePredicate_predicates = ReflectionHelper.getFields(AdventureModePredicate.class).get("predicates"); @@ -555,13 +566,13 @@ private ItemStack setAdventureModePredicateMaterials(ItemStack item, DataCompone return item; } nmsItemStack.remove(nmsComponent); - return CraftItemStack.asBukkitCopy(nmsItemStack); + return asBukkitCopy(nmsItemStack); } BlockPredicate nmsPredicate = new BlockPredicate(Optional.of( HolderSet.direct(material -> BuiltInRegistries.BLOCK.get(CraftNamespacedKey.toMinecraft(material.getKey())).orElseThrow(), materials) ), Optional.empty(), Optional.empty(), DataComponentMatchers.ANY); nmsItemStack.set(nmsComponent, new AdventureModePredicate(List.of(nmsPredicate))); - return CraftItemStack.asBukkitCopy(nmsItemStack); + return asBukkitCopy(nmsItemStack); } @Override @@ -607,7 +618,7 @@ public void setDisplayName(ItemTag item, String name) { else { nmsItemStack.set(DataComponents.CUSTOM_NAME, Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE))); } - item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); + item.setItemStack(asBukkitCopy(nmsItemStack)); } @Override @@ -623,7 +634,7 @@ public void setLore(ItemTag item, List lore) { } nmsItemStack.set(DataComponents.LORE, new ItemLore(nmsLore)); } - item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); + item.setItemStack(asBukkitCopy(nmsItemStack)); } /** @@ -769,7 +780,7 @@ public Map getCustomBrewingRecipes() { } RecipeChoice ingredient = convertChoice(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "ingredient", paperMix)); RecipeChoice input = convertChoice(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "input", paperMix)); - ItemStack result = CraftItemStack.asBukkitCopy(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "result", paperMix)); + ItemStack result = asBukkitCopy(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "result", paperMix)); return new BrewingRecipe(input, ingredient, result); }); } diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/NBTAdapter.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/NBTAdapter.java index 9072903cba..41f35f52ac 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/NBTAdapter.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/NBTAdapter.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizencore.utilities.ReflectionHelper; import net.kyori.adventure.nbt.*; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PacketHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PacketHelperImpl.java index 38a889be6f..78e80f13b4 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PacketHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PacketHelperImpl.java @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.interfaces.PacketHelper; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.impl.SidebarImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.impl.SidebarImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; import com.denizenscript.denizen.utilities.FormattedTextHelper; @@ -27,6 +27,7 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.entity.PositionMoveRotation; import net.minecraft.world.entity.Relative; import net.minecraft.world.entity.ai.attributes.AttributeInstance; @@ -118,16 +119,16 @@ public void respawn(Player player) { public void setVision(Player player, EntityType entityType) { final net.minecraft.world.entity.LivingEntity entity; if (entityType == EntityType.CREEPER) { - entity = new Creeper(net.minecraft.world.entity.EntityType.CREEPER, ((CraftWorld) player.getWorld()).getHandle()); + entity = new Creeper(EntityTypes.CREEPER, ((CraftWorld) player.getWorld()).getHandle()); } else if (entityType == EntityType.SPIDER) { - entity = new Spider(net.minecraft.world.entity.EntityType.SPIDER, ((CraftWorld) player.getWorld()).getHandle()); + entity = new Spider(EntityTypes.SPIDER, ((CraftWorld) player.getWorld()).getHandle()); } else if (entityType == EntityType.CAVE_SPIDER) { - entity = new CaveSpider(net.minecraft.world.entity.EntityType.CAVE_SPIDER, ((CraftWorld) player.getWorld()).getHandle()); + entity = new CaveSpider(EntityTypes.CAVE_SPIDER, ((CraftWorld) player.getWorld()).getHandle()); } else if (entityType == EntityType.ENDERMAN) { - entity = new EnderMan(net.minecraft.world.entity.EntityType.ENDERMAN, ((CraftWorld) player.getWorld()).getHandle()); + entity = new EnderMan(EntityTypes.ENDERMAN, ((CraftWorld) player.getWorld()).getHandle()); } else { return; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PlayerHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PlayerHelperImpl.java index 0760d3bbee..5f86a70362 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PlayerHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/PlayerHelperImpl.java @@ -1,17 +1,17 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.ImprovedOfflinePlayer; import com.denizenscript.denizen.nms.enums.CustomEntityType; import com.denizenscript.denizen.nms.interfaces.PlayerHelper; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.impl.ImprovedOfflinePlayerImpl; -import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; -import com.denizenscript.denizen.nms.v26_1.impl.entities.CraftFakePlayerImpl; -import com.denizenscript.denizen.nms.v26_1.impl.entities.EntityItemProjectileImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.AbstractListenerPlayInImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.impl.ImprovedOfflinePlayerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_2.impl.entities.CraftFakePlayerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.entities.EntityItemProjectileImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.AbstractListenerPlayInImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/WorldHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/WorldHelperImpl.java index ce84fabd38..9cf7b262d9 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/WorldHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/WorldHelperImpl.java @@ -1,7 +1,7 @@ -package com.denizenscript.denizen.nms.v26_1.helpers; +package com.denizenscript.denizen.nms.v26_2.helpers; import com.denizenscript.denizen.nms.interfaces.WorldHelper; -import com.denizenscript.denizen.nms.v26_1.impl.BiomeNMSImpl; +import com.denizenscript.denizen.nms.v26_2.impl.BiomeNMSImpl; import com.denizenscript.denizen.objects.BiomeTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.mojang.datafixers.util.Pair; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/BiomeNMSImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/BiomeNMSImpl.java index 47e5afc040..c08d4c03f4 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/BiomeNMSImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/BiomeNMSImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl; +package com.denizenscript.denizen.nms.v26_2.impl; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.BiomeNMS; -import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_2.Handler; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.core.BlockPos; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ImprovedOfflinePlayerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ImprovedOfflinePlayerImpl.java index dfed25aac1..4826347c16 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ImprovedOfflinePlayerImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ImprovedOfflinePlayerImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl; +package com.denizenscript.denizen.nms.v26_2.impl; import com.denizenscript.denizen.nms.abstracts.ImprovedOfflinePlayer; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.helpers.NBTAdapter; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.helpers.NBTAdapter; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; import net.kyori.adventure.nbt.CompoundBinaryTag; @@ -14,6 +14,7 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.ItemStackWithSlot; import net.minecraft.world.entity.EntityEquipment; +import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.AttributeMap; @@ -132,7 +133,7 @@ public void setMaxHealth(double input) { } private AttributeMap getAttributes() { - AttributeMap amb = new AttributeMap(DefaultAttributes.getSupplier(net.minecraft.world.entity.EntityType.PLAYER)); + AttributeMap amb = new AttributeMap(DefaultAttributes.getSupplier(EntityTypes.PLAYER)); Handler.useValueInput(NBTAdapter.toNMS(this.compound), valueInput -> valueInput.read("attributes", AttributeInstance.Packed.LIST_CODEC).ifPresent(amb::apply)); return amb; } @@ -145,7 +146,7 @@ public void setAttributes(AttributeMap attributes) { protected boolean loadPlayerData(UUID uuid) { try { this.player = uuid; - this.file = new File(MinecraftServer.getServer().playerDataStorage.getPlayerDir(), this.player + ".dat"); + this.file = new File(MinecraftServer.getServer().getPlayerList().playerIo.getPlayerDir(), this.player + ".dat"); if (this.file.exists()) { this.compound = NBTAdapter.toAPI(NbtIo.readCompressed(new FileInputStream(this.file), NbtAccounter.unlimitedHeap())); return true; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ProfileEditorImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ProfileEditorImpl.java index d620ff984f..881c6df7ff 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ProfileEditorImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/ProfileEditorImpl.java @@ -1,12 +1,12 @@ -package com.denizenscript.denizen.nms.v26_1.impl; +package com.denizenscript.denizen.nms.v26_2.impl; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.ProfileEditor; import com.denizenscript.denizen.nms.util.PlayerProfile; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.ReflectionHelper; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/SidebarImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/SidebarImpl.java index 0e08145f36..69f2257017 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/SidebarImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/SidebarImpl.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl; +package com.denizenscript.denizen.nms.v26_2.impl; import com.denizenscript.denizen.nms.abstracts.Sidebar; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.helpers.PacketHelperImpl; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.md_5.bungee.api.ChatColor; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/blocks/BlockLightImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/blocks/BlockLightImpl.java index e64e9483fb..b81f0a6bde 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/blocks/BlockLightImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/blocks/BlockLightImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.blocks; +package com.denizenscript.denizen.nms.v26_2.impl.blocks; import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.BlockLight; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakeArrowImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakeArrowImpl.java index 160f12a001..7d622d3984 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakeArrowImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakeArrowImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.entities; +package com.denizenscript.denizen.nms.v26_2.impl.entities; import com.denizenscript.denizen.nms.interfaces.FakeArrow; import net.minecraft.world.entity.projectile.arrow.AbstractArrow; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakePlayerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakePlayerImpl.java index 79f8121011..7effccb9b1 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakePlayerImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftFakePlayerImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.entities; +package com.denizenscript.denizen.nms.v26_2.impl.entities; import com.denizenscript.denizen.nms.interfaces.FakePlayer; import com.denizenscript.denizen.nms.NMSHandler; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftItemProjectileImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftItemProjectileImpl.java index da41f2da0c..624eefbf70 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftItemProjectileImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/CraftItemProjectileImpl.java @@ -1,6 +1,7 @@ -package com.denizenscript.denizen.nms.v26_1.impl.entities; +package com.denizenscript.denizen.nms.v26_2.impl.entities; import com.denizenscript.denizen.nms.interfaces.ItemProjectile; +import com.denizenscript.denizen.nms.v26_2.helpers.ItemHelperImpl; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import org.bukkit.craftbukkit.CraftServer; @@ -42,7 +43,7 @@ public String getEntityTypeName() { @Override public ItemStack getItemStack() { - return CraftItemStack.asBukkitCopy(getHandle().getItemStack()); + return ItemHelperImpl.asBukkitCopy(getHandle().getItemStack()); } @Override diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakeArrowImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakeArrowImpl.java index 01b789f238..8d40d1ace4 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakeArrowImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakeArrowImpl.java @@ -1,7 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl.entities; +package com.denizenscript.denizen.nms.v26_2.impl.entities; -import com.denizenscript.denizen.nms.v26_1.Handler; +import com.denizenscript.denizen.nms.v26_2.Handler; import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.entity.projectile.arrow.SpectralArrow; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -14,7 +15,7 @@ public class EntityFakeArrowImpl extends SpectralArrow { public EntityFakeArrowImpl(CraftWorld craftWorld, Location location) { - super(net.minecraft.world.entity.EntityType.SPECTRAL_ARROW, craftWorld.getHandle()); + super(EntityTypes.SPECTRAL_ARROW, craftWorld.getHandle()); try { Handler.ENTITY_BUKKITYENTITY.set(this, new CraftFakeArrowImpl((CraftServer) Bukkit.getServer(), this)); } diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakePlayerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakePlayerImpl.java index d81df1ffa7..84332b3107 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakePlayerImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityFakePlayerImpl.java @@ -1,9 +1,9 @@ -package com.denizenscript.denizen.nms.v26_1.impl.entities; +package com.denizenscript.denizen.nms.v26_2.impl.entities; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.impl.network.fakes.FakeNetworkManagerImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.fakes.FakePlayerConnectionImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.impl.network.fakes.FakeNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.fakes.FakePlayerConnectionImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; import net.minecraft.network.protocol.PacketFlow; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityItemProjectileImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityItemProjectileImpl.java index e385265301..8771ed2bda 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityItemProjectileImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/entities/EntityItemProjectileImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.entities; +package com.denizenscript.denizen.nms.v26_2.impl.entities; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -7,6 +7,7 @@ import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.projectile.ThrowableProjectile; import net.minecraft.world.item.ItemStack; @@ -36,7 +37,7 @@ public class EntityItemProjectileImpl extends ThrowableProjectile { } public EntityItemProjectileImpl(Level world, Location location, ItemStack item) { - super((net.minecraft.world.entity.EntityType) net.minecraft.world.entity.EntityType.ITEM, world); + super((net.minecraft.world.entity.EntityType) EntityTypes.ITEM, world); try { setBukkitEntityMethod.invoke(this, new CraftItemProjectileImpl(((ServerLevel) world).getServer().server, this)); } diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeChannelImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeChannelImpl.java index e265656f2e..9c14ea7dd4 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeChannelImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeChannelImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; +package com.denizenscript.denizen.nms.v26_2.impl.network.fakes; import io.netty.channel.*; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeNetworkManagerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeNetworkManagerImpl.java index a94b4367aa..10b17690fb 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeNetworkManagerImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakeNetworkManagerImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; +package com.denizenscript.denizen.nms.v26_2.impl.network.fakes; import net.minecraft.network.Connection; import net.minecraft.network.protocol.PacketFlow; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakePlayerConnectionImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakePlayerConnectionImpl.java index 373e74ada5..0804cca68d 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakePlayerConnectionImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/fakes/FakePlayerConnectionImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.fakes; +package com.denizenscript.denizen.nms.v26_2.impl.network.fakes; import net.minecraft.network.Connection; import net.minecraft.network.protocol.Packet; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/AbstractListenerPlayInImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/AbstractListenerPlayInImpl.java index 6d5d5a2b48..97d6182d45 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/AbstractListenerPlayInImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/AbstractListenerPlayInImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers; import com.denizenscript.denizen.events.player.PlayerSendPacketScriptEvent; import com.denizenscript.denizen.nms.NMSHandler; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java index 4023acd8d5..da4f6aa456 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -1,9 +1,9 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers; import com.denizenscript.denizen.events.player.PlayerReceivesPacketScriptEvent; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet.*; +import com.denizenscript.denizen.nms.v26_2.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet.*; import com.denizenscript.denizen.utilities.Settings; import com.denizenscript.denizen.utilities.packets.NetworkInterceptCodeGen; import com.denizenscript.denizencore.utilities.CoreUtilities; @@ -41,10 +41,7 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -469,8 +466,13 @@ public void setEncryptionKey(Cipher cipher, Cipher cipher1) { } @Override - public boolean isEncrypted() { - return oldManager.isEncrypted(); + public void setIntendedProfileId(UUID profileId) { + oldManager.setIntendedProfileId(profileId); + } + + @Override + public UUID getIntendedProfileId() { + return oldManager.getIntendedProfileId(); } @Override diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenPacketListenerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenPacketListenerImpl.java index 224b0c76ba..b69819fd14 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenPacketListenerImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenPacketListenerImpl.java @@ -1,10 +1,10 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers; import com.denizenscript.denizen.events.player.PlayerChangesSignScriptEvent; import com.denizenscript.denizen.events.player.PlayerSteersEntityScriptEvent; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketInResourcePackStatusImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketInSteerVehicleImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.packets.PacketInResourcePackStatusImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.packets.PacketInSteerVehicleImpl; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java index 11a61644f0..e25cf5ae38 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers; import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.objects.LocationTag; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/ActionBarEventPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/ActionBarEventPacketHandlers.java index c1f641f7b5..5ddec205f5 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/ActionBarEventPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/ActionBarEventPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerReceivesActionbarScriptEvent; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.objects.core.ElementTag; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/AttachPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/AttachPacketHandlers.java index b1dc7adaf2..96e3bad4fa 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/AttachPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/AttachPacketHandlers.java @@ -1,7 +1,7 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.ReflectionHelper; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/BlockLightPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/BlockLightPacketHandlers.java index 0a6f0257bc..3ce4b72fb0 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/BlockLightPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/BlockLightPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; import com.denizenscript.denizen.nms.abstracts.BlockLight; -import com.denizenscript.denizen.nms.v26_1.impl.blocks.BlockLightImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.blocks.BlockLightImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java index 43f76611ee..255a57fed6 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerReceivesMessageScriptEvent; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.packets.PacketOutChatImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.packets.PacketOutChatImpl; import com.denizenscript.denizen.utilities.packets.DenizenPacketHandler; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DisguisePacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DisguisePacketHandlers.java index 12f13d8070..c89e8fb819 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DisguisePacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/DisguisePacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; import com.denizenscript.denizen.utilities.entity.EntityAttachmentHelper; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/EntityMetadataPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/EntityMetadataPacketHandlers.java index f0b1cf4b7f..a039e0f218 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/EntityMetadataPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/EntityMetadataPacketHandlers.java @@ -1,8 +1,8 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.helpers.PacketHelperImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.GlowCommand; import com.denizenscript.denizen.scripts.commands.entity.InvisibleCommand; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 0144bcfa08..55ffea84b7 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -1,7 +1,7 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.FakeBlockHelper; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.FakeBlockHelper; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java index 9471624704..7f5547eaf6 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeEquipmentPacketHandlers.java @@ -1,6 +1,6 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; import com.mojang.datafixers.util.Pair; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakePlayerPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakePlayerPacketHandlers.java index ac5c76ae4f..9b5f0b2c05 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakePlayerPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakePlayerPacketHandlers.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; /* import com.denizenscript.denizen.nms.NMSHandler; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java index d905b22d07..46425d983e 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HiddenEntitiesPacketHandlers.java @@ -1,6 +1,6 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.entity.HideEntitiesHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.network.protocol.Packet; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HideParticlesPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HideParticlesPacketHandlers.java index 70c64da27b..12ceca2b78 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HideParticlesPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/HideParticlesPacketHandlers.java @@ -1,6 +1,6 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.packets.HideParticles; import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; import org.bukkit.Particle; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java index f26a97ad7e..60ac9388e8 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/PlayerHearsSoundEventPacketHandlers.java @@ -1,7 +1,7 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerHearsSoundScriptEvent; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java index cd436d5d26..95cb8f5189 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java @@ -1,9 +1,9 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.handlers.packet; +package com.denizenscript.denizen.nms.v26_2.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerReceivesTablistUpdateScriptEvent; -import com.denizenscript.denizen.nms.v26_1.Handler; -import com.denizenscript.denizen.nms.v26_1.impl.ProfileEditorImpl; -import com.denizenscript.denizen.nms.v26_1.impl.network.handlers.DenizenNetworkManagerImpl; +import com.denizenscript.denizen.nms.v26_2.Handler; +import com.denizenscript.denizen.nms.v26_2.impl.ProfileEditorImpl; +import com.denizenscript.denizen.nms.v26_2.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.Debug; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInResourcePackStatusImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInResourcePackStatusImpl.java index 64a80bad64..ddcf59c7b3 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInResourcePackStatusImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInResourcePackStatusImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.packets; +package com.denizenscript.denizen.nms.v26_2.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketInResourcePackStatus; import net.minecraft.network.protocol.common.ServerboundResourcePackPacket; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInSteerVehicleImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInSteerVehicleImpl.java index fb041134f3..401b1d89c4 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInSteerVehicleImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketInSteerVehicleImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.packets; +package com.denizenscript.denizen.nms.v26_2.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketInSteerVehicle; import net.minecraft.network.protocol.game.ServerboundPlayerInputPacket; diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketOutChatImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketOutChatImpl.java index ed5445a201..4bb78f2e3e 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketOutChatImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/packets/PacketOutChatImpl.java @@ -1,4 +1,4 @@ -package com.denizenscript.denizen.nms.v26_1.impl.network.packets; +package com.denizenscript.denizen.nms.v26_2.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; import com.denizenscript.denizen.utilities.FormattedTextHelper; From 10dad85525302edb659bcbc21a4289721ca55f8b Mon Sep 17 00:00:00 2001 From: MCSamuel <187220916+MC-Samuel@users.noreply.github.com> Date: Thu, 18 Jun 2026 14:54:21 -0700 Subject: [PATCH 106/169] Sulfur cube & potent sulfur features (#2827) * 26.2 additions to existing properties * formatting fixes --- .../objects/properties/entity/EntitySize.java | 148 +++++++----------- .../properties/material/MaterialMode.java | 82 +++++----- 2 files changed, 99 insertions(+), 131 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java index e821a24dbc..44cfb4c1c7 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java @@ -1,53 +1,68 @@ package com.denizenscript.denizen.objects.properties.entity; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.EntityTag; +import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.ObjectTag; -import com.denizenscript.denizencore.objects.properties.Property; -import com.denizenscript.denizencore.objects.properties.PropertyParser; -import org.bukkit.entity.Phantom; -import org.bukkit.entity.PufferFish; -import org.bukkit.entity.Slime; - -public class EntitySize implements Property { - - public static boolean describes(ObjectTag entity) { - return entity instanceof EntityTag && - (((EntityTag) entity).getBukkitEntity() instanceof Slime - || ((EntityTag) entity).getBukkitEntity() instanceof Phantom - || ((EntityTag) entity).getBukkitEntity() instanceof PufferFish); +import org.bukkit.entity.*; + +public class EntitySize extends EntityProperty { + // TODO: once 26.2 is the minimum supported version, remove Slime usage in favor of AbstractCubeMob + + // <--[property] + // @object MaterialTag + // @name mode + // @input ElementTag + // @description + // Controls the size of an entity. + // Cube-type (slime, magma cube, sulfur cube) mob sizes are between 1 and 127. + // Phantom mob sizes are between 0 and 64. + // Pufferfish mob sizes are between 0 and 2. + // --> + + public static boolean describes(EntityTag entity) { + Entity bukkitEntity = entity.getBukkitEntity(); + return bukkitEntity instanceof Phantom + || bukkitEntity instanceof PufferFish + || bukkitEntity instanceof Slime + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && bukkitEntity instanceof AbstractCubeMob); } - public static EntitySize getFrom(ObjectTag entity) { - if (!describes(entity)) { - return null; - } - else { - return new EntitySize((EntityTag) entity); + @Override + public ElementTag getPropertyValue() { + if (getEntity() instanceof Phantom phantom) { + return new ElementTag(phantom.getSize()); } - } - - public EntitySize(EntityTag ent) { - entity = ent; - } - - EntityTag entity; - - public int getSize() { - if (isSlime()) { - return getSlime().getSize(); + else if (getEntity() instanceof PufferFish pufferfish) { + return new ElementTag(pufferfish.getPuffState()); } - else if (isPhantom()) { - return getPhantom().getSize(); + else if (getEntity() instanceof Slime slime) { + return new ElementTag(slime.getSize()); } - else { - return getPufferFish().getPuffState(); + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && getEntity() instanceof AbstractCubeMob cube) { + return new ElementTag(cube.getSize()); } + return null; } @Override - public String getPropertyString() { - return String.valueOf(getSize()); + public void setPropertyValue(ElementTag value, Mechanism mechanism) { + if (!mechanism.requireInteger()) { + return; + } + if (getEntity() instanceof Phantom phantom) { + phantom.setSize(value.asInt()); + } + else if (getEntity() instanceof PufferFish pufferfish) { + pufferfish.setPuffState(value.asInt()); + } + else if (getEntity() instanceof Slime slime) { + slime.setSize(value.asInt()); + } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && getEntity() instanceof AbstractCubeMob cube) { + cube.setSize(value.asInt()); + } } @Override @@ -56,63 +71,6 @@ public String getPropertyId() { } public static void register() { - - // <--[tag] - // @attribute - // @returns ElementTag(Number) - // @mechanism EntityTag.size - // @group properties - // @description - // Returns the size of a slime-type entity or a Phantom (1-120). - // If the entity is a PufferFish it returns the puff state (0-3). - // --> - PropertyParser.registerTag(EntitySize.class, ElementTag.class, "size", (attribute, object) -> { - return new ElementTag(object.getSize()); - }); - - - // <--[mechanism] - // @object EntityTag - // @name size - // @input ElementTag(Number) - // @description - // Sets the size of a slime-type entity or a Phantom (1-120). - // If the entity is a PufferFish it sets the puff state (0-3). - // @tags - // - // --> - PropertyParser.registerMechanism(EntitySize.class, ElementTag.class, "size", (object, mechanism, input) -> { - if (mechanism.requireInteger()) { - if (object.isSlime()) { - object.getSlime().setSize(input.asInt()); - } - else if (object.isPhantom()) { - object.getPhantom().setSize(input.asInt()); - } - else { - object.getPufferFish().setPuffState(input.asInt()); - } - } - }); - } - - public boolean isSlime() { - return entity.getBukkitEntity() instanceof Slime; - } - - public boolean isPhantom() { - return entity.getBukkitEntity() instanceof Phantom; - } - - public Slime getSlime() { - return (Slime) entity.getBukkitEntity(); - } - - public Phantom getPhantom() { - return (Phantom) entity.getBukkitEntity(); - } - - public PufferFish getPufferFish() { - return (PufferFish) entity.getBukkitEntity(); + autoRegister("size", EntitySize.class, ElementTag.class, false); } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java index 1f40830f93..89dc0216e8 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java @@ -16,65 +16,67 @@ public class MaterialMode extends MaterialProperty { // @input ElementTag // @description // Controls a block's mode. - // For comparators, modes are COMPARE and SUBTRACT. - // For piston_heads, modes are NORMAL and SHORT. + // For big_dripleafs, modes are FULL, NONE, PARTIAL, and UNSTABLE. // For bubble_columns, modes are NORMAL and DRAG. - // For structure_blocks, modes are CORNER, DATA, LOAD, and SAVE. - // For sculk_sensors, modes are ACTIVE, COOLDOWN, and INACTIVE. - // For daylight_detectors, modes are INVERTED and NORMAL. // For command_blocks, modes are CONDITIONAL and NORMAL. - // For big_dripleafs, modes are FULL, NONE, PARTIAL, and UNSTABLE. + // For comparators, modes are COMPARE and SUBTRACT. + // For creaking_hearts, modes are AWAKE, DORMANT, and UPROOTED. + // For daylight_detectors, modes are INVERTED and NORMAL. + // For potent sulfur, modes are CONTINUOUS, DORMANT, DRY, ERUPTING, and WET. CONTINUOUS is only available on Paper. + // For piston_heads, modes are NORMAL and SHORT. // For sculk_catalysts, modes are BLOOM and NORMAL. + // For sculk_sensors, modes are ACTIVE, COOLDOWN, and INACTIVE. // For sculk_shriekers, modes are SHRIEKING and NORMAL. + // For structure_blocks, modes are CORNER, DATA, LOAD, and SAVE. // For tripwires, modes are ARMED and DISARMED. - // For creaking_hearts, modes are AWAKE, DORMANT, and UPROOTED. // For trial_spawners, modes are ACTIVE, COOLDOWN, EJECTING_REWARD, INACTIVE, WAITING_FOR_PLAYERS, and WAITING_FOR_REWARD_EJECTION. // For vaults, modes are ACTIVE, EJECTING, INACTIVE, and UNLOCKING. // --> public static boolean describes(MaterialTag material) { BlockData data = material.getModernData(); - return data instanceof Comparator - || data instanceof PistonHead + return data instanceof BigDripleaf || data instanceof BubbleColumn - || data instanceof StructureBlock - || data instanceof DaylightDetector || data instanceof CommandBlock + || data instanceof Comparator + || data instanceof DaylightDetector + || data instanceof PistonHead || data instanceof SculkSensor - || data instanceof BigDripleaf + || data instanceof StructureBlock || data instanceof Tripwire || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19) && (data instanceof SculkCatalyst || data instanceof SculkShrieker)) || (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && (data instanceof CreakingHeart || data instanceof TrialSpawner - || data instanceof Vault)); + || data instanceof Vault)) + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && data instanceof PotentSulfur); } @Override public ElementTag getPropertyValue() { - if (getBlockData() instanceof Comparator comparator) { - return new ElementTag(comparator.getMode()); + if (getBlockData() instanceof BigDripleaf bigDripleaf) { + return new ElementTag(bigDripleaf.getTilt()); } else if (getBlockData() instanceof BubbleColumn bubbleColumn) { return new ElementTag(bubbleColumn.isDrag() ? "DRAG" : "NORMAL", true); } - else if (getBlockData() instanceof PistonHead pistonHead) { - return new ElementTag(pistonHead.isShort() ? "SHORT" : "NORMAL", true); + else if (getBlockData() instanceof CommandBlock cmdBlock) { + return new ElementTag(cmdBlock.isConditional() ? "CONDITIONAL" : "NORMAL", true); } - else if (getBlockData() instanceof StructureBlock structureBlock) { - return new ElementTag(structureBlock.getMode()); + else if (getBlockData() instanceof Comparator comparator) { + return new ElementTag(comparator.getMode()); } else if (getBlockData() instanceof DaylightDetector daylightDetector) { return new ElementTag(daylightDetector.isInverted() ? "INVERTED" : "NORMAL", true); } - else if (getBlockData() instanceof CommandBlock cmdBlock) { - return new ElementTag(cmdBlock.isConditional() ? "CONDITIONAL" : "NORMAL", true); + else if (getBlockData() instanceof PistonHead pistonHead) { + return new ElementTag(pistonHead.isShort() ? "SHORT" : "NORMAL", true); } else if (getBlockData() instanceof SculkSensor sculkSensor) { return new ElementTag(sculkSensor.getPhase()); } - else if (getBlockData() instanceof BigDripleaf bigDripleaf) { - return new ElementTag(bigDripleaf.getTilt()); + else if (getBlockData() instanceof StructureBlock structureBlock) { + return new ElementTag(structureBlock.getMode()); } else if (getBlockData() instanceof Tripwire tripwire) { return new ElementTag(tripwire.isDisarmed() ? "DISARMED" : "ARMED", true); @@ -94,41 +96,44 @@ else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() i else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() instanceof Vault vault) { return new ElementTag(vault.getVaultState().name(), true); // TODO: once 1.21 is the minimum supported version, use the enum constructor } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && getBlockData() instanceof PotentSulfur potentSulfur) { + return new ElementTag(potentSulfur.getPotentSulfurState().name(), true); // TODO: once 1.21. is the minimum supported version, use the enum constructor + } return null; } @Override public void setPropertyValue(ElementTag value, Mechanism mechanism) { - if (getBlockData() instanceof Comparator comparator) { - if (mechanism.requireEnum(Comparator.Mode.class)) { - comparator.setMode(value.asEnum(Comparator.Mode.class)); + if (getBlockData() instanceof BigDripleaf bigDripleaf) { + if (mechanism.requireEnum(BigDripleaf.Tilt.class)) { + bigDripleaf.setTilt(value.asEnum(BigDripleaf.Tilt.class)); } } else if (getBlockData() instanceof BubbleColumn bubbleColumn) { bubbleColumn.setDrag(value.asLowerString().equals("drag")); } - else if (getBlockData() instanceof PistonHead pistonHead) { - pistonHead.setShort(value.asLowerString().equals("short")); + else if (getBlockData() instanceof CommandBlock cmdBlock) { + cmdBlock.setConditional(value.asLowerString().equals("conditional")); } - else if (getBlockData() instanceof StructureBlock structureBlock) { - if (mechanism.requireEnum(StructureBlock.Mode.class)) { - structureBlock.setMode(value.asEnum(StructureBlock.Mode.class)); + else if (getBlockData() instanceof Comparator comparator) { + if (mechanism.requireEnum(Comparator.Mode.class)) { + comparator.setMode(value.asEnum(Comparator.Mode.class)); } } else if (getBlockData() instanceof DaylightDetector daylightDetector) { daylightDetector.setInverted(value.asLowerString().equals("inverted")); } - else if (getBlockData() instanceof CommandBlock cmdBlock) { - cmdBlock.setConditional(value.asLowerString().equals("conditional")); + else if (getBlockData() instanceof PistonHead pistonHead) { + pistonHead.setShort(value.asLowerString().equals("short")); } else if (getBlockData() instanceof SculkSensor sculkSensor) { if (mechanism.requireEnum(SculkSensor.Phase.class)) { sculkSensor.setPhase(value.asEnum(SculkSensor.Phase.class)); } } - else if (getBlockData() instanceof BigDripleaf bigDripleaf) { - if (mechanism.requireEnum(BigDripleaf.Tilt.class)) { - bigDripleaf.setTilt(value.asEnum(BigDripleaf.Tilt.class)); + else if (getBlockData() instanceof StructureBlock structureBlock) { + if (mechanism.requireEnum(StructureBlock.Mode.class)) { + structureBlock.setMode(value.asEnum(StructureBlock.Mode.class)); } } else if (getBlockData() instanceof Tripwire tripwire) { @@ -155,6 +160,11 @@ else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() i vault.setVaultState(value.asEnum(Vault.State.class)); } } + else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && getBlockData() instanceof PotentSulfur potentSulfur) { + if (mechanism.requireEnum(PotentSulfur.State.class)) { + potentSulfur.setPotentSulfurState(value.asEnum(PotentSulfur.State.class)); + } + } } @Override From 1630b0add51f2c2f5383b57e0ea87ac724d6dc91 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 18 Jun 2026 23:20:51 +0100 Subject: [PATCH 107/169] Minor fixes to recent PR --- .../objects/properties/entity/EntitySize.java | 12 ++++++------ .../objects/properties/material/MaterialMode.java | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java index 44cfb4c1c7..89dd66077e 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java @@ -21,12 +21,12 @@ public class EntitySize extends EntityProperty { // Pufferfish mob sizes are between 0 and 2. // --> - public static boolean describes(EntityTag entity) { - Entity bukkitEntity = entity.getBukkitEntity(); - return bukkitEntity instanceof Phantom - || bukkitEntity instanceof PufferFish - || bukkitEntity instanceof Slime - || (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && bukkitEntity instanceof AbstractCubeMob); + public static boolean describes(EntityTag entityTag) { + Entity entity = entityTag.getBukkitEntity(); + return entity instanceof Phantom + || entity instanceof PufferFish + || entity instanceof Slime + || (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && entity instanceof AbstractCubeMob); } @Override diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java index 89dc0216e8..68f720512a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/material/MaterialMode.java @@ -22,7 +22,7 @@ public class MaterialMode extends MaterialProperty { // For comparators, modes are COMPARE and SUBTRACT. // For creaking_hearts, modes are AWAKE, DORMANT, and UPROOTED. // For daylight_detectors, modes are INVERTED and NORMAL. - // For potent sulfur, modes are CONTINUOUS, DORMANT, DRY, ERUPTING, and WET. CONTINUOUS is only available on Paper. + // For potent_sulfur, modes are CONTINUOUS, DORMANT, DRY, ERUPTING, and WET. // For piston_heads, modes are NORMAL and SHORT. // For sculk_catalysts, modes are BLOOM and NORMAL. // For sculk_sensors, modes are ACTIVE, COOLDOWN, and INACTIVE. @@ -97,7 +97,7 @@ else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21) && getBlockData() i return new ElementTag(vault.getVaultState().name(), true); // TODO: once 1.21 is the minimum supported version, use the enum constructor } else if (NMSHandler.getVersion().isAtLeast(NMSVersion.v26_2) && getBlockData() instanceof PotentSulfur potentSulfur) { - return new ElementTag(potentSulfur.getPotentSulfurState().name(), true); // TODO: once 1.21. is the minimum supported version, use the enum constructor + return new ElementTag(potentSulfur.getPotentSulfurState().name(), true); // TODO: once 26.2 is the minimum supported version, use the enum constructor } return null; } From 0ebde8310d2b199809a5f1873c3169ccf6168362 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 18 Jun 2026 23:21:02 +0100 Subject: [PATCH 108/169] 26.2 Paper NMS patch --- .../denizen/nms/v26_2/helpers/ItemHelperImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java index 6abf550fff..0e851f7076 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/helpers/ItemHelperImpl.java @@ -439,7 +439,7 @@ public ItemStack setPartialOldNbt(ItemStack item, CompoundBinaryTag oldTag) { nmsOldTag.putString("id", item.getType().getKey().toString()); nmsOldTag.putByte("Count", (byte) item.getAmount()); nmsOldTag.put("tag", NBTAdapter.toNMS(oldTag)); - CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, nmsOldTag), DATA_VERSION_1_20_4, currentDataVersion).getValue(); + CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().getFixerUpper().update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, nmsOldTag), DATA_VERSION_1_20_4, currentDataVersion).getValue(); CompoundTag nmsCurrentTag = serializeNmsItem(CraftItemStack.asNMSCopy(item)); CompoundTag nmsMergedTag = nmsCurrentTag.merge(nmsUpdatedTag); return asBukkitCopy(parseNmsItem(nmsMergedTag)); @@ -502,7 +502,7 @@ public ItemStack setRawComponentsPatch(ItemStack item, MapTag rawComponentsMap, legacyItemData.putString("id", item.getType().getKey().toString()); legacyItemData.putInt("count", item.getAmount()); legacyItemData.put("components", nmsRawComponents); - CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(registryOps, legacyItemData), dataVersion, currentDataVersion).getValue(); + CompoundTag nmsUpdatedTag = (CompoundTag) MinecraftServer.getServer().getFixerUpper().update(References.ITEM_STACK, new Dynamic<>(registryOps, legacyItemData), dataVersion, currentDataVersion).getValue(); nmsRawComponents = nmsUpdatedTag.getCompound("components").orElseGet(CompoundTag::new); } net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item); From c61d157551f6e4fafac6e82ed75cba6985be2258 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Thu, 18 Jun 2026 21:59:17 -0700 Subject: [PATCH 109/169] fix meta errors --- .../paper/datacomponents/MaxDurabilityAdapter.java | 4 +++- .../denizen/objects/properties/entity/EntitySize.java | 4 ++-- .../denizen/objects/properties/item/ItemDurability.java | 9 +-------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxDurabilityAdapter.java b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxDurabilityAdapter.java index 6a9967d95f..cc021bda08 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxDurabilityAdapter.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/datacomponents/MaxDurabilityAdapter.java @@ -11,7 +11,9 @@ public class MaxDurabilityAdapter extends DataComponentAdapter.Valued. + // Controls the maximum durability (number of uses) of this item. + // For use with <@link tag ItemTag.durability> and <@link mechanism ItemTag.durability>. + // See also <@link language Item Components>. // @mechanism // Provide no input to reset the item to its default value. // --> diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java index 89dd66077e..6c58c4fab9 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/entity/EntitySize.java @@ -11,8 +11,8 @@ public class EntitySize extends EntityProperty { // TODO: once 26.2 is the minimum supported version, remove Slime usage in favor of AbstractCubeMob // <--[property] - // @object MaterialTag - // @name mode + // @object EntityTag + // @name size // @input ElementTag // @description // Controls the size of an entity. diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemDurability.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemDurability.java index ddd46aa1fb..a8a8b3847d 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemDurability.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemDurability.java @@ -58,14 +58,7 @@ public ObjectTag getObjectAttribute(Attribute attribute) { .getObjectAttribute(attribute.fulfill(1)); } - // <--[tag] - // @attribute - // @returns ElementTag(Number) - // @group properties - // @description - // Returns the maximum durability (number of uses) of this item. - // For use with <@link tag ItemTag.durability> and <@link mechanism ItemTag.durability>. - // --> + // replaced by paper->MaxDurabilityAdapter if (attribute.startsWith("max_durability")) { return new ElementTag(item.getMaterial().getMaterial().getMaxDurability()) .getObjectAttribute(attribute.fulfill(1)); From 118a5b098ceee48442da419332e2aaa6b426cdf9 Mon Sep 17 00:00:00 2001 From: MCSamuel <187220916+MC-Samuel@users.noreply.github.com> Date: Thu, 9 Jul 2026 02:16:18 -0700 Subject: [PATCH 110/169] Multi-Sided Sign Support (#2796) * Added SignContentsBack ItemTag property and LocationTag tag and mechanism. Added back-of-sign support to CopyBlock command * slight corrections * one more * slight adjustments * meta removal fix from merge * meta fix from original pr implementation * added back-of-sign glowing and glow color tags and mechanisms * minor changes * renamed `sign_x_back` usages to `sign_back_x` * missed one * meta clarification * minor changes * fixes * import changes --- .../denizen/paper/PaperModule.java | 11 + .../paper/utilities/PaperAPIToolsImpl.java | 27 +- .../denizen/objects/LocationTag.java | 328 +++++++++++++----- .../objects/properties/PropertyRegistry.java | 1 + .../properties/item/ItemSignContents.java | 124 ++----- .../properties/item/ItemSignContentsBack.java | 60 ++++ .../commands/world/CopyBlockCommand.java | 13 +- .../denizen/utilities/PaperAPITools.java | 29 +- 8 files changed, 391 insertions(+), 202 deletions(-) create mode 100644 plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContentsBack.java diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index 3b53707e18..3775fc1409 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -21,6 +21,9 @@ import net.md_5.bungee.api.ChatColor; import org.bukkit.Bukkit; +import java.util.ArrayList; +import java.util.List; + public class PaperModule { public static void init() { @@ -175,6 +178,14 @@ public static String stringifyComponent(Component component) { return FormattedTextHelper.stringify(FormattedTextHelper.parseJson(componentToJson(component))); } + public static List stringifyComponentList(List components) { + List values = new ArrayList<>(components.size()); + for (Component component : components) { + values.add(stringifyComponent(component)); + } + return values; + } + public static Component jsonToComponent(String json) { if (json == null) { return null; diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java index 0b6d741ced..71975bf001 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java @@ -28,6 +28,7 @@ import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.*; import org.bukkit.block.Sign; +import org.bukkit.block.sign.Side; import org.bukkit.command.CommandSender; import org.bukkit.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent; @@ -101,18 +102,28 @@ public String getPlayerListName(Player player) { } @Override - public String[] getSignLines(Sign sign) { - String[] output = new String[4]; - int i = 0; - for (Component component : sign.lines()) { - output[i++] = PaperModule.stringifyComponent(component); - } - return output; + public List getSignLines(Sign sign) { + return PaperModule.stringifyComponentList(NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? sign.getSide(Side.FRONT).lines() : sign.lines()); + } + + @Override + public List getBackSignLines(Sign sign) { + return PaperModule.stringifyComponentList(sign.getSide(Side.BACK).lines()); } @Override public void setSignLine(Sign sign, int line, String text) { - sign.line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK)); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + sign.getSide(Side.FRONT).line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK)); + } + else { + sign.line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK)); + } + } + + @Override + public void setBackSignLine(Sign sign, int line, String text) { + sign.getSide(Side.BACK).line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK)); } @Override diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java index a57c200884..23f02ca817 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java @@ -7,10 +7,7 @@ import com.denizenscript.denizen.nms.interfaces.EntityHelper; import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.objects.properties.bukkit.BukkitColorExtensions; -import com.denizenscript.denizen.objects.properties.material.MaterialAttachmentFace; -import com.denizenscript.denizen.objects.properties.material.MaterialDirectional; -import com.denizenscript.denizen.objects.properties.material.MaterialDistance; -import com.denizenscript.denizen.objects.properties.material.MaterialHalf; +import com.denizenscript.denizen.objects.properties.material.*; import com.denizenscript.denizen.scripts.commands.world.SwitchCommand; import com.denizenscript.denizen.utilities.*; import com.denizenscript.denizen.utilities.blocks.SpawnableHelper; @@ -25,10 +22,7 @@ import com.denizenscript.denizencore.objects.notable.Notable; import com.denizenscript.denizencore.objects.notable.Note; import com.denizenscript.denizencore.objects.notable.NoteManager; -import com.denizenscript.denizencore.tags.Attribute; -import com.denizenscript.denizencore.tags.ObjectTagProcessor; -import com.denizenscript.denizencore.tags.TagContext; -import com.denizenscript.denizencore.tags.TagManager; +import com.denizenscript.denizencore.tags.*; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.SimplexNoise; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -40,6 +34,7 @@ import org.bukkit.block.banner.PatternType; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; +import org.bukkit.block.sign.Side; import org.bukkit.block.structure.Mirror; import org.bukkit.block.structure.StructureRotation; import org.bukkit.block.structure.UsageMode; @@ -52,8 +47,8 @@ import org.bukkit.material.MaterialData; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import org.bukkit.util.Vector; import org.bukkit.util.*; +import org.bukkit.util.Vector; import java.lang.ref.WeakReference; import java.util.*; @@ -1249,14 +1244,14 @@ public static void register() { // @group world // @description // Returns a list of lines on a sign. + // For MC 1.20+, this returns the contents on the front of the sign. + // To get the contents on the back, see <@link tag LocationTag.sign_back_contents>. // --> tagProcessor.registerTag(ListTag.class, "sign_contents", (attribute, object) -> { - if (object.getBlockStateForTag(attribute) instanceof Sign) { - return new ListTag(Arrays.asList(PaperAPITools.instance.getSignLines(((Sign) object.getBlockStateForTag(attribute))))); - } - else { - return null; + if (object.getBlockStateForTag(attribute) instanceof Sign sign) { + return new ListTag(PaperAPITools.instance.getSignLines(sign), true); } + return null; }); // <--[tag] @@ -4156,14 +4151,15 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk // @group world // @description // Returns whether the location is a Sign block that is glowing. + // For MC 1.20+, this returns the glowing status of the front of the sign. + // To get the glowing state of the back, see <@link tag LocationTag.sign_back_glowing>. // --> tagProcessor.registerTag(ElementTag.class, "sign_glowing", (attribute, object) -> { - BlockState state = object.getBlockStateForTag(attribute); - if (!(state instanceof Sign)) { + if (!(object.getBlockStateForTag(attribute) instanceof Sign sign)) { attribute.echoError("Location is not a valid Sign block."); return null; } - return new ElementTag(((Sign) state).isGlowingText()); + return new ElementTag(NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? sign.getSide(Side.FRONT).isGlowingText() : sign.isGlowingText()); }); // <--[tag] @@ -4173,15 +4169,16 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk // @group world // @description // Returns the name of the glow-color of the sign at the location. + // For MC 1.20+, this returns the color on the front of the sign. + // To get the color of the back, see <@link tag LocationTag.sign_back_glow_color>. // See also <@link tag LocationTag.sign_glowing> // --> tagProcessor.registerTag(ElementTag.class, "sign_glow_color", (attribute, object) -> { - BlockState state = object.getBlockStateForTag(attribute); - if (!(state instanceof Sign)) { + if (!(object.getBlockStateForTag(attribute) instanceof Sign sign)) { attribute.echoError("Location is not a valid Sign block."); return null; } - return new ElementTag(((Sign) state).getColor()); + return new ElementTag(NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? sign.getSide(Side.FRONT).getColor() : sign.getColor()); }); // <--[tag] @@ -4568,6 +4565,131 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk } crafter.update(); }); + + // <--[tag] + // @attribute + // @returns ListTag + // @mechanism LocationTag.sign_back_contents + // @group world + // @description + // Returns the contents on the back of a sign block. + // For the contents on the front, see <@link tag LocationTag.sign_contents>. + // --> + tagProcessor.registerTag(ListTag.class, "sign_back_contents", (attribute, object) -> { + if (object.getBlockStateForTag(attribute) instanceof Sign sign) { + return new ListTag(PaperAPITools.instance.getBackSignLines(sign), true); + } + return null; + }); + + // <--[mechanism] + // @object LocationTag + // @name sign_back_contents + // @input ListTag + // @description + // Sets the contents on the back of a sign block. + // To set the contents of the front, see <@link mechanism LocationTag.sign_contents>. + // @tags + // + // --> + tagProcessor.registerMechanism("sign_back_contents", false, ListTag.class, (object, mechanism, input) -> { + if (!(object.getBlockState() instanceof Sign sign)) { + mechanism.echoError("This mechanism is only valid for Sign blocks."); + return; + } + for (int i = 0; i < 4; i++) { + PaperAPITools.instance.setBackSignLine(sign, i, ""); + } + CoreUtilities.fixNewLinesToListSeparation(input); + if (input.size() > 4) { + mechanism.echoError("Sign can only hold four lines!"); + } + else { + for (int i = 0; i < input.size(); i++) { + PaperAPITools.instance.setBackSignLine(sign, i, input.get(i)); + } + } + sign.update(); + }); + + // <--[tag] + // @attribute + // @returns ElementTag(Boolean) + // @mechanism LocationTag.sign_back_glowing + // @group world + // @description + // Returns whether the back of a Sign block at this location is glowing. + // To get the glowing state of the front, see <@link tag LocationTag.sign_glowing>. + // --> + tagProcessor.registerTag(ElementTag.class, "sign_back_glowing", (attribute, object) -> { + if (!(object.getBlockStateForTag(attribute) instanceof Sign sign)) { + attribute.echoError("Location is not a valid Sign block."); + return null; + } + return new ElementTag(sign.getSide(Side.BACK).isGlowingText()); + }); + + // <--[mechanism] + // @object LocationTag + // @name sign_back_glowing + // @input ElementTag(Boolean) + // @description + // Changes whether the back of the sign at the location is glowing. + // To set the glowing state of the front, see <@link mechanism LocationTag.sign_glowing>. + // @tags + // + // + // --> + tagProcessor.registerMechanism("sign_back_glowing", false, ElementTag.class, (object, mechanism, input) -> { + if (!(object.getBlockState() instanceof Sign sign)) { + mechanism.echoError("This mechanism can only be called on Sign blocks."); + } + else if (mechanism.requireBoolean()) { + sign.getSide(Side.BACK).setGlowingText(input.asBoolean()); + sign.update(); + } + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @mechanism LocationTag.sign_back_glow_color + // @group world + // @description + // Returns the name of the glow-color on the back of the sign at the location. + // To get the color of the front, see <@link tag LocationTag.sign_glow_color>. + // See also <@link tag LocationTag.sign_back_glowing>. + // --> + tagProcessor.registerTag(ElementTag.class, "sign_back_glow_color", (attribute, object) -> { + if (!(object.getBlockStateForTag(attribute) instanceof Sign sign)) { + attribute.echoError("Location is not a valid Sign block."); + return null; + } + return new ElementTag(sign.getSide(Side.BACK).getColor()); + }); + + // <--[mechanism] + // @object LocationTag + // @name sign_back_glow_color + // @input ElementTag + // @description + // Changes the glow color on the back of a sign. + // For the list of possible colors, see <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/DyeColor.html>. + // If a sign is not glowing, this is equivalent to applying a chat color to the sign. + // Use <@link mechanism LocationTag.sign_glowing> to toggle whether the front of the sign is glowing. + // @tags + // + // + // --> + tagProcessor.registerMechanism("sign_back_glow_color", false, ElementTag.class, (object, mechanism, input) -> { + if (!(object.getBlockState() instanceof Sign sign)) { + mechanism.echoError("This mechanism can only be called on Sign blocks."); + } + else if (mechanism.requireEnum(DyeColor.class)) { + sign.getSide(Side.BACK).setColor(input.asEnum(DyeColor.class)); + sign.update(); + } + }); } // <--[mechanism] @@ -4635,6 +4757,98 @@ else if (mechanism.requireObject(EntityTag.class)) { mechanism.echoError("The 'LocationTag.page' mechanism can only be called on a lectern block."); } }); + + // <--[mechanism] + // @object LocationTag + // @name sign_contents + // @input ListTag + // @description + // Sets the contents of a sign block. + // For MC 1.20+, this sets the contents on the front of the sign. + // To set the contents of the back, see <@link mechanism LocationTag.sign_back_contents>. + // @tags + // + // --> + tagProcessor.registerMechanism("sign_contents", false, ListTag.class, (object, mechanism, value) -> { + if (!(object.getBlockState() instanceof Sign sign)) { + mechanism.echoError("This mechanism is only valid for Sign blocks."); + return; + } + for (int i = 0; i < 4; i++) { + PaperAPITools.instance.setSignLine(sign, i, ""); + } + CoreUtilities.fixNewLinesToListSeparation(value); + if (value.size() > 4) { + mechanism.echoError("Sign can only hold four lines!"); + } + else { + for (int i = 0; i < value.size(); i++) { + PaperAPITools.instance.setSignLine(sign, i, value.get(i)); + } + } + sign.update(); + }); + + // <--[mechanism] + // @object LocationTag + // @name sign_glowing + // @input ElementTag(Boolean) + // @description + // Changes whether the sign at the location is glowing. + // For MC 1.20+, this sets the glowing status on the front of the sign. + // To set the glowing status of the back, see <@link mechanism LocationTag.sign_back_glowing>. + // @tags + // + // + // --> + tagProcessor.registerMechanism("sign_glowing", false, ElementTag.class, (object, mechanism, input) -> { + if (!mechanism.requireBoolean()) { + return; + } + if (!(object.getBlockState() instanceof Sign sign)) { + mechanism.echoError("This mechanism can only be called on Sign blocks."); + return; + } + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + sign.getSide(Side.FRONT).setGlowingText(input.asBoolean()); + } + else { + sign.setGlowingText(input.asBoolean()); + } + sign.update(); + }); + + // <--[mechanism] + // @object LocationTag + // @name sign_glow_color + // @input ElementTag + // @description + // Changes the glow color of a sign. + // For the list of possible colors, see <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/DyeColor.html>. + // If a sign is not glowing, this is equivalent to applying a chat color to the sign. + // Use <@link mechanism LocationTag.sign_glowing> to toggle whether the sign is glowing. + // For MC 1.20+, this sets the color on the front of the sign. + // To set the color of the back, see <@link mechanism LocationTag.sign_back_glow_color>. + // @tags + // + // + // --> + tagProcessor.registerMechanism("sign_glow_color", false, ElementTag.class, (object, mechanism, input) -> { + if (!mechanism.requireEnum(DyeColor.class)) { + return; + } + if (!(object.getBlockState() instanceof Sign sign)) { + mechanism.echoError("This mechanism can only be called on Sign blocks."); + return; + } + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + sign.getSide(Side.FRONT).setColor(input.asEnum(DyeColor.class)); + } + else { + sign.setColor(input.asEnum(DyeColor.class)); + } + sign.update(); + }); } public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); @@ -4830,33 +5044,6 @@ public void adjust(Mechanism mechanism) { state.update(); } - // <--[mechanism] - // @object LocationTag - // @name sign_contents - // @input ListTag - // @description - // Sets the contents of a sign block. - // @tags - // - // --> - if (mechanism.matches("sign_contents") && getBlockState() instanceof Sign) { - Sign state = (Sign) getBlockState(); - for (int i = 0; i < 4; i++) { - PaperAPITools.instance.setSignLine(state, i, ""); - } - ListTag list = mechanism.valueAsType(ListTag.class); - CoreUtilities.fixNewLinesToListSeparation(list); - if (list.size() > 4) { - mechanism.echoError("Sign can only hold four lines!"); - } - else { - for (int i = 0; i < list.size(); i++) { - PaperAPITools.instance.setSignLine(state, i, list.get(i)); - } - } - state.update(); - } - // <--[mechanism] // @object LocationTag // @name skull_skin @@ -5503,53 +5690,6 @@ else if (state instanceof Dropper) { } } - // <--[mechanism] - // @object LocationTag - // @name sign_glowing - // @input ElementTag(Boolean) - // @description - // Changes whether the sign at the location is glowing. - // @tags - // - // - // --> - if (mechanism.matches("sign_glowing") && mechanism.requireBoolean()) { - BlockState state = getBlockState(); - if (!(state instanceof Sign)) { - mechanism.echoError("'sign_glowing' mechanism can only be called on Sign blocks."); - } - else { - Sign sign = (Sign) state; - sign.setGlowingText(mechanism.getValue().asBoolean()); - sign.update(); - } - } - - // <--[mechanism] - // @object LocationTag - // @name sign_glow_color - // @input ElementTag - // @description - // Changes the glow color of a sign. - // For the list of possible colors, see <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/DyeColor.html>. - // If a sign is not glowing, this is equivalent to applying a chat color to the sign. - // Use <@link mechanism LocationTag.sign_glowing> to toggle whether the sign is glowing. - // @tags - // - // - // --> - if (mechanism.matches("sign_glow_color") && mechanism.requireEnum(DyeColor.class)) { - BlockState state = getBlockState(); - if (!(state instanceof Sign)) { - mechanism.echoError("'sign_glow_color' mechanism can only be called on Sign blocks."); - } - else { - Sign sign = (Sign) state; - sign.setColor(mechanism.getValue().asEnum(DyeColor.class)); - sign.update(); - } - } - // <--[mechanism] // @object LocationTag // @name structure_block_data diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java index 8f7f2410a4..51cb2d2f88 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java @@ -263,6 +263,7 @@ public static void registerMainProperties() { PropertyParser.registerProperty(ItemScript.class, ItemTag.class); PropertyParser.registerProperty(ItemSignContents.class, ItemTag.class); // Special case handling in ItemComponentsPatch if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + PropertyParser.registerProperty(ItemSignContentsBack.class, ItemTag.class); // Special case handling in ItemComponentsPatch PropertyParser.registerProperty(ItemSignIsWaxed.class, ItemTag.class); // Special case handling in ItemComponentsPatch } registerItemProperty(ItemSkullskin.class, "profile"); diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContents.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContents.java index 9774eccaf2..2149f4d950 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContents.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContents.java @@ -1,84 +1,53 @@ package com.denizenscript.denizen.objects.properties.item; -import com.denizenscript.denizen.utilities.PaperAPITools; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.objects.core.ListTag; -import com.denizenscript.denizencore.objects.ObjectTag; -import com.denizenscript.denizencore.objects.properties.Property; -import com.denizenscript.denizencore.tags.Attribute; import com.denizenscript.denizencore.utilities.CoreUtilities; import org.bukkit.block.Sign; import org.bukkit.inventory.meta.BlockStateMeta; -import java.util.Arrays; +public class ItemSignContents extends ItemProperty { -public class ItemSignContents implements Property { - - public static boolean describes(ObjectTag item) { - return item instanceof ItemTag - && ((ItemTag) item).getItemMeta() instanceof BlockStateMeta - && ((BlockStateMeta) ((ItemTag) item).getItemMeta()).getBlockState() instanceof Sign; - } + // <--[property] + // @object ItemTag + // @name sign_contents + // @input ListTag + // @description + // Controls the contents of a sign item. + // For MC 1.20+, this is the contents on the front of the sign. + // For the back of the sign, see <@link property ItemTag.sign_back_contents>. + // --> - public static ItemSignContents getFrom(ObjectTag _item) { - if (!describes(_item)) { - return null; - } - else { - return new ItemSignContents((ItemTag) _item); - } + public static boolean describes(ItemTag item) { + return item.getItemMeta() instanceof BlockStateMeta blockStateMeta + && blockStateMeta.getBlockState() instanceof Sign; } - public static final String[] handledTags = new String[] { - "sign_contents" - }; - - public static final String[] handledMechs = new String[] { - "sign_contents" - }; - - public ListTag getSignContents() { - return new ListTag(Arrays.asList(PaperAPITools.instance.getSignLines((Sign) ((BlockStateMeta) item.getItemMeta()).getBlockState())), true); - } - - public ItemSignContents(ItemTag _item) { - item = _item; + @Override + public ListTag getPropertyValue() { + return new ListTag(PaperAPITools.instance.getSignLines((Sign) ((BlockStateMeta) getItemMeta()).getBlockState()), true); } - ItemTag item; - @Override - public ObjectTag getObjectAttribute(Attribute attribute) { - - if (attribute == null) { - return null; + public void setPropertyValue(ListTag value, Mechanism mechanism) { + BlockStateMeta bsm = as(BlockStateMeta.class); + Sign sign = (Sign) bsm.getBlockState(); + for (int i = 0; i < 4; i++) { + PaperAPITools.instance.setSignLine(sign, i, ""); } - - // <--[tag] - // @attribute - // @returns ListTag - // @mechanism ItemTag.sign_contents - // @group properties - // @description - // Returns a list of lines on a sign item. - // --> - if (attribute.startsWith("sign_contents")) { - return getSignContents().getObjectAttribute(attribute.fulfill(1)); + CoreUtilities.fixNewLinesToListSeparation(value); + if (value.size() > 4) { + mechanism.echoError("Sign can only hold four lines!"); } - - return null; - } - - @Override - public String getPropertyString() { - for (String line : getSignContents()) { - if (line.length() > 0) { - return getSignContents().identify(); + else { + for (int i = 0; i < value.size(); i++) { + PaperAPITools.instance.setSignLine(sign, i, value.get(i)); } } - return null; + bsm.setBlockState(sign); + setItemMeta(bsm); } @Override @@ -86,36 +55,7 @@ public String getPropertyId() { return "sign_contents"; } - @Override - public void adjust(Mechanism mechanism) { - - // <--[mechanism] - // @object ItemTag - // @name sign_contents - // @input ListTag - // @description - // Sets the contents of a sign item. - // @tags - // - // --> - if (mechanism.matches("sign_contents")) { - BlockStateMeta bsm = ((BlockStateMeta) item.getItemMeta()); - Sign sign = (Sign) bsm.getBlockState(); - for (int i = 0; i < 4; i++) { - PaperAPITools.instance.setSignLine(sign, i, ""); - } - ListTag list = mechanism.valueAsType(ListTag.class); - CoreUtilities.fixNewLinesToListSeparation(list); - if (list.size() > 4) { - Debug.echoError("Sign can only hold four lines!"); - } - else { - for (int i = 0; i < list.size(); i++) { - PaperAPITools.instance.setSignLine(sign, i, list.get(i)); - } - } - bsm.setBlockState(sign); - item.setItemMeta(bsm); - } + public static void register() { + autoRegister("sign_contents", ItemSignContents.class, ListTag.class, false); } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContentsBack.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContentsBack.java new file mode 100644 index 0000000000..a33d2ed8b3 --- /dev/null +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContentsBack.java @@ -0,0 +1,60 @@ +package com.denizenscript.denizen.objects.properties.item; + +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizen.utilities.PaperAPITools; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.core.ListTag; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import org.bukkit.block.Sign; +import org.bukkit.inventory.meta.BlockStateMeta; + +public class ItemSignContentsBack extends ItemProperty { + + // <--[property] + // @object ItemTag + // @name sign_back_contents + // @input ListTag + // @description + // Controls the contents on the back of a sign item. + // For the front of the sign, see <@link property ItemTag.sign_contents>. + // --> + + public static boolean describes(ItemTag item) { + return item.getItemMeta() instanceof BlockStateMeta blockStateMeta + && blockStateMeta.getBlockState() instanceof Sign; + } + + @Override + public ListTag getPropertyValue() { + return new ListTag(PaperAPITools.instance.getBackSignLines((Sign) ((BlockStateMeta) getItemMeta()).getBlockState()), true); + } + + @Override + public void setPropertyValue(ListTag value, Mechanism mechanism) { + BlockStateMeta bsm = as(BlockStateMeta.class); + Sign sign = (Sign) bsm.getBlockState(); + for (int i = 0; i < 4; i++) { + PaperAPITools.instance.setBackSignLine(sign, i, ""); + } + CoreUtilities.fixNewLinesToListSeparation(value); + if (value.size() > 4) { + mechanism.echoError("Sign can only hold four lines!"); + } + else { + for (int i = 0; i < value.size(); i++) { + PaperAPITools.instance.setBackSignLine(sign, i, value.get(i)); + } + } + bsm.setBlockState(sign); + setItemMeta(bsm); + } + + @Override + public String getPropertyId() { + return "sign_back_contents"; + } + + public static void register() { + autoRegister("sign_back_contents", ItemSignContentsBack.class, ListTag.class, false); + } +} diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/CopyBlockCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/CopyBlockCommand.java index 05e42edccb..dfe9ed1e41 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/CopyBlockCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/CopyBlockCommand.java @@ -1,17 +1,20 @@ package com.denizenscript.denizen.scripts.commands.world; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; +import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.blocks.FullBlockData; -import com.denizenscript.denizencore.utilities.debugging.Debug; -import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; import com.denizenscript.denizencore.objects.Argument; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.commands.AbstractCommand; +import com.denizenscript.denizencore.utilities.debugging.Debug; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.*; +import org.bukkit.block.sign.Side; import org.bukkit.inventory.InventoryHolder; import java.util.ArrayList; @@ -110,6 +113,12 @@ else if (sourceState instanceof Sign) { for (String line : ((Sign) sourceState).getLines()) { PaperAPITools.instance.setSignLine(((Sign) updateState), n++, line); } + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + n = 0; + for (String line : ((Sign) sourceState).getSide(Side.BACK).getLines()) { + PaperAPITools.instance.setBackSignLine(((Sign) updateState), n++, line); + } + } } else if (sourceState instanceof Skull) { ((Skull) updateState).setSkullType(((Skull) sourceState).getSkullType()); diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java index 6f6877e768..2fece1095b 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java @@ -12,6 +12,7 @@ import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.*; import org.bukkit.block.Sign; +import org.bukkit.block.sign.Side; import org.bukkit.command.CommandSender; import org.bukkit.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent; @@ -25,8 +26,7 @@ import java.lang.invoke.MethodHandle; import java.net.URI; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.function.Predicate; public class PaperAPITools { @@ -84,12 +84,29 @@ public String getPlayerListName(Player player) { return player.getPlayerListName(); } - public String[] getSignLines(Sign sign) { - return sign.getLines(); + public List getSignLines(Sign sign) { + List lines = new ArrayList<>(4); + lines.addAll(Arrays.asList(NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? sign.getSide(Side.FRONT).getLines() : sign.getLines())); + return lines; + } + + public List getBackSignLines(Sign sign) { + List lines = new ArrayList<>(4); + lines.addAll(Arrays.asList(sign.getSide(Side.BACK).getLines())); + return lines; } public void setSignLine(Sign sign, int line, String text) { - sign.setLine(line, text == null ? "" : text); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + sign.getSide(Side.FRONT).setLine(line, text == null ? "" : text); + } + else { + sign.setLine(line, text == null ? "" : text); + } + } + + public void setBackSignLine(Sign sign, int line, String text) { + sign.getSide(Side.BACK).setLine(line, text == null ? "" : text); } public void sendResourcePack(Player player, String url, String hash, boolean forced, String prompt) { @@ -237,7 +254,7 @@ public void setMaterialTags(Material type, Set tags) { public void addLink(ServerLinks links, String display, URI uri) { links.addLink(display, uri); } - + public double[] getRecentTps() { return NMSHandler.instance.getRecentTps(); } From f468a513436b9d1b3c67cf6ce64e9dd682c1c590 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 9 Jul 2026 10:20:50 +0100 Subject: [PATCH 111/169] Minor fixups to sign PR --- .../denizen/paper/PaperModule.java | 6 ++-- .../paper/utilities/PaperAPIToolsImpl.java | 9 +++--- .../denizen/objects/LocationTag.java | 32 ++++++++++++------- .../objects/properties/PropertyRegistry.java | 2 +- ...ntsBack.java => ItemSignBackContents.java} | 28 ++++++++++------ .../properties/item/ItemSignContents.java | 20 +++++++++--- .../commands/world/CopyBlockCommand.java | 6 ++-- .../scripts/commands/world/SignCommand.java | 8 +++-- .../denizen/utilities/PaperAPITools.java | 19 ++++++----- 9 files changed, 80 insertions(+), 50 deletions(-) rename plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/{ItemSignContentsBack.java => ItemSignBackContents.java} (65%) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index 3775fc1409..14cce970a0 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -179,11 +179,11 @@ public static String stringifyComponent(Component component) { } public static List stringifyComponentList(List components) { - List values = new ArrayList<>(components.size()); + List result = new ArrayList<>(components.size()); for (Component component : components) { - values.add(stringifyComponent(component)); + result.add(stringifyComponent(component)); } - return values; + return result; } public static Component jsonToComponent(String json) { diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java index 71975bf001..2b648d75a1 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java @@ -6,6 +6,7 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.paper.PaperModule; import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; +import com.denizenscript.denizen.scripts.commands.world.SignCommand; import com.denizenscript.denizen.scripts.containers.core.ItemScriptContainer; import com.denizenscript.denizen.scripts.containers.core.ItemScriptHelper; import com.denizenscript.denizen.utilities.FormattedTextHelper; @@ -103,17 +104,17 @@ public String getPlayerListName(Player player) { @Override public List getSignLines(Sign sign) { - return PaperModule.stringifyComponentList(NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? sign.getSide(Side.FRONT).lines() : sign.lines()); + return PaperModule.stringifyComponentList(SignCommand.SIGN_SIDES_SUPPORTED ? sign.getSide(Side.FRONT).lines() : sign.lines()); } @Override - public List getBackSignLines(Sign sign) { + public List getSignBackLines(Sign sign) { return PaperModule.stringifyComponentList(sign.getSide(Side.BACK).lines()); } @Override public void setSignLine(Sign sign, int line, String text) { - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + if (SignCommand.SIGN_SIDES_SUPPORTED) { sign.getSide(Side.FRONT).line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK)); } else { @@ -122,7 +123,7 @@ public void setSignLine(Sign sign, int line, String text) { } @Override - public void setBackSignLine(Sign sign, int line, String text) { + public void setSignBackLine(Sign sign, int line, String text) { sign.getSide(Side.BACK).line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK)); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java index 23f02ca817..eff8b59faf 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java @@ -7,7 +7,11 @@ import com.denizenscript.denizen.nms.interfaces.EntityHelper; import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.objects.properties.bukkit.BukkitColorExtensions; -import com.denizenscript.denizen.objects.properties.material.*; +import com.denizenscript.denizen.objects.properties.material.MaterialAttachmentFace; +import com.denizenscript.denizen.objects.properties.material.MaterialDirectional; +import com.denizenscript.denizen.objects.properties.material.MaterialDistance; +import com.denizenscript.denizen.objects.properties.material.MaterialHalf; +import com.denizenscript.denizen.scripts.commands.world.SignCommand; import com.denizenscript.denizen.scripts.commands.world.SwitchCommand; import com.denizenscript.denizen.utilities.*; import com.denizenscript.denizen.utilities.blocks.SpawnableHelper; @@ -22,7 +26,10 @@ import com.denizenscript.denizencore.objects.notable.Notable; import com.denizenscript.denizencore.objects.notable.Note; import com.denizenscript.denizencore.objects.notable.NoteManager; -import com.denizenscript.denizencore.tags.*; +import com.denizenscript.denizencore.tags.Attribute; +import com.denizenscript.denizencore.tags.ObjectTagProcessor; +import com.denizenscript.denizencore.tags.TagContext; +import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.SimplexNoise; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -4159,7 +4166,7 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk attribute.echoError("Location is not a valid Sign block."); return null; } - return new ElementTag(NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? sign.getSide(Side.FRONT).isGlowingText() : sign.isGlowingText()); + return new ElementTag(SignCommand.SIGN_SIDES_SUPPORTED ? sign.getSide(Side.FRONT).isGlowingText() : sign.isGlowingText()); }); // <--[tag] @@ -4168,7 +4175,7 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk // @mechanism LocationTag.sign_glow_color // @group world // @description - // Returns the name of the glow-color of the sign at the location. + // Returns the name of the glow color of the sign at the location. // For MC 1.20+, this returns the color on the front of the sign. // To get the color of the back, see <@link tag LocationTag.sign_back_glow_color>. // See also <@link tag LocationTag.sign_glowing> @@ -4178,7 +4185,7 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk attribute.echoError("Location is not a valid Sign block."); return null; } - return new ElementTag(NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? sign.getSide(Side.FRONT).getColor() : sign.getColor()); + return new ElementTag(SignCommand.SIGN_SIDES_SUPPORTED ? sign.getSide(Side.FRONT).getColor() : sign.getColor()); }); // <--[tag] @@ -4577,7 +4584,7 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk // --> tagProcessor.registerTag(ListTag.class, "sign_back_contents", (attribute, object) -> { if (object.getBlockStateForTag(attribute) instanceof Sign sign) { - return new ListTag(PaperAPITools.instance.getBackSignLines(sign), true); + return new ListTag(PaperAPITools.instance.getSignBackLines(sign), true); } return null; }); @@ -4598,7 +4605,7 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk return; } for (int i = 0; i < 4; i++) { - PaperAPITools.instance.setBackSignLine(sign, i, ""); + PaperAPITools.instance.setSignBackLine(sign, i, ""); } CoreUtilities.fixNewLinesToListSeparation(input); if (input.size() > 4) { @@ -4606,7 +4613,7 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk } else { for (int i = 0; i < input.size(); i++) { - PaperAPITools.instance.setBackSignLine(sign, i, input.get(i)); + PaperAPITools.instance.setSignBackLine(sign, i, input.get(i)); } } sign.update(); @@ -4656,7 +4663,7 @@ else if (mechanism.requireBoolean()) { // @mechanism LocationTag.sign_back_glow_color // @group world // @description - // Returns the name of the glow-color on the back of the sign at the location. + // Returns the name of the glow color on the back of the sign at the location. // To get the color of the front, see <@link tag LocationTag.sign_glow_color>. // See also <@link tag LocationTag.sign_back_glowing>. // --> @@ -4675,8 +4682,9 @@ else if (mechanism.requireBoolean()) { // @description // Changes the glow color on the back of a sign. // For the list of possible colors, see <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/DyeColor.html>. + // Use <@link mechanism LocationTag.sign_back_glowing> to toggle whether the sign is glowing. // If a sign is not glowing, this is equivalent to applying a chat color to the sign. - // Use <@link mechanism LocationTag.sign_glowing> to toggle whether the front of the sign is glowing. + // To set the color of the front, see <@link mechanism LocationTag.sign_glow_color>. // @tags // // @@ -4809,7 +4817,7 @@ else if (mechanism.requireObject(EntityTag.class)) { mechanism.echoError("This mechanism can only be called on Sign blocks."); return; } - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + if (SignCommand.SIGN_SIDES_SUPPORTED) { sign.getSide(Side.FRONT).setGlowingText(input.asBoolean()); } else { @@ -4841,7 +4849,7 @@ else if (mechanism.requireObject(EntityTag.class)) { mechanism.echoError("This mechanism can only be called on Sign blocks."); return; } - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + if (SignCommand.SIGN_SIDES_SUPPORTED) { sign.getSide(Side.FRONT).setColor(input.asEnum(DyeColor.class)); } else { diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java index 51cb2d2f88..b4339b1773 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/PropertyRegistry.java @@ -263,7 +263,7 @@ public static void registerMainProperties() { PropertyParser.registerProperty(ItemScript.class, ItemTag.class); PropertyParser.registerProperty(ItemSignContents.class, ItemTag.class); // Special case handling in ItemComponentsPatch if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { - PropertyParser.registerProperty(ItemSignContentsBack.class, ItemTag.class); // Special case handling in ItemComponentsPatch + PropertyParser.registerProperty(ItemSignBackContents.class, ItemTag.class); // Special case handling in ItemComponentsPatch PropertyParser.registerProperty(ItemSignIsWaxed.class, ItemTag.class); // Special case handling in ItemComponentsPatch } registerItemProperty(ItemSkullskin.class, "profile"); diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContentsBack.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignBackContents.java similarity index 65% rename from plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContentsBack.java rename to plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignBackContents.java index a33d2ed8b3..3371e133b0 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContentsBack.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignBackContents.java @@ -8,7 +8,7 @@ import org.bukkit.block.Sign; import org.bukkit.inventory.meta.BlockStateMeta; -public class ItemSignContentsBack extends ItemProperty { +public class ItemSignBackContents extends ItemProperty { // <--[property] // @object ItemTag @@ -26,15 +26,25 @@ public static boolean describes(ItemTag item) { @Override public ListTag getPropertyValue() { - return new ListTag(PaperAPITools.instance.getBackSignLines((Sign) ((BlockStateMeta) getItemMeta()).getBlockState()), true); + return new ListTag(PaperAPITools.instance.getSignBackLines((Sign) as(BlockStateMeta.class).getBlockState()), true); + } + + @Override + public boolean isDefaultValue(ListTag value) { + for (String line : value) { + if (!line.isEmpty()) { + return false; + } + } + return true; } @Override public void setPropertyValue(ListTag value, Mechanism mechanism) { - BlockStateMeta bsm = as(BlockStateMeta.class); - Sign sign = (Sign) bsm.getBlockState(); + BlockStateMeta blockStateMeta = as(BlockStateMeta.class); + Sign sign = (Sign) blockStateMeta.getBlockState(); for (int i = 0; i < 4; i++) { - PaperAPITools.instance.setBackSignLine(sign, i, ""); + PaperAPITools.instance.setSignBackLine(sign, i, ""); } CoreUtilities.fixNewLinesToListSeparation(value); if (value.size() > 4) { @@ -42,11 +52,11 @@ public void setPropertyValue(ListTag value, Mechanism mechanism) { } else { for (int i = 0; i < value.size(); i++) { - PaperAPITools.instance.setBackSignLine(sign, i, value.get(i)); + PaperAPITools.instance.setSignBackLine(sign, i, value.get(i)); } } - bsm.setBlockState(sign); - setItemMeta(bsm); + blockStateMeta.setBlockState(sign); + setItemMeta(blockStateMeta); } @Override @@ -55,6 +65,6 @@ public String getPropertyId() { } public static void register() { - autoRegister("sign_back_contents", ItemSignContentsBack.class, ListTag.class, false); + autoRegister("sign_back_contents", ItemSignBackContents.class, ListTag.class, false); } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContents.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContents.java index 2149f4d950..c307452885 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContents.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemSignContents.java @@ -27,13 +27,23 @@ public static boolean describes(ItemTag item) { @Override public ListTag getPropertyValue() { - return new ListTag(PaperAPITools.instance.getSignLines((Sign) ((BlockStateMeta) getItemMeta()).getBlockState()), true); + return new ListTag(PaperAPITools.instance.getSignLines((Sign) as(BlockStateMeta.class).getBlockState()), true); + } + + @Override + public boolean isDefaultValue(ListTag value) { + for (String line : value) { + if (!line.isEmpty()) { + return false; + } + } + return true; } @Override public void setPropertyValue(ListTag value, Mechanism mechanism) { - BlockStateMeta bsm = as(BlockStateMeta.class); - Sign sign = (Sign) bsm.getBlockState(); + BlockStateMeta blockStateMeta = as(BlockStateMeta.class); + Sign sign = (Sign) blockStateMeta.getBlockState(); for (int i = 0; i < 4; i++) { PaperAPITools.instance.setSignLine(sign, i, ""); } @@ -46,8 +56,8 @@ public void setPropertyValue(ListTag value, Mechanism mechanism) { PaperAPITools.instance.setSignLine(sign, i, value.get(i)); } } - bsm.setBlockState(sign); - setItemMeta(bsm); + blockStateMeta.setBlockState(sign); + setItemMeta(blockStateMeta); } @Override diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/CopyBlockCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/CopyBlockCommand.java index dfe9ed1e41..b0f939b657 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/CopyBlockCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/CopyBlockCommand.java @@ -1,7 +1,5 @@ package com.denizenscript.denizen.scripts.commands.world; -import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.blocks.FullBlockData; @@ -113,10 +111,10 @@ else if (sourceState instanceof Sign) { for (String line : ((Sign) sourceState).getLines()) { PaperAPITools.instance.setSignLine(((Sign) updateState), n++, line); } - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + if (SignCommand.SIGN_SIDES_SUPPORTED) { n = 0; for (String line : ((Sign) sourceState).getSide(Side.BACK).getLines()) { - PaperAPITools.instance.setBackSignLine(((Sign) updateState), n++, line); + PaperAPITools.instance.setSignBackLine(((Sign) updateState), n++, line); } } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/SignCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/SignCommand.java index 5623bdc060..2904ef64ce 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/SignCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/world/SignCommand.java @@ -1,16 +1,18 @@ package com.denizenscript.denizen.scripts.commands.world; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; +import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.objects.properties.material.MaterialDirectional; import com.denizenscript.denizen.utilities.Utilities; -import com.denizenscript.denizencore.utilities.debugging.Debug; -import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; import com.denizenscript.denizencore.objects.Argument; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.commands.AbstractCommand; +import com.denizenscript.denizencore.utilities.debugging.Debug; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -19,6 +21,8 @@ public class SignCommand extends AbstractCommand { + public static final boolean SIGN_SIDES_SUPPORTED = NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20); + public SignCommand() { setName("sign"); setSyntax("sign (type:{automatic}/sign_post/wall_sign) (material:) [|...] [] (direction:north/east/south/west)"); diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java index 2fece1095b..1c516f02cd 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java @@ -3,6 +3,7 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; +import com.denizenscript.denizen.scripts.commands.world.SignCommand; import com.denizenscript.denizen.scripts.containers.core.ItemScriptContainer; import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; import com.denizenscript.denizencore.objects.Mechanism; @@ -26,7 +27,9 @@ import java.lang.invoke.MethodHandle; import java.net.URI; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Set; import java.util.function.Predicate; public class PaperAPITools { @@ -85,19 +88,15 @@ public String getPlayerListName(Player player) { } public List getSignLines(Sign sign) { - List lines = new ArrayList<>(4); - lines.addAll(Arrays.asList(NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? sign.getSide(Side.FRONT).getLines() : sign.getLines())); - return lines; + return Arrays.asList(SignCommand.SIGN_SIDES_SUPPORTED ? sign.getSide(Side.FRONT).getLines() : sign.getLines()); } - public List getBackSignLines(Sign sign) { - List lines = new ArrayList<>(4); - lines.addAll(Arrays.asList(sign.getSide(Side.BACK).getLines())); - return lines; + public List getSignBackLines(Sign sign) { + return Arrays.asList(sign.getSide(Side.BACK).getLines()); } public void setSignLine(Sign sign, int line, String text) { - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + if (SignCommand.SIGN_SIDES_SUPPORTED) { sign.getSide(Side.FRONT).setLine(line, text == null ? "" : text); } else { @@ -105,7 +104,7 @@ public void setSignLine(Sign sign, int line, String text) { } } - public void setBackSignLine(Sign sign, int line, String text) { + public void setSignBackLine(Sign sign, int line, String text) { sign.getSide(Side.BACK).setLine(line, text == null ? "" : text); } From bcc2c7e3f0808b51b044fe915d3fcaf2b448715e Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:38:00 +0200 Subject: [PATCH 112/169] `map` command: fix default radius value (#2829) --- .../denizenscript/denizen/scripts/commands/item/MapCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/item/MapCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/item/MapCommand.java index aec090b8ce..bf48201523 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/item/MapCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/item/MapCommand.java @@ -98,7 +98,7 @@ public static void autoExecute(ScriptEntry scriptEntry, @ArgName("resize") boolean resize, @ArgName("script") @ArgPrefixed @ArgDefaultNull ScriptTag script, @ArgName("dot") @ArgPrefixed @ArgDefaultNull ColorTag dot, - @ArgName("radius") @ArgPrefixed @ArgDefaultText("-1") int radius, + @ArgName("radius") @ArgPrefixed @ArgDefaultText("1") int radius, @ArgName("x") @ArgPrefixed @ArgDefaultText("0") double x, @ArgName("y") @ArgPrefixed @ArgDefaultText("0") double y, @ArgName("width") @ArgPrefixed @ArgDefaultText("-1") int width, From ca30c91e4c951a9b65e6d9d1d45daeed81cc607c Mon Sep 17 00:00:00 2001 From: MCSamuel <187220916+MC-Samuel@users.noreply.github.com> Date: Thu, 9 Jul 2026 02:46:37 -0700 Subject: [PATCH 113/169] `entity forms block` event: fix material context (#2822) * Added context.new_material and rephrased context.material * minor changes --- .../events/entity/EntityFormsBlockScriptEvent.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityFormsBlockScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityFormsBlockScriptEvent.java index 95d02da061..c282dbf1b1 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityFormsBlockScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/entity/EntityFormsBlockScriptEvent.java @@ -1,10 +1,10 @@ package com.denizenscript.denizen.events.entity; +import com.denizenscript.denizen.events.BukkitScriptEvent; import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; -import com.denizenscript.denizen.events.BukkitScriptEvent; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; import org.bukkit.event.EventHandler; @@ -27,8 +27,8 @@ public class EntityFormsBlockScriptEvent extends BukkitScriptEvent implements Li // For example, when a snowman forms snow. // // @Context - // returns the LocationTag the block. - // returns the MaterialTag of the block. + // returns the LocationTag of the block. + // returns the MaterialTag of what the block will become. // returns the EntityTag that formed the block. // // --> @@ -74,7 +74,7 @@ public ObjectTag getContext(String name) { @EventHandler public void onEntityFormsBlock(EntityBlockFormEvent event) { location = new LocationTag(event.getBlock().getLocation()); - material = new MaterialTag(event.getBlock()); + material = new MaterialTag(event.getNewState()); entity = new EntityTag(event.getEntity()); this.event = event; fire(event); From d9b897cb32d8f6eea17e4093407a5f4fce1aeac8 Mon Sep 17 00:00:00 2001 From: MCSamuel <187220916+MC-Samuel@users.noreply.github.com> Date: Sat, 18 Jul 2026 01:05:36 -0700 Subject: [PATCH 114/169] `player raises|lowers `: spear support (#2825) * adds "spears" to the list of acceptable raisableItems * moved spears to a separate area * import changes * slight meta change (thanks behr) --- .../events/AnvilBlockDamagedScriptEvent.java | 2 +- .../PlayerRaiseLowerItemScriptEvent.java | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/AnvilBlockDamagedScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/AnvilBlockDamagedScriptEvent.java index effc8f9e27..5f4268d66b 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/AnvilBlockDamagedScriptEvent.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/AnvilBlockDamagedScriptEvent.java @@ -36,7 +36,7 @@ public class AnvilBlockDamagedScriptEvent extends BukkitScriptEvent implements L // // @Determine // "STATE:" to set the anvil's new damage state. - // "BREAK:" to set weather the anvil will break. + // "BREAK:" to set whether the anvil will break. // --> public AnvilBlockDamagedScriptEvent() { diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerRaiseLowerItemScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerRaiseLowerItemScriptEvent.java index 0d17a6c1ed..c727a00188 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerRaiseLowerItemScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerRaiseLowerItemScriptEvent.java @@ -1,6 +1,8 @@ package com.denizenscript.denizen.events.player; import com.denizenscript.denizen.events.BukkitScriptEvent; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; @@ -9,19 +11,14 @@ import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.PlayerDropItemEvent; -import org.bukkit.event.player.PlayerItemHeldEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerSwapHandItemsEvent; +import org.bukkit.event.player.*; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; public class PlayerRaiseLowerItemScriptEvent extends BukkitScriptEvent implements Listener { @@ -29,7 +26,7 @@ public class PlayerRaiseLowerItemScriptEvent extends BukkitScriptEvent implement // @Events // player raises|lowers|toggles // - // @Synonyms player raises shield, player raises spyglass + // @Synonyms player raises shield, player raises spyglass, player raises spear // // @Group Player // @@ -55,6 +52,12 @@ public class PlayerRaiseLowerItemScriptEvent extends BukkitScriptEvent implement public static final EnumSet raisableItems = EnumSet.of(Material.SHIELD, Material.CROSSBOW, Material.BOW, Material.TRIDENT, Material.SPYGLASS); + static { + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { + raisableItems.addAll(Tag.ITEMS_SPEARS.getValues()); + } + } + public PlayerRaiseLowerItemScriptEvent() { registerCouldMatcher("player raises|lowers|toggles "); registerSwitches("reason"); From 17507288b7646c60c7da77a06ea7607381239a8a Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:20:36 +0100 Subject: [PATCH 115/169] `FormattedTextHelper`: stricter URL parsing (#2832) * `FormattedTextHelper`: stricter URL parsing * simplify logic * imports * minor optimization --- .../utilities/FormattedTextHelper.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java index 67392b5fa9..f253ece61c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java @@ -19,6 +19,8 @@ import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.chat.VersionedComponentSerializer; +import java.net.URI; +import java.net.URISyntaxException; import java.util.List; public class FormattedTextHelper { @@ -798,13 +800,18 @@ else if (code == 'o' || code == 'O') { started = i + 1; } else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i + 1] == 't' && chars[i + 2] == 't' && chars[i + 3] == 'p') { - String subStr = str.substring(i, i + "https://a.".length()); - if (subStr.startsWith("https://") || subStr.startsWith("http://")) { - int nextSpace = CoreUtilities.indexOfAny(str, i, ' ', '\t', '\n', ChatColor.COLOR_CHAR); - if (nextSpace == -1) { - nextSpace = str.length(); + if (str.startsWith("https://", i) || str.startsWith("http://", i)) { + int urlEnd = indexOfUrlEnd(chars, i); + if (urlEnd - i < "https://a.".length()) { + continue; + } + String url = str.substring(i, urlEnd); + try { + new URI(url); + } + catch (URISyntaxException ignored) { + continue; } - String url = str.substring(i, nextSpace); nextText.setText(nextText.getText() + str.substring(started, i)); base.addExtra(nextText); lastText = nextText; @@ -813,8 +820,8 @@ else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i TextComponent clickableText = new TextComponent(url); clickableText.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); lastText.addExtra(clickableText); - i = nextSpace - 1; - started = nextSpace; + i = urlEnd - 1; + started = urlEnd; continue; } } @@ -826,6 +833,17 @@ else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i return new BaseComponent[] { cleanBase && !optimize ? root : base }; } + public static final AsciiMatcher URL_VALID = new AsciiMatcher(AsciiMatcher.LETTERS_LOWER + AsciiMatcher.LETTERS_UPPER + AsciiMatcher.DIGITS + "-._~:/?#@!$&'()*+,;=%"); + + public static int indexOfUrlEnd(char[] chars, int start) { + for (int i = start; i < chars.length; i++) { + if (!URL_VALID.isMatch(chars[i])) { + return i; + } + } + return chars.length; + } + public static int indexOfLastColorBlockStart(String text) { int result = text.lastIndexOf(ChatColor.COLOR_CHAR + "["); if (result == -1 || text.indexOf(']', result + 2) != -1) { From a28495271162211cf4f18b38daa38ca10d10642d Mon Sep 17 00:00:00 2001 From: david <89749147+davight@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:11:49 +0200 Subject: [PATCH 116/169] `pause`/`resume` commands: update & fix (#2816) * move to its own class * cleanup and fixes * cleanups * Fix alphabetical ordering --------- Co-authored-by: Aya <31237389+tal5@users.noreply.github.com> --- .../commands/BukkitCommandRegistry.java | 2 +- .../scripts/commands/npc/PauseCommand.java | 116 +++++------------- .../scripts/commands/npc/ResumeCommand.java | 47 +++++++ 3 files changed, 79 insertions(+), 86 deletions(-) create mode 100644 plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/ResumeCommand.java diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/BukkitCommandRegistry.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/BukkitCommandRegistry.java index 63be0127f2..6e06ceaef5 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/BukkitCommandRegistry.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/BukkitCommandRegistry.java @@ -68,9 +68,9 @@ public static void registerCitizensCommands() { registerCommand(FishCommand.class); registerCommand(LookcloseCommand.class); registerCommand(PauseCommand.class); - registerCommand(PauseCommand.ResumeCommand.class); registerCommand(PoseCommand.class); registerCommand(PushableCommand.class); + registerCommand(ResumeCommand.class); registerCommand(SitCommand.class); registerCommand(SleepCommand.class); registerCommand(StandCommand.class); diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/PauseCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/PauseCommand.java index a4e8a8d0d6..682be06d73 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/PauseCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/PauseCommand.java @@ -2,12 +2,13 @@ import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException; +import com.denizenscript.denizencore.scripts.commands.generator.ArgDefaultNull; +import com.denizenscript.denizencore.scripts.commands.generator.ArgLinear; +import com.denizenscript.denizencore.scripts.commands.generator.ArgName; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizen.objects.NPCTag; -import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; -import com.denizenscript.denizencore.objects.Argument; import com.denizenscript.denizencore.objects.core.DurationTag; -import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.commands.AbstractCommand; import net.citizensnpcs.trait.waypoint.Waypoints; @@ -17,19 +18,12 @@ public class PauseCommand extends AbstractCommand { - public static class ResumeCommand extends PauseCommand { - - public ResumeCommand() { - setName("resume"); - setSyntax("resume [waypoints/activity] ()"); - } - } - public PauseCommand() { setName("pause"); setSyntax("pause [waypoints/activity] ()"); setRequiredArguments(1, 2); isProcedural = false; + autoCompile(); } // <--[command] @@ -68,101 +62,53 @@ public PauseCommand() { // - resume waypoints // --> - // <--[command] - // @Name Resume - // @Syntax resume [waypoints/activity] () - // @Required 1 - // @Plugin Citizens - // @Short Resumes an NPC's waypoint navigation or goal activity temporarily or indefinitely. - // @Group npc - // - // @Description - // The resume command resumes an NPC's waypoint navigation or goal activity temporarily or indefinitely. - // This works along side <@link command pause>. - // See the documentation of the pause command for more details. - // - // @Tags - // - // - // @Usage - // Use to pause an NPC's waypoint navigation and then resume it. - // - pause waypoints - // - resume waypoints - // --> + public static final Map durations = new HashMap<>(); - private Map durations = new HashMap<>(); + public enum Type { ACTIVITY, WAYPOINTS, NAVIGATION } - enum PauseType {ACTIVITY, WAYPOINTS, NAVIGATION} - - @Override - public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { - for (Argument arg : scriptEntry) { - if (arg.matchesArgumentType(DurationTag.class) - && !scriptEntry.hasObject("duration")) { - scriptEntry.addObject("duration", arg.asType(DurationTag.class)); - } - else if (!scriptEntry.hasObject("pause_type") - && arg.matchesEnum(PauseType.class)) { - scriptEntry.addObject("pause_type", arg.asElement()); - } - else { - arg.reportUnhandled(); - } - } - if (!scriptEntry.hasObject("pause_type")) { - throw new InvalidArgumentsException("Must specify a pause type!"); - } + public static void autoExecute(ScriptEntry scriptEntry, + @ArgName("action") Type type, + @ArgName("duration") @ArgLinear @ArgDefaultNull DurationTag duration) { + executeToggle(scriptEntry, type, duration, true); } - @Override - public void execute(ScriptEntry scriptEntry) { - DurationTag duration = scriptEntry.getObjectTag("duration"); - ElementTag pauseTypeElement = scriptEntry.getElement("pause_type"); - PauseType pauseType = PauseType.valueOf(pauseTypeElement.asString().toUpperCase()); - if (scriptEntry.dbCallShouldDebug()) { - Debug.report(scriptEntry, getName(), duration, pauseTypeElement); - } - NPCTag npc = null; - if (Utilities.getEntryNPC(scriptEntry) != null) { - npc = Utilities.getEntryNPC(scriptEntry); + public static void executeToggle(ScriptEntry scriptEntry, Type type, DurationTag duration, boolean pause) { + if (!Utilities.entryHasNPC(scriptEntry)) { + throw new InvalidArgumentsRuntimeException("Need to provide an NPC"); } - pause(npc, pauseType, !scriptEntry.getCommandName().equalsIgnoreCase("RESUME")); + NPCData data = new NPCData(Utilities.getEntryNPC(scriptEntry), type); + toggle(data, pause); if (duration != null) { - if (durations.containsKey(npc.getCitizen().getId() + pauseType.name())) { + if (durations.containsKey(data)) { try { - Denizen.getInstance().getServer().getScheduler().cancelTask(durations.get(npc.getCitizen().getId() + pauseType.name())); + Denizen.getInstance().getServer().getScheduler().cancelTask(durations.get(data)); } catch (Exception e) { Debug.echoError(scriptEntry, "There was an error pausing that!"); Debug.echoError(scriptEntry, e); } } - Debug.echoDebug(scriptEntry, "Running delayed task: Unpause " + pauseType); - final NPCTag theNpc = npc; - final ScriptEntry se = scriptEntry; - durations.put(npc.getId() + pauseType.name(), Denizen.getInstance() + durations.put(data, Denizen.getInstance() .getServer().getScheduler().scheduleSyncDelayedTask(Denizen.getInstance(), () -> { - Debug.echoDebug(se, "Running delayed task: Pausing " + pauseType); - pause(theNpc, pauseType, false); - + Debug.echoDebug(scriptEntry, "Running delayed task: " + (!pause ? "Pausing" : "Resuming") + " " + type); + toggle(data, !pause); }, duration.getTicks())); } } - public void pause(NPCTag denizen, PauseType pauseType, boolean pause) { - switch (pauseType) { - case WAYPOINTS: - denizen.getCitizen().getOrAddTrait(Waypoints.class).getCurrentProvider().setPaused(pause); + public static void toggle(NPCData data, boolean pause) { + switch (data.type) { + case WAYPOINTS -> { + data.npc.getCitizen().getOrAddTrait(Waypoints.class).getCurrentProvider().setPaused(pause); if (pause) { - denizen.getNavigator().cancelNavigation(); + data.npc.getNavigator().cancelNavigation(); } - return; - case ACTIVITY: - denizen.getCitizen().getDefaultBehaviorController().setPaused(pause); - return; - case NAVIGATION: - // TODO: Finish this + } + case ACTIVITY -> data.npc.getCitizen().getDefaultBehaviorController().setPaused(pause); + case NAVIGATION -> { /* TODO IMPLEMENT */ } } } + + public record NPCData(NPCTag npc, Type type) { } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/ResumeCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/ResumeCommand.java new file mode 100644 index 0000000000..0bc01e013e --- /dev/null +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/npc/ResumeCommand.java @@ -0,0 +1,47 @@ +package com.denizenscript.denizen.scripts.commands.npc; + +import com.denizenscript.denizencore.objects.core.DurationTag; +import com.denizenscript.denizencore.scripts.ScriptEntry; +import com.denizenscript.denizencore.scripts.commands.AbstractCommand; +import com.denizenscript.denizencore.scripts.commands.generator.ArgDefaultNull; +import com.denizenscript.denizencore.scripts.commands.generator.ArgLinear; +import com.denizenscript.denizencore.scripts.commands.generator.ArgName; + +public class ResumeCommand extends AbstractCommand { + + public ResumeCommand() { + setName("resume"); + setSyntax("resume [waypoints/activity] ()"); + setRequiredArguments(1, 2); + isProcedural = false; + autoCompile(); + } + + // <--[command] + // @Name Resume + // @Syntax resume [waypoints/activity] () + // @Required 1 + // @Plugin Citizens + // @Short Resumes an NPC's waypoint navigation or goal activity temporarily or indefinitely. + // @Group npc + // + // @Description + // The resume command resumes an NPC's waypoint navigation or goal activity temporarily or indefinitely. + // This works along side <@link command pause>. + // See the documentation of the pause command for more details. + // + // @Tags + // + // + // @Usage + // Use to pause an NPC's waypoint navigation and then resume it. + // - pause waypoints + // - resume waypoints + // --> + + public static void autoExecute(ScriptEntry scriptEntry, + @ArgName("action") PauseCommand.Type type, + @ArgName("duration") @ArgLinear @ArgDefaultNull DurationTag duration) { + PauseCommand.executeToggle(scriptEntry, type, duration, false); + } +} From 6aa77dd16e44407fe4089cf2ed27dd3591a098ae Mon Sep 17 00:00:00 2001 From: MCSamuel <187220916+MC-Samuel@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:19:38 -0700 Subject: [PATCH 117/169] `NPCTag`: modernize, `can_navigate_to` tag (#2811) * NPCTag modernization & NPCTag.can_navigate_to tag * miscellaneous changes * extra space * plain-text arguments * minor changes * minor changes * minor changes * reverted a couple changes * minor change * revert empty `set_nickname` mechanism and minor changes --- .../denizenscript/denizen/objects/NPCTag.java | 539 +++++++++--------- 1 file changed, 258 insertions(+), 281 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/NPCTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/NPCTag.java index a99fa9ec70..74e6bc5e56 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/NPCTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/NPCTag.java @@ -501,7 +501,7 @@ public static void register() { // --> tagProcessor.registerTag(ElementTag.class, "nickname", (attribute, object) -> { return new ElementTag(object.getCitizen().hasTrait(NicknameTrait.class) ? object.getCitizen().getOrAddTrait(NicknameTrait.class) - .getNickname() : object.getName()); + .getNickname() : object.getName(), true); }); // Documented in EntityTag @@ -510,16 +510,16 @@ public static void register() { BukkitImplDeprecations.npcNicknameTag.warn(attribute.context); attribute.fulfill(1); return new ElementTag(object.getCitizen().hasTrait(NicknameTrait.class) ? object.getCitizen().getOrAddTrait(NicknameTrait.class) - .getNickname() : object.getName()); + .getNickname() : object.getName(), true); } - return new ElementTag(object.getName()); + return new ElementTag(object.getName(), true); }); // <--[tag] // @attribute // @returns ListTag // @description - // Returns a list of all of the NPC's traits. + // Returns a list of all the NPC's traits. // --> tagProcessor.registerTag(ListTag.class, "traits", (attribute, object) -> { List list = new ArrayList<>(); @@ -535,14 +535,9 @@ public static void register() { // @description // Returns whether the NPC has a specified trait. // --> - tagProcessor.registerTag(ElementTag.class, "has_trait", (attribute, object) -> { - if (attribute.hasParam()) { - Class trait = CitizensAPI.getTraitFactory().getTraitClass(attribute.getParam()); - if (trait != null) { - return new ElementTag(object.getCitizen().hasTrait(trait)); - } - } - return null; + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "has_trait", (attribute, object, param) -> { + Class trait = CitizensAPI.getTraitFactory().getTraitClass(param.asString()); + return trait != null ? new ElementTag(object.getCitizen().hasTrait(trait)) : null; }); // <--[tag] @@ -561,15 +556,12 @@ public static void register() { // @description // Returns whether the NPC has a specified trigger. // --> - tagProcessor.registerTag(ElementTag.class, "has_trigger", (attribute, object) -> { - if (!attribute.hasParam()) { - return null; - } + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "has_trigger", (attribute, object, param) -> { if (!object.getCitizen().hasTrait(TriggerTrait.class)) { return new ElementTag(false); } TriggerTrait trait = object.getCitizen().getOrAddTrait(TriggerTrait.class); - return new ElementTag(trait.hasTrigger(attribute.getParam())); + return new ElementTag(trait.hasTrigger(param.asString())); }); // <--[tag] @@ -579,7 +571,7 @@ public static void register() { // Returns whether the NPC has anchors assigned. // --> tagProcessor.registerTag(ElementTag.class, "has_anchors", (attribute, object) -> { - return (new ElementTag(object.getCitizen().getOrAddTrait(Anchors.class).getAnchors().size() > 0)); + return new ElementTag(!object.getCitizen().getOrAddTrait(Anchors.class).getAnchors().isEmpty()); }); // <--[tag] @@ -589,11 +581,7 @@ public static void register() { // Returns a list of anchor names currently assigned to the NPC. // --> tagProcessor.registerTag(ListTag.class, "list_anchors", (attribute, object) -> { - ListTag list = new ListTag(); - for (Anchor anchor : object.getCitizen().getOrAddTrait(Anchors.class).getAnchors()) { - list.add(anchor.getName()); - } - return list; + return new ListTag(object.getCitizen().getOrAddTrait(Anchors.class).getAnchors(), anchor -> new ElementTag(anchor.getName(), true)); }); // <--[tag] @@ -606,22 +594,18 @@ public static void register() { Anchors trait = object.getCitizen().getOrAddTrait(Anchors.class); if (attribute.hasParam()) { Anchor anchor = trait.getAnchor(attribute.getParam()); - if (anchor != null) { - return new LocationTag(anchor.getLocation()); - } - else { - attribute.echoError("NPC Anchor '" + attribute.getParam() + "' is not defined."); - return null; - } + if (anchor != null) { + return new LocationTag(anchor.getLocation()); + } + else { + attribute.echoError("NPC Anchor '" + attribute.getParam() + "' is not defined."); + return null; + } } else if (attribute.startsWith("list", 2)) { attribute.fulfill(1); BukkitImplDeprecations.npcAnchorListTag.warn(attribute.context); - ListTag list = new ListTag(); - for (Anchor anchor : trait.getAnchors()) { - list.add(anchor.getName()); - } - return list; + return new ListTag(trait.getAnchors(), anchor -> new ElementTag(anchor.getName(), true)); } else { attribute.echoError("npc.anchor[...] tag must have an input."); @@ -635,18 +619,14 @@ else if (attribute.startsWith("list", 2)) { // @description // Returns the specified constant from the NPC. // --> - tagProcessor.registerTag(ElementTag.class, "constant", (attribute, object) -> { - if (attribute.hasParam()) { - if (object.getCitizen().hasTrait(ConstantsTrait.class) - && object.getCitizen().getOrAddTrait(ConstantsTrait.class).getConstant(attribute.getParam()) != null) { - return new ElementTag(object.getCitizen().getOrAddTrait(ConstantsTrait.class) - .getConstant(attribute.getParam())); - } - else { - return null; - } + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "constant", (attribute, object, param) -> { + if (object.getCitizen().hasTrait(ConstantsTrait.class) + && object.getCitizen().getOrAddTrait(ConstantsTrait.class).getConstant(param.asString()) != null) { + return new ElementTag(object.getCitizen().getOrAddTrait(ConstantsTrait.class).getConstant(param.asString()), true); + } + else { + return null; } - return null; }); // <--[tag] @@ -655,13 +635,8 @@ else if (attribute.startsWith("list", 2)) { // @description // Returns true if the NPC has the specified pose, otherwise returns false. // --> - tagProcessor.registerTag(ElementTag.class, "has_pose", (attribute, object) -> { - if (attribute.hasParam()) { - return new ElementTag(object.getCitizen().getOrAddTrait(Poses.class).hasPose(attribute.getParam())); - } - else { - return null; - } + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "has_pose", (attribute, object, param) -> { + return new ElementTag(object.getCitizen().getOrAddTrait(Poses.class).hasPose(param.asString())); }); // <--[tag] @@ -671,14 +646,9 @@ else if (attribute.startsWith("list", 2)) { // Returns the pose as a LocationTag with x, y, and z set to 0, and the world set to the first // possible available world Bukkit knows about. // --> - tagProcessor.registerTag(LocationTag.class, "pose", (attribute, object) -> { - if (attribute.hasParam()) { - Pose pose = object.getCitizen().getOrAddTrait(Poses.class).getPose(attribute.getParam()); - return new LocationTag(org.bukkit.Bukkit.getWorlds().get(0), 0, 0, 0, pose.getYaw(), pose.getPitch()); - } - else { - return null; - } + tagProcessor.registerTag(LocationTag.class, ElementTag.class, "pose", (attribute, object, param) -> { + Pose pose = object.getCitizen().getOrAddTrait(Poses.class).getPose(param.asString()); + return new LocationTag(Bukkit.getWorlds().get(0), 0, 0, 0, pose.getYaw(), pose.getPitch()); }, "get_pose"); // <--[tag] @@ -716,11 +686,7 @@ else if (attribute.startsWith("list", 2)) { if (stands == null || stands.isEmpty()) { return null; } - ListTag output = new ListTag(); - for (Entity stand : stands) { - output.addObject(new EntityTag(stand).getDenizenObject()); - } - return output; + return new ListTag(stands, stand -> new EntityTag(stand).getDenizenObject()); }); // <--[tag] @@ -865,7 +831,7 @@ else if (attribute.startsWith("list", 2)) { if (skin.getSignature() != null) { sign = ";" + skin.getSignature(); } - return new ElementTag(tex + sign); + return new ElementTag(tex + sign, true); } return null; }); @@ -883,7 +849,7 @@ else if (attribute.startsWith("list", 2)) { return null; } SkinTrait skin = object.getCitizen().getOrAddTrait(SkinTrait.class); - return new ElementTag(skin.getSkinName() + "|" + skin.getTexture()); + return new ElementTag(skin.getSkinName() + "|" + skin.getTexture(), true); }); // <--[tag] @@ -895,7 +861,7 @@ else if (attribute.startsWith("list", 2)) { // --> tagProcessor.registerTag(ElementTag.class, "skin", (attribute, object) -> { if (object.getCitizen().hasTrait(SkinTrait.class)) { - return new ElementTag(object.getCitizen().getOrAddTrait(SkinTrait.class).getSkinName()); + return new ElementTag(object.getCitizen().getOrAddTrait(SkinTrait.class).getSkinName(), true); } return null; }); @@ -1044,13 +1010,7 @@ else if (attribute.startsWith("list", 2)) { return null; } else { - ListTag result = new ListTag(); - for (AssignmentScriptContainer container : citizen.getOrAddTrait(AssignmentTrait.class).containerCache) { - if (container != null) { - result.addObject(new ScriptTag(container)); - } - } - return result; + return new ListTag(citizen.getOrAddTrait(AssignmentTrait.class).containerCache, Objects::nonNull, ScriptTag::new); } }); @@ -1139,7 +1099,7 @@ else if (attribute.startsWith("list", 2)) { // Not related to Sentinel combat. // --> tagProcessor.registerTag(ElementTag.class, "attack_strategy", (attribute, object) -> { - return new ElementTag(object.getNavigator().getLocalParameters().attackStrategy().toString()); + return new ElementTag(object.getNavigator().getLocalParameters().attackStrategy().toString(), true); }); // <--[tag] @@ -1224,7 +1184,7 @@ else if (attribute.startsWith("list", 2)) { if (object.getNavigator().getTargetType() == null) { return null; } - return new ElementTag(object.getNavigator().getTargetType().toString()); + return new ElementTag(object.getNavigator().getTargetType().toString(), true); }); // <--[tag] @@ -1247,7 +1207,7 @@ else if (attribute.startsWith("list", 2)) { // Returns the name of the registry this NPC came from. // --> tagProcessor.registerTag(ElementTag.class, "registry_name", (attribute, object) -> { - return new ElementTag(object.getCitizen().getOwningRegistry().getName()); + return new ElementTag(object.getCitizen().getOwningRegistry().getName(), true); }); // <--[tag] @@ -1256,15 +1216,9 @@ else if (attribute.startsWith("list", 2)) { // @description // Returns the value of a Citizens NPC metadata key. // --> - tagProcessor.registerTag(ElementTag.class, "citizens_data", (attribute, object) -> { - if (!attribute.hasParam()) { - return null; - } - Object val = object.getCitizen().data().get(attribute.getParam()); - if (val == null) { - return null; - } - return new ElementTag(val.toString()); + tagProcessor.registerTag(ElementTag.class, ElementTag.class, "citizens_data", (attribute, object, param) -> { + Object val = object.getCitizen().data().get(param.asString()); + return val != null ? new ElementTag(val.toString(), true) : null; }); // <--[tag] @@ -1343,6 +1297,16 @@ else if (attribute.startsWith("list", 2)) { return null; }); + // <--[tag] + // @attribute ]> + // @returns ElementTag(Boolean) + // @description + // Returns whether an NPC can navigate to a specified location. + // --> + tagProcessor.registerTag(ElementTag.class, LocationTag.class, "can_navigate_to", (attribute, object, param) -> { + return new ElementTag(object.getCitizen().getNavigator().canNavigateTo(param)); + }); + // <--[mechanism] // @object NPCTag // @name hologram_lines @@ -1454,29 +1418,6 @@ else if (attribute.startsWith("list", 2)) { mechanism.echoError("Must set waypoint_provider to 'wander' before setting wander_yrange!"); } }); - } - - public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); - - @Override - public ObjectTag getObjectAttribute(Attribute attribute) { - return tagProcessor.getObjectAttribute(this, attribute); - } - - @Override - public ObjectTag getNextObjectTypeDown() { - if (getEntity() != null) { - return new EntityTag(this); - } - return new ElementTag(identify()); - } - - public void applyProperty(Mechanism mechanism) { - mechanism.echoError("Cannot apply properties to an NPC!"); - } - - @Override - public void adjust(Mechanism mechanism) { // TODO: For all the mechanism tags, add the @Mechanism link! @@ -1489,11 +1430,11 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("set_assignment") && mechanism.requireObject(ScriptTag.class)) { - AssignmentTrait trait = getCitizen().getOrAddTrait(AssignmentTrait.class); + tagProcessor.registerMechanism("set_assignment", false, ScriptTag.class, (object, mechanism, input) -> { + AssignmentTrait trait = object.getCitizen().getOrAddTrait(AssignmentTrait.class); trait.clearAssignments(null); - trait.addAssignmentScript((AssignmentScriptContainer) mechanism.valueAsType(ScriptTag.class).getContainer(), null); - } + trait.addAssignmentScript((AssignmentScriptContainer) input.getContainer(), null); + }); // <--[mechanism] // @object NPCTag @@ -1504,9 +1445,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("add_assignment") && mechanism.requireObject(ScriptTag.class)) { - getCitizen().getOrAddTrait(AssignmentTrait.class).addAssignmentScript((AssignmentScriptContainer) mechanism.valueAsType(ScriptTag.class).getContainer(), null); - } + tagProcessor.registerMechanism("add_assignment", false, ScriptTag.class, (object, mechanism, input) -> { + object.getCitizen().getOrAddTrait(AssignmentTrait.class).addAssignmentScript((AssignmentScriptContainer) input.getContainer(), null); + }); // <--[mechanism] // @object NPCTag @@ -1517,20 +1458,21 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("remove_assignment")) { - if (npc.hasTrait(AssignmentTrait.class)) { - if (mechanism.hasValue()) { - AssignmentTrait trait = getCitizen().getOrAddTrait(AssignmentTrait.class); - trait.removeAssignmentScript(mechanism.getValue().asString(), null); - trait.checkAutoRemove(); - } - else { - BukkitImplDeprecations.assignmentRemove.warn(mechanism.context); - getCitizen().getOrAddTrait(AssignmentTrait.class).clearAssignments(null); - npc.removeTrait(AssignmentTrait.class); - } + tagProcessor.registerMechanism("remove_assignment", false, (object, mechanism) -> { + if (!object.getCitizen().hasTrait(AssignmentTrait.class)) { + return; } - } + if (mechanism.hasValue()) { + AssignmentTrait trait = object.getCitizen().getOrAddTrait(AssignmentTrait.class); + trait.removeAssignmentScript(mechanism.getValue().asString(), null); + trait.checkAutoRemove(); + } + else { + BukkitImplDeprecations.assignmentRemove.warn(mechanism.context); + object.getCitizen().getOrAddTrait(AssignmentTrait.class).clearAssignments(null); + object.getCitizen().removeTrait(AssignmentTrait.class); + } + }); // <--[mechanism] // @object NPCTag @@ -1541,12 +1483,12 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("clear_assignments")) { - if (npc.hasTrait(AssignmentTrait.class)) { - getCitizen().getOrAddTrait(AssignmentTrait.class).clearAssignments(null); - npc.removeTrait(AssignmentTrait.class); + tagProcessor.registerMechanism("clear_assignments", false, (object, mechanism) -> { + if (object.getCitizen().hasTrait(AssignmentTrait.class)) { + object.getCitizen().getOrAddTrait(AssignmentTrait.class).clearAssignments(null); + object.getCitizen().removeTrait(AssignmentTrait.class); } - } + }); // <--[mechanism] // @object NPCTag @@ -1558,11 +1500,13 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("hologram_direction")) { // && mechanism.requireEnum(HologramTrait.HologramDirection.class) + tagProcessor.registerMechanism("hologram_direction", false, (object, mechanism) -> { + //if (mechanism.requireEnum(HologramTrait.HologramDirection.class)) { + //HologramTrait hologram = object.getCitizen().getOrAddTrait(HologramTrait.class); + //hologram.setDirection(HologramTrait.HologramDirection.valueOf(param.asString().toUpperCase())); + //} BukkitImplDeprecations.npcHologramDirection.warn(mechanism.context); - //HologramTrait hologram = getCitizen().getOrAddTrait(HologramTrait.class); - //hologram.setDirection(HologramTrait.HologramDirection.valueOf(mechanism.getValue().asString().toUpperCase())); - } + }); // <--[mechanism] // @object NPCTag @@ -1573,10 +1517,11 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("hologram_line_height") && mechanism.requireDouble()) { - HologramTrait hologram = getCitizen().getOrAddTrait(HologramTrait.class); - hologram.setLineHeight(mechanism.getValue().asDouble()); - } + tagProcessor.registerMechanism("hologram_line_height", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireDouble()) { + object.getCitizen().getOrAddTrait(HologramTrait.class).setLineHeight(input.asDouble()); + } + }); // <--[mechanism] // @object NPCTag @@ -1587,9 +1532,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("set_nickname")) { - getNicknameTrait().setNickname(mechanism.getValue().asString()); - } + tagProcessor.registerMechanism("set_nickname", false, ElementTag.class, (object, mechanism, input) -> { + object.getNicknameTrait().setNickname(input.asString()); + }); // <--[mechanism] // @object NPCTag @@ -1600,9 +1545,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("remove_nickname")) { - getNicknameTrait().removeNickname(); - } + tagProcessor.registerMechanism("remove_nickname", false, (object, mechanism) -> { + object.getNicknameTrait().removeNickname(); + }); // <--[mechanism] // @object NPCTag @@ -1613,9 +1558,9 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("set_entity_type") && mechanism.requireObject(EntityTag.class)) { - getCitizen().setBukkitEntityType(mechanism.valueAsType(EntityTag.class).getBukkitEntityType()); - } + tagProcessor.registerMechanism("set_entity_type", false, EntityTag.class, (object, mechanism, input) -> { + object.getCitizen().setBukkitEntityType(input.getBukkitEntityType()); + }); // <--[mechanism] // @object NPCTag @@ -1626,27 +1571,22 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("name") || mechanism.matches("set_name")) { - getCitizen().setName(mechanism.getValue().asString().length() > 256 ? mechanism.getValue().asString().substring(0, 256) : mechanism.getValue().asString()); - } + tagProcessor.registerMechanism("name", false, ElementTag.class, (object, mechanism, input) -> { + object.getCitizen().setName(input.asString().length() > 256 ? input.asString().substring(0, 256) : input.asString()); + }, "set_name"); // <--[mechanism] // @object NPCTag // @name owner // @input PlayerTag // @description - // Sets the owner of the NPC. + // Sets the owner of the NPC. Provide no input to set the server as the owner. // @tags // // --> - if (mechanism.matches("owner")) { - if (PlayerTag.matches(mechanism.getValue().asString())) { - getCitizen().getOrAddTrait(Owner.class).setOwner(mechanism.valueAsType(PlayerTag.class).getPlayerEntity()); - } - else { - getCitizen().getOrAddTrait(Owner.class).setOwner(mechanism.getValue().asString()); - } - } + tagProcessor.registerMechanism("owner", false, (object, mechanism) -> { + object.getCitizen().getOrAddTrait(Owner.class).setOwner(mechanism.getValue().canBeType(PlayerTag.class) ? mechanism.valueAsType(PlayerTag.class).getUUID() : null); + }); // <--[mechanism] // @object NPCTag @@ -1659,29 +1599,29 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("skin_blob")) { + tagProcessor.registerMechanism("skin_blob", false, (object, mechanism) -> { if (!mechanism.hasValue()) { - if (getCitizen().hasTrait(SkinTrait.class)) { - getCitizen().getOrAddTrait(SkinTrait.class).clearTexture(); - if (getCitizen().isSpawned()) { - getCitizen().despawn(DespawnReason.PENDING_RESPAWN); - getCitizen().spawn(getCitizen().getStoredLocation()); + if (object.getCitizen().hasTrait(SkinTrait.class)) { + object.getCitizen().getOrAddTrait(SkinTrait.class).clearTexture(); + if (object.getCitizen().isSpawned()) { + object.getCitizen().despawn(DespawnReason.PENDING_RESPAWN); + object.getCitizen().spawn(object.getCitizen().getStoredLocation()); } } } else { - SkinTrait skinTrait = getCitizen().getOrAddTrait(SkinTrait.class); + SkinTrait skinTrait = object.getCitizen().getOrAddTrait(SkinTrait.class); String[] dat = mechanism.getValue().asString().split(";"); if (dat.length < 2) { Debug.echoError("Invalid skin_blob input. Must specify texture;signature;name in full."); return; } skinTrait.setSkinPersistent(dat.length > 2 ? dat[2] : UUID.randomUUID().toString(), dat[1], dat[0]); - if (getCitizen().isSpawned() && getCitizen().getEntity() instanceof SkinnableEntity) { - ((SkinnableEntity) getCitizen().getEntity()).getSkinTracker().notifySkinChange(true); + if (object.getCitizen().isSpawned() && object.getCitizen().getEntity() instanceof SkinnableEntity skinnable) { + skinnable.getSkinTracker().notifySkinChange(true); } } - } + }); // <--[mechanism] // @object NPCTag @@ -1694,21 +1634,21 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("skin")) { + tagProcessor.registerMechanism("skin", false, (object, mechanism) -> { if (!mechanism.hasValue()) { - if (getCitizen().hasTrait(SkinTrait.class)) { - getCitizen().getOrAddTrait(SkinTrait.class).clearTexture(); + if (object.getCitizen().hasTrait(SkinTrait.class)) { + object.getCitizen().getOrAddTrait(SkinTrait.class).clearTexture(); } } else { - SkinTrait skinTrait = getCitizen().getOrAddTrait(SkinTrait.class); + SkinTrait skinTrait = object.getCitizen().getOrAddTrait(SkinTrait.class); skinTrait.setSkinName(mechanism.getValue().asString()); } - if (getCitizen().isSpawned()) { - getCitizen().despawn(DespawnReason.PENDING_RESPAWN); - getCitizen().spawn(getCitizen().getStoredLocation()); + if (object.getCitizen().isSpawned()) { + object.getCitizen().despawn(DespawnReason.PENDING_RESPAWN); + object.getCitizen().spawn(object.getCitizen().getStoredLocation()); } - } + }); // <--[mechanism] // @object NPCTag @@ -1720,9 +1660,11 @@ public void adjust(Mechanism mechanism) { // @tags // // --> - if (mechanism.matches("auto_update_skin") && mechanism.requireBoolean()) { - getCitizen().getOrAddTrait(SkinTrait.class).setShouldUpdateSkins(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("auto_update_skin", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getCitizen().getOrAddTrait(SkinTrait.class).setShouldUpdateSkins(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1731,10 +1673,10 @@ public void adjust(Mechanism mechanism) { // @description // Sets the item type of the item. // --> - if (mechanism.matches("item_type") && mechanism.requireObject(ItemTag.class)) { - ItemTag item = mechanism.valueAsType(ItemTag.class); - Material mat = item.getMaterial().getMaterial(); - Entity npcEntity = getEntity(); + tagProcessor.registerMechanism("item_type", false, ItemTag.class, (object, mechanism, input) -> { + Material mat = input.getBukkitMaterial(); + Entity npcEntity = object.getEntity(); + NPC citizen = object.getCitizen(); if (npcEntity instanceof Item droppedItem) { droppedItem.getItemStack().setType(mat); } @@ -1742,27 +1684,27 @@ else if (npcEntity instanceof ItemFrame itemFrame) { itemFrame.getItem().setType(mat); } else if (npcEntity instanceof FallingBlock) { - getCitizen().data().setPersistent(NPC.Metadata.ITEM_ID, mat.name()); - getCitizen().data().setPersistent(NPC.Metadata.ITEM_DATA, 0); + citizen.data().setPersistent(NPC.Metadata.ITEM_ID, mat.name()); + citizen.data().setPersistent(NPC.Metadata.ITEM_DATA, 0); } else { Debug.echoError("NPC is the not an item type!"); } - if (getCitizen().isSpawned()) { - getCitizen().despawn(); - getCitizen().spawn(getCitizen().getStoredLocation()); + if (citizen.isSpawned()) { + citizen.despawn(); + citizen.spawn(citizen.getStoredLocation()); } - } + }); - if (mechanism.matches("spawn")) { + tagProcessor.registerMechanism("spawn", false, (object, mechanism) -> { BukkitImplDeprecations.npcSpawnMechanism.warn(mechanism.context); if (mechanism.requireObject("Invalid LocationTag specified. Assuming last known NPC location.", LocationTag.class)) { - getCitizen().spawn(mechanism.valueAsType(LocationTag.class)); + object.getCitizen().spawn(mechanism.valueAsType(LocationTag.class)); } else { - getCitizen().spawn(getCitizen().getStoredLocation()); + object.getCitizen().spawn(object.getCitizen().getStoredLocation()); } - } + }); // <--[mechanism] // @object NPCTag @@ -1773,10 +1715,12 @@ else if (npcEntity instanceof FallingBlock) { // @tags // // --> - if (mechanism.matches("range") && mechanism.requireFloat()) { - getCitizen().getNavigator().getDefaultParameters().range(mechanism.getValue().asFloat()); - getCitizen().getNavigator().getLocalParameters().range(mechanism.getValue().asFloat()); - } + tagProcessor.registerMechanism("range", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireFloat()) { + object.getCitizen().getNavigator().getDefaultParameters().range(input.asFloat()); + object.getCitizen().getNavigator().getLocalParameters().range(input.asFloat()); + } + }); // <--[mechanism] // @object NPCTag @@ -1787,10 +1731,12 @@ else if (npcEntity instanceof FallingBlock) { // @tags // // --> - if (mechanism.matches("attack_range") && mechanism.requireFloat()) { - getCitizen().getNavigator().getDefaultParameters().attackRange(mechanism.getValue().asFloat()); - getCitizen().getNavigator().getLocalParameters().attackRange(mechanism.getValue().asFloat()); - } + tagProcessor.registerMechanism("attack_range", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireFloat()) { + object.getCitizen().getNavigator().getDefaultParameters().attackRange(input.asFloat()); + object.getCitizen().getNavigator().getLocalParameters().attackRange(input.asFloat()); + } + }); // <--[mechanism] // @object NPCTag @@ -1801,15 +1747,17 @@ else if (npcEntity instanceof FallingBlock) { // @tags // // --> - if (mechanism.matches("speed") && mechanism.requireFloat()) { - getCitizen().getNavigator().getDefaultParameters().speedModifier(mechanism.getValue().asFloat()); - getCitizen().getNavigator().getLocalParameters().speedModifier(mechanism.getValue().asFloat()); - } + tagProcessor.registerMechanism("speed", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireFloat()) { + object.getCitizen().getNavigator().getDefaultParameters().speedModifier(input.asFloat()); + object.getCitizen().getNavigator().getLocalParameters().speedModifier(input.asFloat()); + } + }); - if (mechanism.matches("despawn")) { + tagProcessor.registerMechanism("despawn", false, (object, mechanism) -> { BukkitImplDeprecations.npcDespawnMech.warn(mechanism.context); - getCitizen().despawn(DespawnReason.PLUGIN); - } + object.getCitizen().despawn(DespawnReason.PLUGIN); + }); // <--[mechanism] // @object NPCTag @@ -1820,18 +1768,18 @@ else if (npcEntity instanceof FallingBlock) { // @tags // // --> - if (mechanism.matches("set_sneaking") && mechanism.requireBoolean()) { - if (!getCitizen().hasTrait(SneakingTrait.class)) { - getCitizen().addTrait(SneakingTrait.class); + tagProcessor.registerMechanism("set_sneaking", false, ElementTag.class, (object, mechanism, input) -> { + if (!mechanism.requireBoolean()) { + return; } - SneakingTrait trait = getCitizen().getOrAddTrait(SneakingTrait.class); - if (trait.isSneaking() && !mechanism.getValue().asBoolean()) { + SneakingTrait trait = object.getCitizen().getOrAddTrait(SneakingTrait.class); + if (trait.isSneaking() && !input.asBoolean()) { trait.stand(); } - else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { + else if (!trait.isSneaking() && input.asBoolean()) { trait.sneak(); } - } + }); // <--[mechanism] // @object NPCTag @@ -1842,9 +1790,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("set_protected") && mechanism.requireBoolean()) { - getCitizen().setProtected(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("set_protected", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getCitizen().setProtected(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1855,9 +1805,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("lookclose") && mechanism.requireBoolean()) { - getLookCloseTrait().lookClose(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("lookclose", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getLookCloseTrait().lookClose(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1868,9 +1820,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("controllable") && mechanism.requireBoolean()) { - getCitizen().getOrAddTrait(Controllable.class).setEnabled(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("controllable", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getCitizen().getOrAddTrait(Controllable.class).setEnabled(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1881,9 +1835,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("targetable") && mechanism.requireBoolean()) { - getCitizen().getOrAddTrait(TargetableTrait.class).setTargetable(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("targetable", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getCitizen().getOrAddTrait(TargetableTrait.class).setTargetable(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1894,14 +1850,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("teleport_on_stuck") && mechanism.requireBoolean()) { - if (mechanism.getValue().asBoolean()) { - getNavigator().getDefaultParameters().stuckAction(TeleportStuckAction.INSTANCE); + tagProcessor.registerMechanism("teleport_on_stuck", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getNavigator().getDefaultParameters().stuckAction(input.asBoolean() ? TeleportStuckAction.INSTANCE : null); } - else { - getNavigator().getDefaultParameters().stuckAction(null); - } - } + }); // <--[mechanism] // @object NPCTag @@ -1912,10 +1865,12 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if ((mechanism.matches("distance_margin") || mechanism.matches("set_distance")) && mechanism.requireDouble()) { - getNavigator().getDefaultParameters().distanceMargin(mechanism.getValue().asDouble()); - getNavigator().getLocalParameters().distanceMargin(mechanism.getValue().asDouble()); - } + tagProcessor.registerMechanism("distance_margin", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireDouble()) { + object.getNavigator().getDefaultParameters().distanceMargin(input.asDouble()); + object.getNavigator().getLocalParameters().distanceMargin(input.asDouble()); + } + }, "set_distance"); // <--[mechanism] // @object NPCTag @@ -1926,10 +1881,12 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("path_distance_margin") && mechanism.requireDouble()) { - getNavigator().getDefaultParameters().pathDistanceMargin(mechanism.getValue().asDouble()); - getNavigator().getLocalParameters().pathDistanceMargin(mechanism.getValue().asDouble()); - } + tagProcessor.registerMechanism("path_distance_margin", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireDouble()) { + object.getNavigator().getDefaultParameters().pathDistanceMargin(input.asDouble()); + object.getNavigator().getLocalParameters().pathDistanceMargin(input.asDouble()); + } + }); // <--[mechanism] // @object NPCTag @@ -1941,9 +1898,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("use_new_finder") && mechanism.requireBoolean()) { - getNavigator().getDefaultParameters().useNewPathfinder(mechanism.getValue().asBoolean()); - } + tagProcessor.registerMechanism("use_new_finder", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getNavigator().getDefaultParameters().useNewPathfinder(input.asBoolean()); + } + }); // <--[mechanism] // @object NPCTag @@ -1956,15 +1915,15 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // // --> - if (mechanism.matches("navigator_look_at")) { + tagProcessor.registerMechanism("navigator_look_at", false, (object, mechanism) -> { if (mechanism.hasValue() && mechanism.requireObject(LocationTag.class)) { final LocationTag loc = mechanism.valueAsType(LocationTag.class); - getNavigator().getLocalParameters().lookAtFunction((n) -> loc); + object.getNavigator().getLocalParameters().lookAtFunction((n) -> loc); } else { - getNavigator().getLocalParameters().lookAtFunction(null); + object.getNavigator().getLocalParameters().lookAtFunction(null); } - } + }); // <--[mechanism] // @object NPCTag @@ -1975,9 +1934,9 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // TODO // --> - if (mechanism.matches("name_visible")) { - getCitizen().data().setPersistent(NPC.Metadata.NAMEPLATE_VISIBLE, mechanism.getValue().asString()); - } + tagProcessor.registerMechanism("name_visible", false, ElementTag.class, (object, mechanism, input) -> { + object.getCitizen().data().setPersistent(NPC.Metadata.NAMEPLATE_VISIBLE, input.asString()); + }); // <--[mechanism] // @object NPCTag @@ -1988,9 +1947,11 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // TODO // --> - if (mechanism.matches("glow_color") && mechanism.requireEnum(ChatColor.class)) { - getCitizen().getOrAddTrait(ScoreboardTrait.class).setColor(ChatColor.valueOf(mechanism.getValue().asString().toUpperCase())); - } + tagProcessor.registerMechanism("glow_color", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireEnum(ChatColor.class)) { + object.getCitizen().getOrAddTrait(ScoreboardTrait.class).setColor(input.asEnum(ChatColor.class)); + } + }); // <--[mechanism] // @object NPCTag @@ -2001,19 +1962,18 @@ else if (!trait.isSneaking() && mechanism.getValue().asBoolean()) { // @tags // TODO // --> - if (mechanism.matches("clear_waypoints")) { - Waypoints wp = getCitizen().getOrAddTrait(Waypoints.class); - if ((wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider)) { - ((List) ((WaypointProvider.EnumerableWaypointProvider) wp.getCurrentProvider()).waypoints()).clear(); + tagProcessor.registerMechanism("clear_waypoints", false, (object, mechanism) -> { + Waypoints wp = object.getCitizen().getOrAddTrait(Waypoints.class); + if (wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider provider) { + ((List) provider.waypoints()).clear(); } - else if ((wp.getCurrentProvider() instanceof WanderWaypointProvider)) { - List locs = ((WanderWaypointProvider) wp.getCurrentProvider()).getRegionCentres(); + else if (wp.getCurrentProvider() instanceof WanderWaypointProvider provider) { + List locs = provider.getRegionCentres(); for (Location loc : locs) { locs.remove(loc); // Manual clear to ensure recalculation for the forwarding list } - } - } + }); // <--[mechanism] // @object NPCTag @@ -2024,22 +1984,39 @@ else if ((wp.getCurrentProvider() instanceof WanderWaypointProvider)) { // @tags // TODO // --> - if (mechanism.matches("add_waypoint") && mechanism.requireObject(LocationTag.class)) { - Location target = mechanism.valueAsType(LocationTag.class).clone(); - Waypoints wp = getCitizen().getOrAddTrait(Waypoints.class); - if ((wp.getCurrentProvider() instanceof LinearWaypointProvider)) { - ((LinearWaypointProvider) wp.getCurrentProvider()).addWaypoint(new Waypoint(target)); + tagProcessor.registerMechanism("add_waypoint", false, LocationTag.class, (object, mechanism, input) -> { + Waypoints wp = object.getCitizen().getOrAddTrait(Waypoints.class); + if (wp.getCurrentProvider() instanceof LinearWaypointProvider provider) { + provider.addWaypoint(new Waypoint(input)); } - else if ((wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider)) { - ((List) ((WaypointProvider.EnumerableWaypointProvider) wp.getCurrentProvider()).waypoints()).add(new Waypoint(target)); + else if (wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider provider) { + ((List) provider.waypoints()).add(new Waypoint(input)); } - else if ((wp.getCurrentProvider() instanceof WanderWaypointProvider)) { - ((WanderWaypointProvider) wp.getCurrentProvider()).getRegionCentres().add(target); + else if (wp.getCurrentProvider() instanceof WanderWaypointProvider provider) { + provider.getRegionCentres().add(input); } - } + }); + } - tagProcessor.processMechanism(this, mechanism); + public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); + + @Override + public ObjectTag getObjectAttribute(Attribute attribute) { + return tagProcessor.getObjectAttribute(this, attribute); + } + @Override + public ObjectTag getNextObjectTypeDown() { + return getEntity() != null ? new EntityTag(this) : new ElementTag(identify()); + } + + public void applyProperty(Mechanism mechanism) { + mechanism.echoError("Cannot apply properties to an NPC!"); + } + + @Override + public void adjust(Mechanism mechanism) { + tagProcessor.processMechanism(this, mechanism); // Pass along to EntityTag mechanism handler if not already handled. if (!mechanism.fulfilled()) { if (isSpawned()) { From ecede59e929a019b96dae975c99ae7ecd8554401 Mon Sep 17 00:00:00 2001 From: MCSamuel <187220916+MC-Samuel@users.noreply.github.com> Date: Sun, 26 Jul 2026 15:00:41 -0700 Subject: [PATCH 118/169] `server list ping` event: player count fix & support (#2831) * fixes to ServerListPingScriptEventPaperImpl * changed excluded player calculation * moved to a separate determination * add back automatically setting number of players with `exclude_players` determination * adjust player count --- .../ServerListPingScriptEventPaperImpl.java | 25 ++++++++++++++++++- .../events/server/ListPingScriptEvent.java | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/ServerListPingScriptEventPaperImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/ServerListPingScriptEventPaperImpl.java index 6ea097a13d..af4af93b2b 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/ServerListPingScriptEventPaperImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/ServerListPingScriptEventPaperImpl.java @@ -15,6 +15,7 @@ import com.destroystokyo.paper.profile.PlayerProfile; import com.destroystokyo.paper.profile.ProfileProperty; import net.md_5.bungee.api.ChatColor; +import org.apache.commons.lang3.mutable.MutableInt; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.profile.PlayerTextures; @@ -70,6 +71,17 @@ public ServerListPingScriptEventPaperImpl() { ListedPlayersEditor.setListedPlayerInfo(evt.getEvent(), text); return true; }); + this.registerOptionalDetermination("player_count", ElementTag.class, (evt, context, input) -> { + if (!CoreConfiguration.allowRestrictedActions) { + Debug.echoError("Cannot use 'player_count' in list ping event: 'Allow restricted actions' is disabled in Denizen config.yml."); + return false; + } + if (input.isInt()) { + evt.getEvent().setNumPlayers(input.asInt()); + return true; + } + return false; + }); } public PaperServerListPingEvent getEvent() { @@ -86,7 +98,18 @@ public static void setListedPlayerInfo(PaperServerListPingEvent event, List exclude) { - event.getListedPlayers().removeIf(listedPlayerInfo -> exclude.contains(listedPlayerInfo.id())); + int size = event.getListedPlayers().size(); + MutableInt counter = new MutableInt(); + event.getListedPlayers().removeIf(listedPlayerInfo -> { + if (exclude.contains(listedPlayerInfo.id())) { + counter.increment(); + return true; + } + return false; + }); + if (size == event.getNumPlayers()) { + event.setNumPlayers(event.getNumPlayers() - counter.intValue()); + } } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/server/ListPingScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/server/ListPingScriptEvent.java index 0e8e554d2c..5f704f67c8 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/server/ListPingScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/server/ListPingScriptEvent.java @@ -48,6 +48,7 @@ public class ListPingScriptEvent extends BukkitScriptEvent implements Listener { // "VERSION_NAME:" to change the server's version name (only on Paper). // "EXCLUDE_PLAYERS:" to exclude a set of players from showing in the player count or preview of online players (only on Paper). // "ALTERNATE_PLAYER_TEXT:" to set custom text for the player list section of the server status (only on Paper). (Requires "Allow restricted actions" in Denizen/config.yml). Usage of this to present lines that look like player names (but aren't) is forbidden. + // "PLAYER_COUNT:" to set the amount of players that are online (only on Paper). (Requires "Allow restricted actions" in Denizen/config.yml). Usage of this to display a higher number of players than are actually connected is forbidden. // "MOTD:" to change the MOTD that will show. // // --> From f72546da985eb960f16e2b5854b1d1243d88d0c7 Mon Sep 17 00:00:00 2001 From: Inquisitor <62276696+creaturesofhabit@users.noreply.github.com> Date: Sun, 9 Aug 2026 20:36:19 -0400 Subject: [PATCH 119/169] `EntityTag`: `is_enemy` tag, `enemy` matcher (#2837) * Add is_enemy tag * Added enemy matcher This also requires/justifies the seperate method * add matcher documentation --- .../denizen/objects/EntityTag.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java index 4ce44f74ab..a31fef84f7 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java @@ -100,6 +100,7 @@ public class EntityTag implements ObjectTag, Adjustable, EntityFormObject, Flagg // "projectile" plaintext: matches for any projectile type (arrow, trident, fish hook, snowball, etc). // "hanging" plaintext: matches for any hanging type (painting, item_frame, etc). // "monster" plaintext: matches for any monster type (creepers, zombies, etc). + // "enemy" plaintext: matches for any hostile entities (zombies, shulkers, ect). // "animal" plaintext: matches for any animal type (pigs, cows, etc). // "mob" plaintext: matches for any mob type (creepers, pigs, etc). // "living" plaintext: matches for any living type (players, pigs, creepers, etc). @@ -610,6 +611,13 @@ public boolean isMonsterType() { return getBukkitEntity() instanceof Monster; } + public boolean isEnemyType() { + if (getBukkitEntity() == null && entity_type != null) { + return Enemy.class.isAssignableFrom(entity_type.getBukkitEntityType().getEntityClass()); + } + return getBukkitEntity() instanceof Enemy; + } + public boolean isMobType() { if (getBukkitEntity() == null && entity_type != null) { return Mob.class.isAssignableFrom(entity_type.getBukkitEntityType().getEntityClass()); @@ -2372,6 +2380,20 @@ else if (object.getBukkitEntity() instanceof Hanging hanging) { return new ElementTag(object.isMonsterType()); }); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19)) { + + // <--[tag] + // @attribute + // @returns ElementTag(Boolean) + // @group data + // @description + // Returns whether the entity type is an enemy. See <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Enemy.html> + // --> + tagProcessor.registerTag(ElementTag.class, "is_enemy", (attribute, object) -> { + return new ElementTag(object.isEnemyType()); + }); + } + // <--[tag] // @attribute // @returns ElementTag(Boolean) @@ -4587,6 +4609,8 @@ public final boolean trySpecialEntityMatcher(String text, boolean isNPC) { return isMobType(); case "animal": return isAnimalType(); + case "enemy": + return isEnemyType(); } return false; } From 234fe8f5dbf2b9f118cfd3b17f2569f4619cc055 Mon Sep 17 00:00:00 2001 From: Bear Riley <46008563+BehrRiley@users.noreply.github.com> Date: Sun, 9 Aug 2026 20:52:43 -0400 Subject: [PATCH 120/169] `FakeBlockHelper`: handle `fluidCount` in chunk data (#2834) --- .../nms/v26_2/impl/network/handlers/FakeBlockHelper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java index e25cf5ae38..784f61ef11 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/FakeBlockHelper.java @@ -122,6 +122,7 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo Registry biomeRegistry = ((CraftWorld) world).getHandle().registryAccess().lookupOrThrow(Registries.BIOME); for (int y = minChunkY; y < maxChunkY; y++) { int blockCount = serial.readShort(); + int fluidCount = serial.readShort(); // reflected constructors as workaround for spigot remapper bug - Mojang "IdMap" became Spigot "IRegistry" but should be "Registry" PalettedContainer states = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); states.read(serial); @@ -151,6 +152,7 @@ else if (newState.isAir() && !oldState.isAir()) { } } outputSerial.writeShort(blockCount); + outputSerial.writeShort(fluidCount); states.write(outputSerial); biomes.write(outputSerial); } From ec61942095eaec10660b31fba079096e6a04c86b Mon Sep 17 00:00:00 2001 From: Bear Riley <46008563+BehrRiley@users.noreply.github.com> Date: Sat, 22 Aug 2026 02:12:42 -0400 Subject: [PATCH 121/169] Update MiniMessage documentation link (#2842) --- .../denizen/paper/properties/PaperElementExtensions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperElementExtensions.java b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperElementExtensions.java index 090124e434..86a512797c 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperElementExtensions.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperElementExtensions.java @@ -19,7 +19,7 @@ public static void register() { // @Plugin Paper // @group paper // @description - // Returns the element with all MiniMessage tags parsed, see <@link url https://docs.adventure.kyori.net/minimessage/format.html> for more information. + // Returns the element with all MiniMessage tags parsed, see <@link url https://docs.papermc.io/adventure/minimessage/format/> for more information. // This may be useful for reading data from external plugins, but should not be used in normal scripts. // --> ElementTag.tagProcessor.registerTag(ElementTag.class, "parse_minimessage", (attribute, object) -> { From 0592bc095f1857d4fb0cd4f064eef9a964095023 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 12 Jul 2025 23:55:39 +0100 Subject: [PATCH 122/169] Initial cleanups & optimizations --- .../nms/v1_21/ReflectionMappingsInfo.java | 4 + .../network/handlers/FakeBlockHelper.java | 144 ++++++++++-------- .../packet/FakeBlocksPacketHandlers.java | 2 +- 3 files changed, 88 insertions(+), 62 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 360d260ee4..271159b1b6 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -99,6 +99,7 @@ public class ReflectionMappingsInfo { public static String ClientboundSetPassengersPacket_passengers = "c"; // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo + public static String ClientboundLevelChunkPacketDataBlockEntityInfo_create_method = "a"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "c"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_y = "d"; @@ -127,4 +128,7 @@ public class ReflectionMappingsInfo { // net.minecraft.stats.ServerRecipeBook public static String ServerRecipeBook_addHighlight_method = "e"; + + // net.minecraft.world.level.block.entity.BlockEntityType + public static String BlockEntityType_validBlocks = "Y"; } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 13ca382b8b..891c717c6f 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -8,10 +8,11 @@ import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.world.level.biome.Biome; @@ -23,38 +24,56 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.Strategy; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockStates; +import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockType; import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; public class FakeBlockHelper { public static Field CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getFirstOfType(List.class); + public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); + public static final MethodHandle CHUNK_DATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); - public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); - public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 2).findFirst().get(); + public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 3).findFirst().get(); + public static Field BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).get(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); + + public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); + + static { + try { + for (BlockEntityType nmsBlockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.get(nmsBlockEntityType); + for (Block validBlock : validBlocks) { + MATERIAL_BLOCK_ENTITY_TYPES.put(CraftBlockType.minecraftToBukkit(validBlock), nmsBlockEntityType); + } + } + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } public static BlockState getNMSState(FakeBlock block) { return ((CraftBlockData) block.material.getModernData()).getState(); } - public static boolean anyBlocksInSection(List blocks, int y) { - int minY = y << 4; - int maxY = (y << 4) + 16; - for (FakeBlock block : blocks) { + public static boolean anyBlocksInSection(List blocksInChunk, int y) { + int minY = SectionPos.sectionToBlockCoord(y); + int maxY = minY + 16; + for (FakeBlock block : blocksInChunk) { int blockY = block.location.getBlockY(); if (blockY >= minY && blockY < maxY) { return true; @@ -66,7 +85,7 @@ public static boolean anyBlocksInSection(List blocks, int y) { public static Field PAPER_CHUNK_READY; public static boolean tryPaperPatch = true; - public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket newPacket, ClientboundLevelChunkWithLightPacket oldPacket) { + public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket newPacket) { if (!Denizen.supportsPaper || !tryPaperPatch) { return; } @@ -89,57 +108,54 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalPacket, int chunkX, int chunkZ, List blocks) { + public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) { try { - ClientboundLevelChunkWithLightPacket duplicateCorePacket = DenizenNetworkManagerImpl.copyPacket(originalPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); - copyPacketPaperPatch(duplicateCorePacket, originalPacket); - RegistryFriendlyByteBuf copier = new RegistryFriendlyByteBuf(Unpooled.buffer(), CraftRegistry.getMinecraftRegistry()); - originalPacket.getChunkData().write(copier); - ClientboundLevelChunkPacketData packet = new ClientboundLevelChunkPacketData(copier, chunkX, chunkZ); - FriendlyByteBuf serial = originalPacket.getChunkData().getReadBuffer(); - FriendlyByteBuf outputSerial = new FriendlyByteBuf(Unpooled.buffer(serial.readableBytes())); - List blockEntities = new ArrayList((List) CHUNKDATA_BLOCK_ENTITIES.get(originalPacket.getChunkData())); - CHUNKDATA_BLOCK_ENTITIES.set(packet, blockEntities); - for (int i = 0; i < blockEntities.size(); i++) { - Object blockEnt = blockEntities.get(i); + ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(copiedChunkPacket); + // A list of block entities sent with the chunk data + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + LocationTag location = new LocationTag(world, 0, 0, 0); + ListIterator blockEntitiesIterator = blockEntities.listIterator(); + while (blockEntitiesIterator.hasNext()) { + Object blockEnt = blockEntitiesIterator.next(); int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); - int x = (chunkX << 4) + ((xz >> 4) & 15); - int z = (chunkZ << 4) + (xz & 15); - for (FakeBlock block : blocks) { - LocationTag loc = block.location; - if (loc.getBlockX() == x && loc.getBlockY() == y && loc.getBlockZ() == z && block.material != null) { - BlockEntity newBlockEnt = CraftBlockStates.createNewTileEntity(block.material.getMaterial()); - Object newData = CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR.invoke(xz, y, newBlockEnt.getType(), newBlockEnt.getUpdateTag(CraftRegistry.getMinecraftRegistry())); - blockEntities.set(i, newData); - break; - } + int relativeX = SectionPos.sectionRelative(xz >> 4); + int relativeZ = SectionPos.sectionRelative(xz); + int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; + int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; + location.setX(x); + location.setY(y); + location.setZ(z); + if (fakeBlockMap.byLocation.containsKey(location)) { + blockEntitiesIterator.remove(); } } + // Get the original chunk data to read, and a buf of the same size to write + FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); int worldMinY = world.getMinHeight(); int worldMaxY = world.getMaxHeight(); - int minChunkY = worldMinY >> 4; - int maxChunkY = worldMaxY >> 4; - Registry biomeRegistry = ((CraftWorld) world).getHandle().registryAccess().lookupOrThrow(Registries.BIOME); + int minChunkY = SectionPos.blockToSectionCoord(worldMinY); + int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + // These are section coords, iterating through every chunk section for (int y = minChunkY; y < maxChunkY; y++) { - int blockCount = serial.readShort(); - // reflected constructors as workaround for spigot remapper bug - Mojang "IdMap" became Spigot "IRegistry" but should be "Registry" - PalettedContainer states = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); - states.read(serial); - PalettedContainer biomes = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry)); - biomes.read(serial); - if (anyBlocksInSection(blocks, y)) { - int minY = y << 4; - int maxY = (y << 4) + 16; - for (FakeBlock block : blocks) { + int blockCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY); + states.read(rawChunkData); + PalettedContainer biomes = new PalettedContainer<>(biomeRegistry.getValueOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry)); + biomes.read(rawChunkData); + if (anyBlocksInSection(blocksInChunk, y)) { + int minY = SectionPos.sectionToBlockCoord(y); + int maxY = minY + 16; + for (FakeBlock block : blocksInChunk) { int blockY = block.location.getBlockY(); if (blockY >= minY && blockY < maxY && block.material != null) { - int blockX = block.location.getBlockX(); - int blockZ = block.location.getBlockZ(); - blockX -= (blockX >> 4) * 16; - blockY -= (blockY >> 4) * 16; - blockZ -= (blockZ >> 4) * 16; - BlockState oldState = states.get(blockX, blockY, blockZ); + int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(blockY); + int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); BlockState newState = getNMSState(block); if (oldState.isAir() && !newState.isAir()) { blockCount++; @@ -147,18 +163,24 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo else if (newState.isAir() && !oldState.isAir()) { blockCount--; } - states.set(blockX, blockY, blockZ, newState); + states.set(relativeX, relativeY, relativeZ, newState); + BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (nmsBlockEntityType == null) { + continue; + } + BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); } } } - outputSerial.writeShort(blockCount); - states.write(outputSerial); - biomes.write(outputSerial); + newChunkData.writeShort(blockCount); + states.write(newChunkData); + biomes.write(newChunkData); } - byte[] outputBytes = outputSerial.array(); - CHUNKDATA_BUFFER_SETTER.invoke(packet, outputBytes); - CHUNKPACKET_CHUNKDATA_SETTER.invoke(duplicateCorePacket, packet); - return duplicateCorePacket; + CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + return copiedChunkPacket; } catch (Throwable ex) { Debug.echoError(ex); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 4938114cac..52ed0f191d 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -47,7 +47,7 @@ public static Packet processShowFakeForPacket(DenizenN if (blocks == null || blocks.isEmpty()) { return packet; } - ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks); + ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); return newPacket; } else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { From 17bcd4d18603a297d6c6a93ef7e3cb48223c3afc Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 12 Jul 2025 23:57:54 +0100 Subject: [PATCH 123/169] Remove unnecessary `try` --- .../network/handlers/FakeBlockHelper.java | 138 +++++++++--------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 891c717c6f..7b52b114d7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -108,83 +108,77 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) { - try { - ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); - copyPacketPaperPatch(copiedChunkPacket); - // A list of block entities sent with the chunk data - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); - LocationTag location = new LocationTag(world, 0, 0, 0); - ListIterator blockEntitiesIterator = blockEntities.listIterator(); - while (blockEntitiesIterator.hasNext()) { - Object blockEnt = blockEntitiesIterator.next(); - int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); - int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); - int relativeX = SectionPos.sectionRelative(xz >> 4); - int relativeZ = SectionPos.sectionRelative(xz); - int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; - int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; - location.setX(x); - location.setY(y); - location.setZ(z); - if (fakeBlockMap.byLocation.containsKey(location)) { - blockEntitiesIterator.remove(); - } + public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { + ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(copiedChunkPacket); + // A list of block entities sent with the chunk data + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + LocationTag location = new LocationTag(world, 0, 0, 0); + ListIterator blockEntitiesIterator = blockEntities.listIterator(); + while (blockEntitiesIterator.hasNext()) { + Object blockEnt = blockEntitiesIterator.next(); + int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); + int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int relativeX = SectionPos.sectionRelative(xz >> 4); + int relativeZ = SectionPos.sectionRelative(xz); + int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; + int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; + location.setX(x); + location.setY(y); + location.setZ(z); + if (fakeBlockMap.byLocation.containsKey(location)) { + blockEntitiesIterator.remove(); } - // Get the original chunk data to read, and a buf of the same size to write - FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); - FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); - int worldMinY = world.getMinHeight(); - int worldMaxY = world.getMaxHeight(); - int minChunkY = SectionPos.blockToSectionCoord(worldMinY); - int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); - Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); - // These are section coords, iterating through every chunk section - for (int y = minChunkY; y < maxChunkY; y++) { - int blockCount = rawChunkData.readShort(); - PalettedContainer states = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY); - states.read(rawChunkData); - PalettedContainer biomes = new PalettedContainer<>(biomeRegistry.getValueOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry)); - biomes.read(rawChunkData); - if (anyBlocksInSection(blocksInChunk, y)) { - int minY = SectionPos.sectionToBlockCoord(y); - int maxY = minY + 16; - for (FakeBlock block : blocksInChunk) { - int blockY = block.location.getBlockY(); - if (blockY >= minY && blockY < maxY && block.material != null) { - int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); - int relativeY = SectionPos.sectionRelative(blockY); - int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); - BlockState oldState = states.get(relativeX, relativeY, relativeZ); - BlockState newState = getNMSState(block); - if (oldState.isAir() && !newState.isAir()) { - blockCount++; - } - else if (newState.isAir() && !oldState.isAir()) { - blockCount--; - } - states.set(relativeX, relativeY, relativeZ, newState); - BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); - if (nmsBlockEntityType == null) { - continue; - } - BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); - Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); - blockEntities.add(packetBlockEntityData); + } + // Get the original chunk data to read, and a buf of the same size to write + FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); + int worldMinY = world.getMinHeight(); + int worldMaxY = world.getMaxHeight(); + int minChunkY = SectionPos.blockToSectionCoord(worldMinY); + int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + // These are section coords, iterating through every chunk section + for (int y = minChunkY; y < maxChunkY; y++) { + int blockCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + states.read(rawChunkData); + PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + biomes.read(rawChunkData); + if (anyBlocksInSection(blocksInChunk, y)) { + int minY = SectionPos.sectionToBlockCoord(y); + int maxY = minY + 16; + for (FakeBlock block : blocksInChunk) { + int blockY = block.location.getBlockY(); + if (blockY >= minY && blockY < maxY && block.material != null) { + int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(blockY); + int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); + BlockState newState = getNMSState(block); + if (oldState.isAir() && !newState.isAir()) { + blockCount++; + } + else if (newState.isAir() && !oldState.isAir()) { + blockCount--; } + states.set(relativeX, relativeY, relativeZ, newState); + BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (nmsBlockEntityType == null) { + continue; + } + BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); } } - newChunkData.writeShort(blockCount); - states.write(newChunkData); - biomes.write(newChunkData); } - CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); - return copiedChunkPacket; - } - catch (Throwable ex) { - Debug.echoError(ex); + newChunkData.writeShort(blockCount); + states.write(newChunkData); + biomes.write(newChunkData); } - return null; + CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + return copiedChunkPacket; } } From 04ef69ffafa8eea88d3344eb44b396a42bf1f485 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 13 Jul 2025 00:27:59 +0100 Subject: [PATCH 124/169] Cleanup reflection --- .../nms/v1_21/ReflectionMappingsInfo.java | 10 +++---- .../network/handlers/FakeBlockHelper.java | 29 ++++++++----------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 271159b1b6..a1e50ac985 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -98,6 +98,10 @@ public class ReflectionMappingsInfo { // net.minecraft.network.protocol.game.ClientboundSetPassengersPacket public static String ClientboundSetPassengersPacket_passengers = "c"; + // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData + public static String ClientboundLevelChunkPacketData_buffer = "d"; + public static String ClientboundLevelChunkPacketData_blockEntitiesData = "e"; + // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo public static String ClientboundLevelChunkPacketDataBlockEntityInfo_create_method = "a"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "c"; @@ -114,12 +118,6 @@ public class ReflectionMappingsInfo { // 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"; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 7b52b114d7..ea80c76f07 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -11,7 +11,6 @@ import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; @@ -33,29 +32,25 @@ import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; import java.lang.invoke.MethodHandle; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.*; public class FakeBlockHelper { - public static Field CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getFirstOfType(List.class); - public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; - public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); - public static final MethodHandle CHUNK_DATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); - public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); - public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); - public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); - public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); - public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 3).findFirst().get(); - public static Field BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).get(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); + public static final MethodHandle CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_blockEntitiesData, List.class); + public static final MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getSetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_buffer, byte[].class); + public static final Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; + public static final MethodHandle CHUNKDATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); + public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); + public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); + public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); static { try { for (BlockEntityType nmsBlockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.get(nmsBlockEntityType); + Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.invokeExact(nmsBlockEntityType); for (Block validBlock : validBlocks) { MATERIAL_BLOCK_ENTITY_TYPES.put(CraftBlockType.minecraftToBukkit(validBlock), nmsBlockEntityType); } @@ -112,13 +107,13 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); // A list of block entities sent with the chunk data - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invoke(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); ListIterator blockEntitiesIterator = blockEntities.listIterator(); while (blockEntitiesIterator.hasNext()) { Object blockEnt = blockEntitiesIterator.next(); - int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); - int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int xz = (int) CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.invoke(blockEnt); + int y = (int) CHUNKDATA_BLOCKENTITYINFO_Y.invoke(blockEnt); int relativeX = SectionPos.sectionRelative(xz >> 4); int relativeZ = SectionPos.sectionRelative(xz); int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; @@ -169,7 +164,7 @@ else if (newState.isAir() && !oldState.isAir()) { } BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); - Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); } } From f60f3962628db20720a44516b0bb55fa818685c7 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:01:41 +0100 Subject: [PATCH 125/169] Initial work on fake block light levels --- .../network/handlers/FakeBlockHelper.java | 155 +++++++++++++++++- .../packet/FakeBlocksPacketHandlers.java | 3 +- 2 files changed, 150 insertions(+), 8 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index ea80c76f07..9723a3ca96 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -1,12 +1,17 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.FakeBlock; +import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -14,6 +19,9 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.network.protocol.game.ClientboundLightUpdatePacketData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; @@ -21,15 +29,17 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.Strategy; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R7.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockType; -import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockType; +import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; @@ -133,8 +143,20 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo int minChunkY = SectionPos.blockToSectionCoord(worldMinY); int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + int blocksLit = 0, skyLit = 0; // These are section coords, iterating through every chunk section + ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); + Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); for (int y = minChunkY; y < maxChunkY; y++) { + SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); + int sectionIndex = y + Math.abs(minChunkY) + 1; + boolean hasSky = false, hasBlock = false; + if (lightData.getBlockYMask().get(sectionIndex)) { + hasBlock = true; + } + if (lightData.getSkyYMask().get(sectionIndex)) { + hasSky = true; + } int blockCount = rawChunkData.readShort(); PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); states.read(rawChunkData); @@ -166,9 +188,29 @@ else if (newState.isAir() && !oldState.isAir()) { createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); + DataLayer blockLights; + if (!hasBlock) { + Debug.log(">>>>>>>>>>>>>>>>>>> No light data, adding"); + blockLights = new DataLayer(); + lightData.getBlockUpdates().add(blocksLit, blockLights.getData()); + lightData.getBlockYMask().set(sectionIndex); + lightData.getEmptyBlockYMask().clear(sectionIndex); + hasBlock = true; + } + else { + blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + } + DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); + blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, world, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } + if (hasBlock) { + blocksLit++; + } + if (hasSky) { + skyLit++; + } newChunkData.writeShort(blockCount); states.write(newChunkData); biomes.write(newChunkData); @@ -176,4 +218,105 @@ else if (newState.isAir() && !oldState.isAir()) { CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); return copiedChunkPacket; } + + public static final int[][] directions = { + {0, -1, 0}, + {0, 1, 0}, + {-1, 0, 0}, + {1, 0, 0}, + {0, 0, -1}, + {0, 0, 1} + }; + + public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + int maxLight = Math.max(blockLights.get(relativeX, relativeY, relativeZ), skyLights.get(relativeX, relativeY, relativeZ)); + if (maxLight == 15) { + return 15; + } + List blockLookups = null; + for (int[] direction : directions) { + int yOffest = direction[1]; + int neighborX = relativeX + direction[0]; + int neighborY = relativeY + yOffest; + int neighborZ = relativeZ + direction[2]; + if (coordOutOfSection(neighborX) || coordOutOfSection(neighborZ)) { + if (blockLookups == null) { + blockLookups = new ArrayList<>(2); + } + blockLookups.add(new BlockPos(sectionPos.minBlockX() + neighborX, sectionPos.minBlockY() + neighborY, sectionPos.minBlockZ() + neighborZ)); + continue; + } + int light; + if (coordOutOfSection(neighborY)) { + int adjacentSectionIndex = sectionIndex + yOffest; + boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); + boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); + if (!hasBlockLights && !hasSkyLights) { + Debug.log("No lights in adjacent section"); + continue; + } + int wrappedNeighborY = SectionPos.sectionRelative(neighborY); + light = Math.max( + hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0, + hasBlockLights ? new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0 + ); + Debug.log("Adjacent packet light: " + light); + } + else { + light = Math.max(blockLights.get(neighborX, neighborY, neighborZ), skyLights.get(neighborX, neighborY, neighborZ)); + Debug.log("Packet light: " + light); + } + if (light == 15) { + return 15; + } + if (light > maxLight) { + maxLight = light; + } + } + if (blockLookups == null) { + return maxLight; + } + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + for (BlockPos blockPos : blockLookups) { + SectionPos containingSection = SectionPos.of(blockPos); + SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { + Debug.log("Getting section to cache"); + LevelLightEngine lightEngine = nmsWorld.getLightEngine(); + DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); + DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); + return new SectionLightCache(sectionBlockLights, sectionSkyLights); + }); + int light = sectionLight.getLight(blockPos); + Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { + NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); + }, 1); + Debug.log("Block light: " + light); + if (light == 15) { + return 15; + } + if (light > maxLight) { + maxLight = light; + } + } + return maxLight; + } + + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { + + public int getLight(BlockPos blockPos) { + int relativeX = SectionPos.sectionRelative(blockPos.getX()); + int relativeY = SectionPos.sectionRelative(blockPos.getY()); + int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); + int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) : 0; + if (skyLight == 15) { + return skyLight; + } + int blockLight = blockLights != null ? blockLights.get(relativeX, relativeY, relativeZ) : 0; + return Math.max(skyLight, blockLight); + } + } + + public static boolean coordOutOfSection(int relativeCoord) { + return relativeCoord < 0 || relativeCoord > 15; + } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 52ed0f191d..f8b31d4052 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -47,8 +47,7 @@ public static Packet processShowFakeForPacket(DenizenN if (blocks == null || blocks.isEmpty()) { return packet; } - ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); - return newPacket; + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); } else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); From 169ba494297718757ed08bd2e3aec57f5eacf050 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:33:58 +0100 Subject: [PATCH 126/169] Minor optimization to `max` handling --- .../network/handlers/FakeBlockHelper.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 9723a3ca96..2f0180bce4 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -229,7 +229,7 @@ else if (newState.isAir() && !oldState.isAir()) { }; public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int maxLight = Math.max(blockLights.get(relativeX, relativeY, relativeZ), skyLights.get(relativeX, relativeY, relativeZ)); + int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); if (maxLight == 15) { return 15; } @@ -256,14 +256,16 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - light = Math.max( - hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0, - hasBlockLights ? new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0 - ); + int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0; + if (skyLight == 15 || !hasBlockLights) { + return skyLight; + } + int blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + light = Math.max(skyLight, blockLight); Debug.log("Adjacent packet light: " + light); } else { - light = Math.max(blockLights.get(neighborX, neighborY, neighborZ), skyLights.get(neighborX, neighborY, neighborZ)); + light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights); Debug.log("Packet light: " + light); } if (light == 15) { @@ -301,6 +303,15 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat return maxLight; } + public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData) { + int skyLight = skyLightData.get(relativeX, relativeY, relativeZ); + if (skyLight == 15) { + return 15; + } + int blockLight = blockLightData.get(relativeX, relativeY, relativeZ); + return Math.max(skyLight, blockLight); + } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { public int getLight(BlockPos blockPos) { From 4134ed6c9b443da48321e766e4f2991607e2a7c5 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:35:19 +0100 Subject: [PATCH 127/169] Pass in NMS world --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 2f0180bce4..e5362bf056 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -185,7 +185,8 @@ else if (newState.isAir() && !oldState.isAir()) { continue; } BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + createdBlockEntity.setLevel(nmsWorld); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); DataLayer blockLights; @@ -201,7 +202,7 @@ else if (newState.isAir() && !oldState.isAir()) { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); } DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); - blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, world, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); + blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } @@ -228,7 +229,7 @@ else if (newState.isAir() && !oldState.isAir()) { {0, 0, 1} }; - public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); if (maxLight == 15) { return 15; @@ -278,7 +279,6 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat if (blockLookups == null) { return maxLight; } - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { From ef72f4e783b35deffade5fd41481e0bb72431959 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:25:47 +0100 Subject: [PATCH 128/169] Account for sky darkness --- .../network/handlers/FakeBlockHelper.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index e5362bf056..fa5bffabbb 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -230,7 +230,8 @@ else if (newState.isAir() && !oldState.isAir()) { }; public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); + int ambientDarkness = nmsWorld.getSkyDarken(); + int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights, ambientDarkness); if (maxLight == 15) { return 15; } @@ -257,7 +258,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0; + int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness : 0; if (skyLight == 15 || !hasBlockLights) { return skyLight; } @@ -266,7 +267,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat Debug.log("Adjacent packet light: " + light); } else { - light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights); + light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights, ambientDarkness); Debug.log("Packet light: " + light); } if (light == 15) { @@ -288,7 +289,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int light = sectionLight.getLight(blockPos); + int light = sectionLight.getLight(blockPos, ambientDarkness); Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); }, 1); @@ -303,8 +304,8 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat return maxLight; } - public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData) { - int skyLight = skyLightData.get(relativeX, relativeY, relativeZ); + public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData, int ambientDarkness) { + int skyLight = skyLightData.get(relativeX, relativeY, relativeZ) - ambientDarkness; if (skyLight == 15) { return 15; } @@ -314,15 +315,15 @@ public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLaye public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - public int getLight(BlockPos blockPos) { + public int getLight(BlockPos blockPos, int ambientDarkness) { int relativeX = SectionPos.sectionRelative(blockPos.getX()); int relativeY = SectionPos.sectionRelative(blockPos.getY()); int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); - int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) : 0; - if (skyLight == 15) { + int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) - ambientDarkness : 0; + if (skyLight == 15 || blockLights == null) { return skyLight; } - int blockLight = blockLights != null ? blockLights.get(relativeX, relativeY, relativeZ) : 0; + int blockLight = blockLights.get(relativeX, relativeY, relativeZ); return Math.max(skyLight, blockLight); } } From 5f9f2ec5526d320dba24214f1aa409504164123d Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 22:13:50 +0100 Subject: [PATCH 129/169] Set both block and sky light for smoother visuals --- .../network/handlers/FakeBlockHelper.java | 136 ++++++++++-------- 1 file changed, 78 insertions(+), 58 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index fa5bffabbb..7681e6892e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -189,20 +189,32 @@ else if (newState.isAir() && !oldState.isAir()) { createdBlockEntity.setLevel(nmsWorld); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); - DataLayer blockLights; - if (!hasBlock) { - Debug.log(">>>>>>>>>>>>>>>>>>> No light data, adding"); - blockLights = new DataLayer(); - lightData.getBlockUpdates().add(blocksLit, blockLights.getData()); - lightData.getBlockYMask().set(sectionIndex); - lightData.getEmptyBlockYMask().clear(sectionIndex); - hasBlock = true; + BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, + getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), + lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); + Debug.log("Final data: " + estimatedLights); + if (estimatedLights.block() > 0) { + DataLayer blockLights; + if (!hasBlock) { + blockLights = addLayer(lightData.getBlockUpdates(), blocksLit, lightData.getBlockYMask(), lightData.getEmptyBlockYMask(), sectionIndex); + hasBlock = true; + } + else { + blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + } + blockLights.set(relativeX, relativeY, relativeZ, estimatedLights.block()); } - else { - blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + if (estimatedLights.sky() > 0) { + DataLayer skyLights; + if (!hasSky) { + skyLights = addLayer(lightData.getSkyUpdates(), skyLit, lightData.getSkyYMask(), lightData.getEmptySkyYMask(), sectionIndex); + hasSky = true; + } + else { + skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); + } + skyLights.set(relativeX, relativeY, relativeZ, estimatedLights.sky()); } - DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); - blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } @@ -220,6 +232,20 @@ else if (newState.isAir() && !oldState.isAir()) { return copiedChunkPacket; } + public static DataLayer addLayer(List layers, int index, BitSet litSections, BitSet unlitSections, int sectionIndex) { + DataLayer newLayer = new DataLayer(); + layers.add(index, newLayer.getData()); + litSections.set(sectionIndex); + unlitSections.clear(sectionIndex); + return newLayer; + } + + public static DataLayer getLayer(boolean has, List layers, int index) { + return has ? new DataLayer(layers.get(index)) : null; + } + + public record BlockLightData(int sky, int block) {} + public static final int[][] directions = { {0, -1, 0}, {0, 1, 0}, @@ -229,12 +255,10 @@ else if (newState.isAir() && !oldState.isAir()) { {0, 0, 1} }; - public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int ambientDarkness = nmsWorld.getSkyDarken(); - int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights, ambientDarkness); - if (maxLight == 15) { - return 15; - } + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + int ambientDarkness = 0; + int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); + int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); List blockLookups = null; for (int[] direction : directions) { int yOffest = direction[1]; @@ -248,7 +272,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat blockLookups.add(new BlockPos(sectionPos.minBlockX() + neighborX, sectionPos.minBlockY() + neighborY, sectionPos.minBlockZ() + neighborZ)); continue; } - int light; + int blockLight = -1, skyLight = -1; if (coordOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); @@ -258,27 +282,28 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness : 0; - if (skyLight == 15 || !hasBlockLights) { - return skyLight; + if (hasSkyLights) { + skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness; + } + if (hasBlockLights) { + blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - int blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); - light = Math.max(skyLight, blockLight); - Debug.log("Adjacent packet light: " + light); + Debug.log("Adjacent packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } else { - light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights, ambientDarkness); - Debug.log("Packet light: " + light); + skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); + blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); + Debug.log("Packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } - if (light == 15) { - return 15; + if (skyLight > maxSky) { + maxSky = skyLight; } - if (light > maxLight) { - maxLight = light; + if (blockLight > maxBlock) { + maxBlock = blockLight; } } if (blockLookups == null) { - return maxLight; + return new BlockLightData(maxSky, maxBlock); } for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); @@ -289,42 +314,37 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int light = sectionLight.getLight(blockPos, ambientDarkness); + int skyLight = sectionLight.getSkyLight(blockPos, ambientDarkness); + int blockLight = sectionLight.getBlockLight(blockPos); + if (skyLight > maxSky) { + maxSky = skyLight; + } + if (blockLight > maxBlock) { + maxBlock = blockLight; + } Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); }, 1); - Debug.log("Block light: " + light); - if (light == 15) { - return 15; - } - if (light > maxLight) { - maxLight = light; - } } - return maxLight; + return new BlockLightData(maxSky, maxBlock); } - public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData, int ambientDarkness) { - int skyLight = skyLightData.get(relativeX, relativeY, relativeZ) - ambientDarkness; - if (skyLight == 15) { - return 15; - } - int blockLight = blockLightData.get(relativeX, relativeY, relativeZ); - return Math.max(skyLight, blockLight); + public static int getLight(DataLayer lightData, BlockPos blockPos) { + return lightData != null ? lightData.get(SectionPos.sectionRelative(blockPos.getX()), SectionPos.sectionRelative(blockPos.getY()), SectionPos.sectionRelative(blockPos.getZ())) : -1; + } + + public static int getLight(DataLayer lightData, int relativeX, int relativeY, int relativeZ) { + return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - public int getLight(BlockPos blockPos, int ambientDarkness) { - int relativeX = SectionPos.sectionRelative(blockPos.getX()); - int relativeY = SectionPos.sectionRelative(blockPos.getY()); - int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); - int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) - ambientDarkness : 0; - if (skyLight == 15 || blockLights == null) { - return skyLight; - } - int blockLight = blockLights.get(relativeX, relativeY, relativeZ); - return Math.max(skyLight, blockLight); + public int getSkyLight(BlockPos blockPos, int ambientDarkness) { + return getLight(skyLights, blockPos) - ambientDarkness; + } + + public int getBlockLight(BlockPos blockPos) { + return getLight(blockLights, blockPos); } } From a44958d2ed7b2d29dd3933f0d2588bd159ab8ffb Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 22:16:09 +0100 Subject: [PATCH 130/169] No need for ambient darkness --- .../impl/network/handlers/FakeBlockHelper.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 7681e6892e..bd122da8dd 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -256,7 +256,6 @@ public record BlockLightData(int sky, int block) {} }; public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int ambientDarkness = 0; int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); List blockLookups = null; @@ -283,7 +282,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); if (hasSkyLights) { - skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness; + skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } if (hasBlockLights) { blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); @@ -314,8 +313,8 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int skyLight = sectionLight.getSkyLight(blockPos, ambientDarkness); - int blockLight = sectionLight.getBlockLight(blockPos); + int skyLight = getLight(sectionLight.skyLights(), blockPos); + int blockLight = getLight(sectionLight.blockLights(), blockPos); if (skyLight > maxSky) { maxSky = skyLight; } @@ -337,16 +336,7 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } - public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - - public int getSkyLight(BlockPos blockPos, int ambientDarkness) { - return getLight(skyLights, blockPos) - ambientDarkness; - } - - public int getBlockLight(BlockPos blockPos) { - return getLight(blockLights, blockPos); - } - } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} public static boolean coordOutOfSection(int relativeCoord) { return relativeCoord < 0 || relativeCoord > 15; From 381c9b12d09d165927e929fbf57367a108d34191 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 18 Jul 2025 20:22:14 +0100 Subject: [PATCH 131/169] Bring back some short-circuiting --- .../network/handlers/FakeBlockHelper.java | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index bd122da8dd..858cbef6cf 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -244,7 +244,10 @@ public static DataLayer getLayer(boolean has, List layers, int index) { return has ? new DataLayer(layers.get(index)) : null; } - public record BlockLightData(int sky, int block) {} + public record BlockLightData(int sky, int block) { + public static final BlockLightData MAX_BLOCK_LIGHT = new BlockLightData(0, 15); + public static final BlockLightData MAX_SKY_LIGHT = new BlockLightData(15, 0); + } public static final int[][] directions = { {0, -1, 0}, @@ -256,8 +259,15 @@ public record BlockLightData(int sky, int block) {} }; public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + boolean isSkyBright = nmsWorld.getSkyDarken() == 0; int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); + if (isSkyBright && maxSky == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (maxBlock == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } List blockLookups = null; for (int[] direction : directions) { int yOffest = direction[1]; @@ -277,7 +287,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); if (!hasBlockLights && !hasSkyLights) { - Debug.log("No lights in adjacent section"); continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); @@ -287,12 +296,16 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (hasBlockLights) { blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - Debug.log("Adjacent packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } else { skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); - Debug.log("Packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); + } + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; } if (skyLight > maxSky) { maxSky = skyLight; @@ -307,7 +320,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { - Debug.log("Getting section to cache"); + Debug.log(">>>>>>>> Getting section to cache"); LevelLightEngine lightEngine = nmsWorld.getLightEngine(); DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); @@ -315,6 +328,12 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY }); int skyLight = getLight(sectionLight.skyLights(), blockPos); int blockLight = getLight(sectionLight.blockLights(), blockPos); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } if (skyLight > maxSky) { maxSky = skyLight; } From 8f451d5a498d0d98e2e94620b4a4b4d9850df37b Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 24 Jul 2025 20:15:23 +0100 Subject: [PATCH 132/169] Handle all semi-transparent blocks' lighting --- .../network/handlers/FakeBlockHelper.java | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 858cbef6cf..b36f7d88a6 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -1,11 +1,9 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; import com.denizenscript.denizen.Denizen; -import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.FakeBlock; -import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; @@ -32,7 +30,6 @@ import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; @@ -180,19 +177,19 @@ else if (newState.isAir() && !oldState.isAir()) { blockCount--; } states.set(relativeX, relativeY, relativeZ, newState); - BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); - if (nmsBlockEntityType == null) { + BlockEntityType blockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (blockEntityType != null) { + BlockEntity createdBlockEntity = blockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); + } + if (blockEntityType == null && newState.isSolidRender()) { continue; } - BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); - createdBlockEntity.setLevel(nmsWorld); - Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); - blockEntities.add(packetBlockEntityData); BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), - lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); - Debug.log("Final data: " + estimatedLights); + lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); if (estimatedLights.block() > 0) { DataLayer blockLights; if (!hasBlock) { @@ -274,7 +271,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int neighborX = relativeX + direction[0]; int neighborY = relativeY + yOffest; int neighborZ = relativeZ + direction[2]; - if (coordOutOfSection(neighborX) || coordOutOfSection(neighborZ)) { + if (posOutOfSection(neighborX) || posOutOfSection(neighborZ)) { if (blockLookups == null) { blockLookups = new ArrayList<>(2); } @@ -282,7 +279,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY continue; } int blockLight = -1, skyLight = -1; - if (coordOutOfSection(neighborY)) { + if (posOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); @@ -320,7 +317,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { - Debug.log(">>>>>>>> Getting section to cache"); LevelLightEngine lightEngine = nmsWorld.getLightEngine(); DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); @@ -340,9 +336,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight > maxBlock) { maxBlock = blockLight; } - Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { - NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); - }, 1); } return new BlockLightData(maxSky, maxBlock); } @@ -357,7 +350,7 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} - public static boolean coordOutOfSection(int relativeCoord) { - return relativeCoord < 0 || relativeCoord > 15; + public static boolean posOutOfSection(int relativePos) { + return relativePos < 0 || relativePos > 15; } } From 1e2424a1a26a2909580a7be5e650df61079262d2 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 27 Jul 2025 13:00:52 +0100 Subject: [PATCH 133/169] Naming, comments --- .../network/handlers/FakeBlockHelper.java | 81 +++++++++---------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index b36f7d88a6..b18b4da774 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -113,7 +113,7 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); - // A list of block entities sent with the chunk data + // A list of ClientboundLevelChunkPacketData$BlockEntityInfo List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invoke(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); ListIterator blockEntitiesIterator = blockEntities.listIterator(); @@ -132,27 +132,26 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo blockEntitiesIterator.remove(); } } - // Get the original chunk data to read, and a buf of the same size to write + // Get the original chunk data to read, and a new buf of the same size to write FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); - int worldMinY = world.getMinHeight(); - int worldMaxY = world.getMaxHeight(); - int minChunkY = SectionPos.blockToSectionCoord(worldMinY); - int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + final int minChunkY = SectionPos.blockToSectionCoord(world.getMinHeight()); + final int maxChunkY = SectionPos.blockToSectionCoord(world.getMaxHeight()); Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); int blocksLit = 0, skyLit = 0; - // These are section coords, iterating through every chunk section ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); + // These are section coords, iterating through every chunk section for (int y = minChunkY; y < maxChunkY; y++) { SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); + // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) int sectionIndex = y + Math.abs(minChunkY) + 1; - boolean hasSky = false, hasBlock = false; + boolean hasSkyLight = false, hasBlockLight = false; if (lightData.getBlockYMask().get(sectionIndex)) { - hasBlock = true; + hasBlockLight = true; } if (lightData.getSkyYMask().get(sectionIndex)) { - hasSky = true; + hasSkyLight = true; } int blockCount = rawChunkData.readShort(); PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); @@ -188,13 +187,13 @@ else if (newState.isAir() && !oldState.isAir()) { continue; } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, - getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), + getLayer(hasBlockLight, lightData.getBlockUpdates(), blocksLit), getLayer(hasSkyLight, lightData.getSkyUpdates(), skyLit), lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); if (estimatedLights.block() > 0) { DataLayer blockLights; - if (!hasBlock) { + if (!hasBlockLight) { blockLights = addLayer(lightData.getBlockUpdates(), blocksLit, lightData.getBlockYMask(), lightData.getEmptyBlockYMask(), sectionIndex); - hasBlock = true; + hasBlockLight = true; } else { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); @@ -203,9 +202,9 @@ else if (newState.isAir() && !oldState.isAir()) { } if (estimatedLights.sky() > 0) { DataLayer skyLights; - if (!hasSky) { + if (!hasSkyLight) { skyLights = addLayer(lightData.getSkyUpdates(), skyLit, lightData.getSkyYMask(), lightData.getEmptySkyYMask(), sectionIndex); - hasSky = true; + hasSkyLight = true; } else { skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); @@ -215,10 +214,10 @@ else if (newState.isAir() && !oldState.isAir()) { } } } - if (hasBlock) { + if (hasBlockLight) { blocksLit++; } - if (hasSky) { + if (hasSkyLight) { skyLit++; } newChunkData.writeShort(blockCount); @@ -246,6 +245,8 @@ public record BlockLightData(int sky, int block) { public static final BlockLightData MAX_SKY_LIGHT = new BlockLightData(15, 0); } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} + public static final int[][] directions = { {0, -1, 0}, {0, 1, 0}, @@ -255,14 +256,14 @@ public record BlockLightData(int sky, int block) { {0, 0, 1} }; - public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { boolean isSkyBright = nmsWorld.getSkyDarken() == 0; - int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); - int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); - if (isSkyBright && maxSky == 15) { + int maxSkyLight = getLight(skyLights, relativeX, relativeY, relativeZ); + int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); + if (isSkyBright && maxSkyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } - if (maxBlock == 15) { + if (maxBlockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } List blockLookups = null; @@ -281,17 +282,17 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int blockLight = -1, skyLight = -1; if (posOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; - boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); - boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); - if (!hasBlockLights && !hasSkyLights) { + boolean hasSkyLight = lightData.getSkyYMask().get(adjacentSectionIndex); + boolean hasBlockLight = lightData.getBlockYMask().get(adjacentSectionIndex); + if (!hasBlockLight && !hasSkyLight) { continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - if (hasSkyLights) { - skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (hasSkyLight) { + skyLight = new DataLayer(lightData.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - if (hasBlockLights) { - blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (hasBlockLight) { + blockLight = new DataLayer(lightData.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } } else { @@ -304,15 +305,15 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } - if (skyLight > maxSky) { - maxSky = skyLight; + if (skyLight > maxSkyLight) { + maxSkyLight = skyLight; } - if (blockLight > maxBlock) { - maxBlock = blockLight; + if (blockLight > maxBlockLight) { + maxBlockLight = blockLight; } } if (blockLookups == null) { - return new BlockLightData(maxSky, maxBlock); + return new BlockLightData(maxSkyLight, maxBlockLight); } for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); @@ -330,14 +331,14 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } - if (skyLight > maxSky) { - maxSky = skyLight; + if (skyLight > maxSkyLight) { + maxSkyLight = skyLight; } - if (blockLight > maxBlock) { - maxBlock = blockLight; + if (blockLight > maxBlockLight) { + maxBlockLight = blockLight; } } - return new BlockLightData(maxSky, maxBlock); + return new BlockLightData(maxSkyLight, maxBlockLight); } public static int getLight(DataLayer lightData, BlockPos blockPos) { @@ -348,8 +349,6 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } - public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} - public static boolean posOutOfSection(int relativePos) { return relativePos < 0 || relativePos > 15; } From cc107e89f75363b32d4060f28f3335cd41be16ff Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 27 Jul 2025 18:11:20 +0100 Subject: [PATCH 134/169] Skip lighting if the existing state isn't solid --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index b18b4da774..deba5a6b61 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -183,7 +183,7 @@ else if (newState.isAir() && !oldState.isAir()) { Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); } - if (blockEntityType == null && newState.isSolidRender()) { + if (!oldState.isSolidRender() || (blockEntityType == null && newState.isSolidRender())) { continue; } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, From 95ca66c7bee945691850da9cc269146a6fe196a9 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:39:33 +0100 Subject: [PATCH 135/169] Split up fake block packet handlers --- .../handlers/DenizenNetworkManagerImpl.java | 4 +- .../packet/FakeBlocksPacketHandlers.java | 155 +++++++++--------- 2 files changed, 82 insertions(+), 77 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java index d725381ce0..76f2da81aa 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -66,7 +66,7 @@ public static > T copyPacket(T original, StreamCodec> { - Packet handlePacket(DenizenNetworkManagerImpl networkManager, T packet) throws Exception; + Packet handlePacket(DenizenNetworkManagerImpl networkManager, T packet) throws Throwable; } public static final Map>, List>> packetHandlers = new HashMap<>(); @@ -376,7 +376,7 @@ public Packet processPacketHandlersFor(Packet processShowFakeForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { - return packet; + return chunkPacket; } - try { - if (packet instanceof ClientboundLevelChunkWithLightPacket) { - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return packet; - } - int chunkX = ((ClientboundLevelChunkWithLightPacket) packet).getX(); - int chunkZ = ((ClientboundLevelChunkWithLightPacket) packet).getZ(); - ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); - List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); - if (blocks == null || blocks.isEmpty()) { - return packet; - } - return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); - } - else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return sectionBlocksUpdatePacket; - } - SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionBlocksUpdatePacket); - ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); - if (!map.byChunk.containsKey(coordinateDenizen)) { - return sectionBlocksUpdatePacket; - } - ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionBlocksUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); - LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); - BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); - short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); - BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); - OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); - BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); - for (int i = 0; i < offsetArray.length; i++) { - short offset = offsetArray[i]; - BlockPos pos = coord.relativeToBlockPos(offset); - location.setX(pos.getX()); - location.setY(pos.getY()); - location.setZ(pos.getZ()); - FakeBlock block = map.byLocation.get(location); - if (block != null) { - dataArray[i] = FakeBlockHelper.getNMSState(block); - } - } - return newPacket; - } - else if (packet instanceof ClientboundBlockUpdatePacket) { - BlockPos pos = ((ClientboundBlockUpdatePacket) packet).getPos(); - LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); - if (block != null) { - ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(((ClientboundBlockUpdatePacket) packet).getPos(), FakeBlockHelper.getNMSState(block)); - return newPacket; - } - } - else if (packet instanceof ClientboundBlockChangedAckPacket) { - // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. - /* - ClientboundBlockChangedAckPacket origPack = (ClientboundBlockChangedAckPacket) packet; - BlockPos pos = origPack.pos(); - LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); - if (block != null) { - ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(origPack.pos(), FakeBlockHelper.getNMSState(block), origPack.action(), false); - oldManager.send(newPacket, genericfuturelistener); - return true; - }*/ + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return chunkPacket; + } + int chunkX = chunkPacket.getX(); + int chunkZ = chunkPacket.getZ(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); + List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); + if (blocks == null || blocks.isEmpty()) { + return chunkPacket; + } + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocks, map); + } + + public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws IllegalAccessException { + if (FakeBlock.blocks.isEmpty()) { + return sectionUpdatePacket; + } + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return sectionUpdatePacket; + } + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); + if (!map.byChunk.containsKey(coordinateDenizen)) { + return sectionUpdatePacket; + } + ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); + BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); + short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); + BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); + OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); + BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); + for (int i = 0; i < offsetArray.length; i++) { + short offset = offsetArray[i]; + BlockPos pos = coord.relativeToBlockPos(offset); + location.setX(pos.getX()); + location.setY(pos.getY()); + location.setZ(pos.getZ()); + FakeBlock block = map.byLocation.get(location); + if (block != null) { + dataArray[i] = FakeBlockHelper.getNMSState(block); } } - catch (Throwable ex) { - Debug.echoError(ex); + return newPacket; + } + + public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { + if (FakeBlock.blocks.isEmpty()) { + return blockUpdatePacket; + } + BlockPos pos = blockUpdatePacket.getPos(); + LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); + if (block != null) { + ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); + return newPacket; + } + return blockUpdatePacket; + } + + // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. + /* + public static ClientboundBlockChangedAckPacket processBlockChangedAckPacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockChangedAckPacket blockChangedAckPacket) { + if (FakeBlock.blocks.isEmpty()) { + return blockChangedAckPacket; + } + BlockPos pos = blockChangedAckPacket.pos(); + LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); + if (block != null) { + ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(blockChangedAckPacket.pos(), FakeBlockHelper.getNMSState(block), blockChangedAckPacket.action(), false); + oldManager.send(newPacket, genericfuturelistener); + return true; } - return packet; } + */ } From b243ab5c3c5eb943cc9dd7c2ef715acef242381a Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:11:45 +0100 Subject: [PATCH 136/169] Cleanup fake block handlers --- .../packet/FakeBlocksPacketHandlers.java | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index e7e76b3723..c74d60d2c7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -7,11 +7,12 @@ import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; +import it.unimi.dsi.fastutil.shorts.ShortArraySet; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; import java.lang.reflect.Field; @@ -61,26 +62,21 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac if (!map.byChunk.containsKey(coordinateDenizen)) { return sectionUpdatePacket; } - ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); - BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); - short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); - BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); - OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); - BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); - for (int i = 0; i < offsetArray.length; i++) { - short offset = offsetArray[i]; - BlockPos pos = coord.relativeToBlockPos(offset); - location.setX(pos.getX()); - location.setY(pos.getY()); - location.setZ(pos.getZ()); + for (int i = 0; i < originalOffsetArray.length; i++) { + short offset = originalOffsetArray[i]; + location.setX(coord.relativeToBlockX(offset)); + location.setY(coord.relativeToBlockY(offset)); + location.setZ(coord.relativeToBlockZ(offset)); FakeBlock block = map.byLocation.get(location); if (block != null) { - dataArray[i] = FakeBlockHelper.getNMSState(block); + statesArray[i] = FakeBlockHelper.getNMSState(block); } } - return newPacket; + return new ClientboundSectionBlocksUpdatePacket(coord, new ShortArraySet(originalOffsetArray), statesArray); } public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { @@ -91,8 +87,7 @@ public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetwo LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); if (block != null) { - ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); - return newPacket; + return new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); } return blockUpdatePacket; } From b00bfde5da0b274f3f860fde0baa43c6853955f1 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:53:51 +0100 Subject: [PATCH 137/169] Don't make new section blocks packet unless needed --- .../network/handlers/packet/FakeBlocksPacketHandlers.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index c74d60d2c7..e5e10d49b2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -66,6 +66,7 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + boolean hasAny = false; for (int i = 0; i < originalOffsetArray.length; i++) { short offset = originalOffsetArray[i]; location.setX(coord.relativeToBlockX(offset)); @@ -74,8 +75,12 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac FakeBlock block = map.byLocation.get(location); if (block != null) { statesArray[i] = FakeBlockHelper.getNMSState(block); + hasAny = true; } } + if (!hasAny) { + return sectionUpdatePacket; + } return new ClientboundSectionBlocksUpdatePacket(coord, new ShortArraySet(originalOffsetArray), statesArray); } From 8b8bf5fd60d0b013ff3ae09053e1d2e90b13dc08 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 17:20:42 +0100 Subject: [PATCH 138/169] Section block packets: use `MethodHandle`s --- .../packet/FakeBlocksPacketHandlers.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index e5e10d49b2..7f513acd96 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -15,7 +15,7 @@ import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; -import java.lang.reflect.Field; +import java.lang.invoke.MethodHandle; import java.util.Arrays; import java.util.List; @@ -27,9 +27,9 @@ public static void registerHandlers() { DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processBlockUpdatePacket); } - public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); - public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); - public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); + public static final MethodHandle SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); + public static final MethodHandle OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); + public static final MethodHandle BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { @@ -49,7 +49,7 @@ public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPac return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocks, map); } - public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws IllegalAccessException { + public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { return sectionUpdatePacket; } @@ -57,13 +57,13 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac if (map == null) { return sectionUpdatePacket; } - SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); if (!map.byChunk.containsKey(coordinateDenizen)) { return sectionUpdatePacket; } - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); - BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + short[] originalOffsetArray = (short[]) OFFSETARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); + BlockState[] originalStatesArray = (BlockState[]) BLOCKARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); boolean hasAny = false; From 1da733192fb544620c12fdd95ba9de028ed76bb2 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:38:59 +0100 Subject: [PATCH 139/169] Minor change --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index deba5a6b61..23bb735dd7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -143,7 +143,6 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); // These are section coords, iterating through every chunk section for (int y = minChunkY; y < maxChunkY; y++) { - SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) int sectionIndex = y + Math.abs(minChunkY) + 1; boolean hasSkyLight = false, hasBlockLight = false; @@ -159,6 +158,7 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); biomes.read(rawChunkData); if (anyBlocksInSection(blocksInChunk, y)) { + SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); int minY = SectionPos.sectionToBlockCoord(y); int maxY = minY + 16; for (FakeBlock block : blocksInChunk) { From 02e15f238496db656370e4e54125affc14252cd6 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:46:31 +0100 Subject: [PATCH 140/169] Reflection fixup --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 23bb735dd7..74b1ec1912 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -224,7 +224,7 @@ else if (newState.isAir() && !oldState.isAir()) { states.write(newChunkData); biomes.write(newChunkData); } - CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); return copiedChunkPacket; } From 1b27c5e9fc4dc00f6392376bd3a33dcb7716d8c4 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 27 Sep 2025 11:16:10 +0100 Subject: [PATCH 141/169] Persist light through fake blocks between sections --- .../denizen/utilities/blocks/FakeBlock.java | 2 + .../network/handlers/FakeBlockHelper.java | 41 ++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java index 5efa823896..87cf588e40 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java @@ -75,6 +75,8 @@ public static List getFakeBlocksFor(UUID id, ChunkCoordinate chunkCoo public final ChunkCoordinate chunkCoord; public MaterialTag material; public BukkitTask currentTask = null; + public int lastBlockLight = -1; + public int lastSkyLight = -1; private FakeBlock(PlayerTag player, LocationTag location) { this.player = player; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 74b1ec1912..433632bac2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -188,7 +188,7 @@ else if (newState.isAir() && !oldState.isAir()) { } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, getLayer(hasBlockLight, lightData.getBlockUpdates(), blocksLit), getLayer(hasSkyLight, lightData.getSkyUpdates(), skyLit), - lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); + lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit, fakeBlockMap); if (estimatedLights.block() > 0) { DataLayer blockLights; if (!hasBlockLight) { @@ -199,6 +199,7 @@ else if (newState.isAir() && !oldState.isAir()) { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); } blockLights.set(relativeX, relativeY, relativeZ, estimatedLights.block()); + block.lastBlockLight = estimatedLights.block(); } if (estimatedLights.sky() > 0) { DataLayer skyLights; @@ -210,6 +211,7 @@ else if (newState.isAir() && !oldState.isAir()) { skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); } skyLights.set(relativeX, relativeY, relativeZ, estimatedLights.sky()); + block.lastSkyLight = estimatedLights.sky(); } } } @@ -256,13 +258,13 @@ public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} {0, 0, 1} }; - public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit, FakeBlock.FakeBlockMap fakeBlockMap) { boolean isSkyBright = nmsWorld.getSkyDarken() == 0; int maxSkyLight = getLight(skyLights, relativeX, relativeY, relativeZ); - int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); if (isSkyBright && maxSkyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } + int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); if (maxBlockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } @@ -290,20 +292,26 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int wrappedNeighborY = SectionPos.sectionRelative(neighborY); if (hasSkyLight) { skyLight = new DataLayer(lightData.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } } if (hasBlockLight) { blockLight = new DataLayer(lightData.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } } } else { skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); - } - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } } if (skyLight > maxSkyLight) { maxSkyLight = skyLight; @@ -324,13 +332,26 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); int skyLight = getLight(sectionLight.skyLights(), blockPos); - int blockLight = getLight(sectionLight.blockLights(), blockPos); if (isSkyBright && skyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } + int blockLight = getLight(sectionLight.blockLights(), blockPos); if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } + FakeBlock fakeBlock = fakeBlockMap.byLocation.get(new LocationTag(nmsWorld.getWorld(), blockPos.getX(), blockPos.getY(), blockPos.getZ())); + if (fakeBlock.lastSkyLight > skyLight) { + skyLight = fakeBlock.lastSkyLight; + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + } + if (fakeBlock.lastBlockLight > blockLight) { + blockLight = fakeBlock.lastBlockLight; + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } + } if (skyLight > maxSkyLight) { maxSkyLight = skyLight; } From 9198b995acb2e822b42839b1c37002d89fbe50b7 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 27 Sep 2025 11:23:09 +0100 Subject: [PATCH 142/169] No `EnumMap` --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 433632bac2..1b0f11f0d0 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -52,7 +52,7 @@ public class FakeBlockHelper { public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); - public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); + public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); static { try { From 378c527d194b343bb9d2396dcfc5c9501abf3bef Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 3 Nov 2025 13:31:32 +0000 Subject: [PATCH 143/169] Breakpoint commit --- .../utilities/blocks/ChunkCoordinate.java | 8 +- .../denizen/utilities/blocks/FakeBlock.java | 38 +- .../nms/v1_21/ReflectionMappingsInfo.java | 2 +- .../network/handlers/FakeBlockHelper.java | 350 ++++++------------ .../packet/FakeBlocksPacketHandlers.java | 34 +- 5 files changed, 183 insertions(+), 249 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/ChunkCoordinate.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/ChunkCoordinate.java index 17ac185ff9..229e2aa1e4 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/ChunkCoordinate.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/ChunkCoordinate.java @@ -7,6 +7,10 @@ public class ChunkCoordinate { + public static int blockToChunkCoord(int coordinate) { + return coordinate >> 4; + } + public final int x; public final int z; @@ -20,8 +24,8 @@ public ChunkCoordinate(int _x, int _z, String _worldName) { } public ChunkCoordinate(Location location) { - x = location.getBlockX() >> 4; - z = location.getBlockZ() >> 4; + x = blockToChunkCoord(location.getBlockX()); + z = blockToChunkCoord(location.getBlockZ()); worldName = location.getWorld().getName(); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java index 87cf588e40..86eccab4a4 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java @@ -8,6 +8,8 @@ import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; import com.denizenscript.denizencore.objects.core.DurationTag; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.scheduler.BukkitRunnable; @@ -24,7 +26,7 @@ public static class FakeBlockMap { public Map byLocation = new HashMap<>(); - public Map> byChunk = new HashMap<>(); + public Map>> byChunk = new HashMap<>(); public FakeBlock getOrAdd(PlayerTag player, LocationTag location) { location = new LocationTag(location.getBlockX(), location.getBlockY(), location.getBlockZ(), location.getWorldName()); @@ -34,19 +36,27 @@ public FakeBlock getOrAdd(PlayerTag player, LocationTag location) { } block = new FakeBlock(player, location); byLocation.put(location, block); - List chunkBlocks = byChunk.computeIfAbsent(block.chunkCoord, k -> new ArrayList<>()); + List chunkBlocks = byChunk.computeIfAbsent(block.chunkCoord, k -> new Int2ObjectOpenHashMap<>()).computeIfAbsent(block.sectionY, k -> new ArrayList<>()); chunkBlocks.add(block); return block; } public void remove(FakeBlock block) { if (byLocation.remove(block.location) != null) { - List chunkBlocks = byChunk.get(block.chunkCoord); - if (chunkBlocks != null) { - chunkBlocks.remove(block); - if (chunkBlocks.isEmpty()) { - byChunk.remove(block.chunkCoord); - } + Int2ObjectMap> chunkBlocks = byChunk.get(block.chunkCoord); + if (chunkBlocks == null) { + return; + } + List sectionBlocks = chunkBlocks.get(block.sectionY); + if (sectionBlocks == null) { + return; + } + sectionBlocks.remove(block); + if (sectionBlocks.isEmpty()) { + chunkBlocks.remove(block.sectionY); + } + if (chunkBlocks.isEmpty()) { + byChunk.remove(block.chunkCoord); } } } @@ -67,21 +77,27 @@ public static List getFakeBlocksFor(UUID id, ChunkCoordinate chunkCoo if (map == null) { return null; } - return map.byChunk.get(chunkCoord); + Int2ObjectMap> chunkMap = map.byChunk.get(chunkCoord); + if (chunkMap == null) { + return null; + } + List blocks = new ArrayList<>(); + chunkMap.values().forEach(blocks::addAll); + return blocks; } public final PlayerTag player; public final LocationTag location; public final ChunkCoordinate chunkCoord; + public final int sectionY; public MaterialTag material; public BukkitTask currentTask = null; - public int lastBlockLight = -1; - public int lastSkyLight = -1; private FakeBlock(PlayerTag player, LocationTag location) { this.player = player; this.location = location; this.chunkCoord = new ChunkCoordinate(location); + this.sectionY = ChunkCoordinate.blockToChunkCoord(location.getBlockY()); } public static void showFakeBlockTo(List players, LocationTag location, MaterialTag material, DurationTag duration, boolean sendNow) { diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index a1e50ac985..29969e0898 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -128,5 +128,5 @@ public class ReflectionMappingsInfo { public static String ServerRecipeBook_addHighlight_method = "e"; // net.minecraft.world.level.block.entity.BlockEntityType - public static String BlockEntityType_validBlocks = "Y"; + public static String BlockEntityType_validBlocks = "aa"; } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 1b0f11f0d0..79f02fd525 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -7,36 +7,33 @@ import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import net.minecraft.core.BlockPos; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.shorts.*; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.network.protocol.game.ClientboundLightUpdatePacketData; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.LightLayer; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LightBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.chunk.Strategy; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockType; -import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlockType; +import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; @@ -52,7 +49,9 @@ public class FakeBlockHelper { public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); + public static final PalettedContainer EMPTY_BLOCKS_CONTAINER = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); + public static final BlockState MAX_LIGHT_LIGHT_BLOCK = Blocks.LIGHT.defaultBlockState().setValue(LightBlock.LEVEL, 15); static { try { @@ -110,11 +109,11 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { + public static Packet handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, Int2ObjectMap> blocksBySection, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); // A list of ClientboundLevelChunkPacketData$BlockEntityInfo - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invoke(copiedChunkPacket.getChunkData()); + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invokeExact(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); ListIterator blockEntitiesIterator = blockEntities.listIterator(); while (blockEntitiesIterator.hasNext()) { @@ -123,8 +122,8 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo int y = (int) CHUNKDATA_BLOCKENTITYINFO_Y.invoke(blockEnt); int relativeX = SectionPos.sectionRelative(xz >> 4); int relativeZ = SectionPos.sectionRelative(xz); - int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; - int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; + int x = SectionPos.sectionToBlockCoord(chunkX, relativeX); + int z = SectionPos.sectionToBlockCoord(chunkZ, relativeZ); location.setX(x); location.setY(y); location.setZ(z); @@ -132,245 +131,136 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo blockEntitiesIterator.remove(); } } + List> packets = new ArrayList<>(blocksBySection.size() + 1); + packets.add(copiedChunkPacket); + // Get the original chunk data to read, and a new buf of the same size to write FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); final int minChunkY = SectionPos.blockToSectionCoord(world.getMinHeight()); final int maxChunkY = SectionPos.blockToSectionCoord(world.getMaxHeight()); Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); - int blocksLit = 0, skyLit = 0; ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); - Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); - // These are section coords, iterating through every chunk section - for (int y = minChunkY; y < maxChunkY; y++) { + BitSet blockLightMask = lightData.getBlockYMask(), blockNoLightMask = lightData.getEmptyBlockYMask(), skyLightMask = lightData.getSkyYMask(), skyNoLightMask = lightData.getEmptySkyYMask(); + int blockLitSections = 0, skyLitSections = 0; + for (int chunkY = minChunkY; chunkY < maxChunkY; chunkY++) { + int blockCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); + states.read(rawChunkData); + PalettedContainer> biomes = new PalettedContainer<>(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry.asHolderIdMap())); + biomes.read(rawChunkData); + List fakeBlocksInSection = blocksBySection.get(chunkY); // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) - int sectionIndex = y + Math.abs(minChunkY) + 1; - boolean hasSkyLight = false, hasBlockLight = false; - if (lightData.getBlockYMask().get(sectionIndex)) { + int sectionIndex = chunkY - minChunkY + 1; + boolean hasBlockLight = false, hasSkyLight = false; + if (blockLightMask.get(sectionIndex)) { hasBlockLight = true; } - if (lightData.getSkyYMask().get(sectionIndex)) { + if (skyLightMask.get(sectionIndex)) { hasSkyLight = true; } - int blockCount = rawChunkData.readShort(); - PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - states.read(rawChunkData); - PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); - biomes.read(rawChunkData); - if (anyBlocksInSection(blocksInChunk, y)) { - SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); - int minY = SectionPos.sectionToBlockCoord(y); - int maxY = minY + 16; - for (FakeBlock block : blocksInChunk) { - int blockY = block.location.getBlockY(); - if (blockY >= minY && blockY < maxY && block.material != null) { - int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); - int relativeY = SectionPos.sectionRelative(blockY); - int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); - BlockState oldState = states.get(relativeX, relativeY, relativeZ); - BlockState newState = getNMSState(block); - if (oldState.isAir() && !newState.isAir()) { - blockCount++; - } - else if (newState.isAir() && !oldState.isAir()) { - blockCount--; - } - states.set(relativeX, relativeY, relativeZ, newState); - BlockEntityType blockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); - if (blockEntityType != null) { - BlockEntity createdBlockEntity = blockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); - Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); - blockEntities.add(packetBlockEntityData); - } - if (!oldState.isSolidRender() || (blockEntityType == null && newState.isSolidRender())) { - continue; - } - BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, - getLayer(hasBlockLight, lightData.getBlockUpdates(), blocksLit), getLayer(hasSkyLight, lightData.getSkyUpdates(), skyLit), - lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit, fakeBlockMap); - if (estimatedLights.block() > 0) { - DataLayer blockLights; - if (!hasBlockLight) { - blockLights = addLayer(lightData.getBlockUpdates(), blocksLit, lightData.getBlockYMask(), lightData.getEmptyBlockYMask(), sectionIndex); - hasBlockLight = true; - } - else { - blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); - } - blockLights.set(relativeX, relativeY, relativeZ, estimatedLights.block()); - block.lastBlockLight = estimatedLights.block(); - } - if (estimatedLights.sky() > 0) { - DataLayer skyLights; - if (!hasSkyLight) { - skyLights = addLayer(lightData.getSkyUpdates(), skyLit, lightData.getSkyYMask(), lightData.getEmptySkyYMask(), sectionIndex); - hasSkyLight = true; - } - else { - skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); + if (fakeBlocksInSection != null) { + List> lightPatch = null; + DataLayer blockLayer = null, skyLayer = null; + if (hasBlockLight) { + blockLightMask.clear(sectionIndex); + blockLayer = new DataLayer(lightData.getBlockUpdates().remove(blockLitSections)); + hasBlockLight = false; + // TODO: light sources from outside the section? Can try adding all lit blocks to the patch, maybe just put the entire section in a patch again atp + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + if (blockLayer.get(x, y, z) > 0) { + BlockState state = states.get(x, y, z); + if (state.isAir()) { + continue; + } + if (lightPatch == null) { + lightPatch = new ArrayList<>(); + } +// Debug.log("Adding lit block " + state.getBlockHolder().getRegisteredName() + " at " + x + ',' + y + ',' + z); + // Based on SectionPos#sectionRelativePos + int offset = x << 8 | z << 4 | y << 0; + lightPatch.add(ShortObjectPair.of((short) offset, Blocks.AIR.defaultBlockState())); + lightPatch.add(ShortObjectPair.of((short) offset, state)); + blockCount--; + states.set(x, y, x, Blocks.AIR.defaultBlockState()); + } } - skyLights.set(relativeX, relativeY, relativeZ, estimatedLights.sky()); - block.lastSkyLight = estimatedLights.sky(); } } } - } - if (hasBlockLight) { - blocksLit++; - } - if (hasSkyLight) { - skyLit++; - } - newChunkData.writeShort(blockCount); - states.write(newChunkData); - biomes.write(newChunkData); - } - CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); - return copiedChunkPacket; - } - - public static DataLayer addLayer(List layers, int index, BitSet litSections, BitSet unlitSections, int sectionIndex) { - DataLayer newLayer = new DataLayer(); - layers.add(index, newLayer.getData()); - litSections.set(sectionIndex); - unlitSections.clear(sectionIndex); - return newLayer; - } - - public static DataLayer getLayer(boolean has, List layers, int index) { - return has ? new DataLayer(layers.get(index)) : null; - } - - public record BlockLightData(int sky, int block) { - public static final BlockLightData MAX_BLOCK_LIGHT = new BlockLightData(0, 15); - public static final BlockLightData MAX_SKY_LIGHT = new BlockLightData(15, 0); - } - - public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} - - public static final int[][] directions = { - {0, -1, 0}, - {0, 1, 0}, - {-1, 0, 0}, - {1, 0, 0}, - {0, 0, -1}, - {0, 0, 1} - }; - - public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit, FakeBlock.FakeBlockMap fakeBlockMap) { - boolean isSkyBright = nmsWorld.getSkyDarken() == 0; - int maxSkyLight = getLight(skyLights, relativeX, relativeY, relativeZ); - if (isSkyBright && maxSkyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } - int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); - if (maxBlockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; - } - List blockLookups = null; - for (int[] direction : directions) { - int yOffest = direction[1]; - int neighborX = relativeX + direction[0]; - int neighborY = relativeY + yOffest; - int neighborZ = relativeZ + direction[2]; - if (posOutOfSection(neighborX) || posOutOfSection(neighborZ)) { - if (blockLookups == null) { - blockLookups = new ArrayList<>(2); - } - blockLookups.add(new BlockPos(sectionPos.minBlockX() + neighborX, sectionPos.minBlockY() + neighborY, sectionPos.minBlockZ() + neighborZ)); - continue; - } - int blockLight = -1, skyLight = -1; - if (posOutOfSection(neighborY)) { - int adjacentSectionIndex = sectionIndex + yOffest; - boolean hasSkyLight = lightData.getSkyYMask().get(adjacentSectionIndex); - boolean hasBlockLight = lightData.getBlockYMask().get(adjacentSectionIndex); - if (!hasBlockLight && !hasSkyLight) { - continue; + else { + blockNoLightMask.clear(sectionIndex); } - int wrappedNeighborY = SectionPos.sectionRelative(neighborY); if (hasSkyLight) { - skyLight = new DataLayer(lightData.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } + skyLightMask.clear(sectionIndex); + skyLayer = new DataLayer(lightData.getSkyUpdates().remove(skyLitSections)); + hasSkyLight = false; } - if (hasBlockLight) { - blockLight = new DataLayer(lightData.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; - } + else { + skyNoLightMask.clear(sectionIndex); } - } - else { - skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; + int size = fakeBlocksInSection.size(); + short[] offsets = new short[size]; + BlockState[] statesArr = new BlockState[size]; + for (int blockIndex = 0; blockIndex < size; blockIndex++) { + FakeBlock fakeBlock = fakeBlocksInSection.get(blockIndex); + int relativeX = SectionPos.sectionRelative(fakeBlock.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(fakeBlock.location.getBlockY()); + int relativeZ = SectionPos.sectionRelative(fakeBlock.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); + BlockState newState = ((CraftBlockData) fakeBlock.material.getModernData()).getState(); + short sectionRelativePos = SectionPos.sectionRelativePos(CraftLocation.toBlockPosition(fakeBlock.location)); + offsets[blockIndex] = sectionRelativePos; + statesArr[blockIndex] = newState; + int maxLight = Math.max( + skyLayer != null ? skyLayer.get(relativeX, relativeY, relativeZ) : 0, + blockLayer != null ? blockLayer.get(relativeX, relativeY, relativeZ) : 0 + ); + if (!oldState.isAir()) { + blockCount--; + states.set(relativeX, relativeY, relativeZ, Blocks.AIR.defaultBlockState()); + if (maxLight <= 0 && !newState.isSolidRender()) { + if (lightPatch == null) { + lightPatch = new ArrayList<>(); + } + lightPatch.add(ShortObjectPair.of(sectionRelativePos, MAX_LIGHT_LIGHT_BLOCK)); + } + } } - blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; + SectionPos sectionPos = SectionPos.of(chunkX, chunkY, chunkZ); + if (lightPatch != null) { + int lightCount = lightPatch.size(); + short[] lightOffsets = new short[lightCount]; + BlockState[] lightStates = new BlockState[lightCount]; + for (int i = 0; i < lightCount; i++) { + ShortObjectPair pair = lightPatch.get(i); + lightOffsets[i] = pair.leftShort(); + lightStates[i] = pair.right(); + } + packets.add(new ClientboundSectionBlocksUpdatePacket(sectionPos, new ShortArraySet(lightOffsets), lightStates)); } + packets.add(new ClientboundSectionBlocksUpdatePacket(sectionPos, new ShortArraySet(offsets), statesArr)); } - if (skyLight > maxSkyLight) { - maxSkyLight = skyLight; - } - if (blockLight > maxBlockLight) { - maxBlockLight = blockLight; - } - } - if (blockLookups == null) { - return new BlockLightData(maxSkyLight, maxBlockLight); - } - for (BlockPos blockPos : blockLookups) { - SectionPos containingSection = SectionPos.of(blockPos); - SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { - LevelLightEngine lightEngine = nmsWorld.getLightEngine(); - DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); - DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); - return new SectionLightCache(sectionBlockLights, sectionSkyLights); - }); - int skyLight = getLight(sectionLight.skyLights(), blockPos); - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } - int blockLight = getLight(sectionLight.blockLights(), blockPos); - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; - } - FakeBlock fakeBlock = fakeBlockMap.byLocation.get(new LocationTag(nmsWorld.getWorld(), blockPos.getX(), blockPos.getY(), blockPos.getZ())); - if (fakeBlock.lastSkyLight > skyLight) { - skyLight = fakeBlock.lastSkyLight; - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } + if (hasBlockLight) { + blockLitSections++; } - if (fakeBlock.lastBlockLight > blockLight) { - blockLight = fakeBlock.lastBlockLight; - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; - } + if (hasSkyLight) { + skyLitSections++; } - if (skyLight > maxSkyLight) { - maxSkyLight = skyLight; + newChunkData.writeShort(blockCount); + if (blockCount > 0) { + states.write(newChunkData); +// Debug.log("Writing non-empty data" + (fakeBlocksInSection != null ? " FAKE!!" : "")); } - if (blockLight > maxBlockLight) { - maxBlockLight = blockLight; + else { +// Debug.log("WRITING EMPTY CONTAINER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + (fakeBlocksInSection != null ? " FAKE!!" : "")); + EMPTY_BLOCKS_CONTAINER.write(newChunkData); } + biomes.write(newChunkData); } - return new BlockLightData(maxSkyLight, maxBlockLight); - } - - public static int getLight(DataLayer lightData, BlockPos blockPos) { - return lightData != null ? lightData.get(SectionPos.sectionRelative(blockPos.getX()), SectionPos.sectionRelative(blockPos.getY()), SectionPos.sectionRelative(blockPos.getZ())) : -1; - } - - public static int getLight(DataLayer lightData, int relativeX, int relativeY, int relativeZ) { - return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; - } - - public static boolean posOutOfSection(int relativePos) { - return relativePos < 0 || relativePos > 15; + CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); + return new ClientboundBundlePacket(packets); } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 7f513acd96..a3a7ed91c1 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -1,19 +1,27 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; +import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.FakeBlockHelper; import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.shorts.ShortArraySet; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Bukkit; +import org.bukkit.World; import java.lang.invoke.MethodHandle; import java.util.Arrays; @@ -31,7 +39,7 @@ public static void registerHandlers() { public static final MethodHandle OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); public static final MethodHandle BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); - public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { + public static Packet processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { return chunkPacket; } @@ -41,12 +49,28 @@ public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPac } int chunkX = chunkPacket.getX(); int chunkZ = chunkPacket.getZ(); - ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); - List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); - if (blocks == null || blocks.isEmpty()) { + World world = networkManager.player.level().getWorld(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, world.getName()); + Int2ObjectMap> blocksBySection = map.byChunk.get(chunkCoord); + if (blocksBySection == null || blocksBySection.isEmpty()) { return chunkPacket; } - return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocks, map); + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocksBySection, map); +// List> packets = new ArrayList<>(blocksBySection.size() + 1); +// packets.add(mappedPacket); +// for (Int2ObjectMap.Entry> entry : blocksBySection.int2ObjectEntrySet()) { +// List fakeBlocks = entry.getValue(); +// int size = fakeBlocks.size(); +// short[] offsets = new short[size]; +// BlockState[] states = new BlockState[size]; +// for (int i = 0; i < size; i++) { +// FakeBlock fakeBlock = fakeBlocks.get(i); +// offsets[i] = SectionPos.sectionRelativePos(CraftLocation.toBlockPosition(fakeBlock.location)); +// states[i] = ((CraftBlockData) fakeBlock.material.getModernData()).getState(); +// } +// packets.add(new ClientboundSectionBlocksUpdatePacket(SectionPos.of(chunkX, entry.getIntKey(), chunkZ), new ShortArraySet(offsets), states)); +// } +// return new ClientboundBundlePacket(packets); } public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws Throwable { From 45033ce6a9de228cb13abf4ee6fe316a6cf105a9 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:11:42 +0000 Subject: [PATCH 144/169] Some more lighting edge-cases --- .../network/handlers/FakeBlockHelper.java | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 79f02fd525..751dc11257 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -8,7 +8,8 @@ import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.shorts.*; +import it.unimi.dsi.fastutil.shorts.ShortArraySet; +import it.unimi.dsi.fastutil.shorts.ShortObjectPair; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; @@ -51,7 +52,7 @@ public class FakeBlockHelper { public static final PalettedContainer EMPTY_BLOCKS_CONTAINER = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); - public static final BlockState MAX_LIGHT_LIGHT_BLOCK = Blocks.LIGHT.defaultBlockState().setValue(LightBlock.LEVEL, 15); + public static final BlockState MAX_LIGHT_LIGHT_BLOCK = Blocks.LIGHT.defaultBlockState().setValue(LightBlock.LEVEL, 15), AIR = Blocks.AIR.defaultBlockState(); static { try { @@ -160,29 +161,28 @@ public static Packet handleMapChunkPacket(World world, hasSkyLight = true; } if (fakeBlocksInSection != null) { - List> lightPatch = null; + List> lightPatch = new ArrayList<>(); DataLayer blockLayer = null, skyLayer = null; if (hasBlockLight) { blockLightMask.clear(sectionIndex); blockLayer = new DataLayer(lightData.getBlockUpdates().remove(blockLitSections)); hasBlockLight = false; - // TODO: light sources from outside the section? Can try adding all lit blocks to the patch, maybe just put the entire section in a patch again atp for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { - if (blockLayer.get(x, y, z) > 0) { - BlockState state = states.get(x, y, z); - if (state.isAir()) { - continue; - } - if (lightPatch == null) { - lightPatch = new ArrayList<>(); - } -// Debug.log("Adding lit block " + state.getBlockHolder().getRegisteredName() + " at " + x + ',' + y + ',' + z); - // Based on SectionPos#sectionRelativePos - int offset = x << 8 | z << 4 | y << 0; - lightPatch.add(ShortObjectPair.of((short) offset, Blocks.AIR.defaultBlockState())); - lightPatch.add(ShortObjectPair.of((short) offset, state)); + BlockState state = states.get(x, y, z); + boolean isAir = state.isAir(); + if (isAir && (y == 0 || states.get(x, y - 1, z).isAir())) { + continue; + } + if (!isAir && blockLayer.get(x, y, z) == 0) { + continue; + } + // Based on SectionPos#sectionRelativePos + short offset = (short) (x << 8 | z << 4 | y << 0); + lightPatch.add(ShortObjectPair.of(offset, isAir ? MAX_LIGHT_LIGHT_BLOCK : AIR)); + lightPatch.add(ShortObjectPair.of(offset, state)); + if (!isAir) { blockCount--; states.set(x, y, x, Blocks.AIR.defaultBlockState()); } @@ -222,15 +222,12 @@ public static Packet handleMapChunkPacket(World world, blockCount--; states.set(relativeX, relativeY, relativeZ, Blocks.AIR.defaultBlockState()); if (maxLight <= 0 && !newState.isSolidRender()) { - if (lightPatch == null) { - lightPatch = new ArrayList<>(); - } lightPatch.add(ShortObjectPair.of(sectionRelativePos, MAX_LIGHT_LIGHT_BLOCK)); } } } SectionPos sectionPos = SectionPos.of(chunkX, chunkY, chunkZ); - if (lightPatch != null) { + if (!lightPatch.isEmpty()) { int lightCount = lightPatch.size(); short[] lightOffsets = new short[lightCount]; BlockState[] lightStates = new BlockState[lightCount]; @@ -252,10 +249,8 @@ public static Packet handleMapChunkPacket(World world, newChunkData.writeShort(blockCount); if (blockCount > 0) { states.write(newChunkData); -// Debug.log("Writing non-empty data" + (fakeBlocksInSection != null ? " FAKE!!" : "")); } else { -// Debug.log("WRITING EMPTY CONTAINER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + (fakeBlocksInSection != null ? " FAKE!!" : "")); EMPTY_BLOCKS_CONTAINER.write(newChunkData); } biomes.write(newChunkData); From d7d915c14f944603222af963dc7cf6c9780413a0 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 29 Nov 2025 21:32:47 +0000 Subject: [PATCH 145/169] Handle missing light data on first chunk load --- .../network/handlers/FakeBlockHelper.java | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 751dc11257..447464371b 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -3,6 +3,7 @@ import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -53,6 +54,7 @@ public class FakeBlockHelper { public static final PalettedContainer EMPTY_BLOCKS_CONTAINER = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); public static final BlockState MAX_LIGHT_LIGHT_BLOCK = Blocks.LIGHT.defaultBlockState().setValue(LightBlock.LEVEL, 15), AIR = Blocks.AIR.defaultBlockState(); + public static final byte[] MAX_LIGHT_SECTION = new DataLayer(15).getData(), MIN_LIGHT_SECTION = new DataLayer(0).getData(); static { try { @@ -113,6 +115,8 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new public static Packet handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, Int2ObjectMap> blocksBySection, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); + // TODO pass coord? + boolean isNaturalLoad = !FakeBlock.scheduled.containsKey(new ChunkCoordinate(chunkX, chunkZ, world.getName())); // A list of ClientboundLevelChunkPacketData$BlockEntityInfo List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invokeExact(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); @@ -144,6 +148,7 @@ public static Packet handleMapChunkPacket(World world, ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); BitSet blockLightMask = lightData.getBlockYMask(), blockNoLightMask = lightData.getEmptyBlockYMask(), skyLightMask = lightData.getSkyYMask(), skyNoLightMask = lightData.getEmptySkyYMask(); int blockLitSections = 0, skyLitSections = 0; + boolean foundFirstSkyLight = false; for (int chunkY = minChunkY; chunkY < maxChunkY; chunkY++) { int blockCount = rawChunkData.readShort(); PalettedContainer states = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); @@ -163,10 +168,40 @@ public static Packet handleMapChunkPacket(World world, if (fakeBlocksInSection != null) { List> lightPatch = new ArrayList<>(); DataLayer blockLayer = null, skyLayer = null; + Debug.log("--------------"); + Debug.log("Has block light: " + hasBlockLight); + Debug.log("Has sky light: " + hasSkyLight); + if (hasSkyLight) { + skyLightMask.clear(sectionIndex); + skyLayer = new DataLayer(lightData.getSkyUpdates().remove(skyLitSections)); + hasSkyLight = false; + if (!foundFirstSkyLight) { + Debug.log(">>> Found first sky light"); + } + foundFirstSkyLight = true; + } + else { + skyNoLightMask.clear(sectionIndex); + } + if (isNaturalLoad) { + Debug.log(">>> Adding " + (foundFirstSkyLight ? "bright" : "dark") + " sky light"); + lightData.getSkyUpdates().add(skyLitSections, foundFirstSkyLight ? MAX_LIGHT_SECTION : MIN_LIGHT_SECTION); + skyLightMask.set(sectionIndex); + hasSkyLight = true; + skyLayer = new DataLayer(lightData.getSkyUpdates().get(skyLitSections)); + } if (hasBlockLight) { blockLightMask.clear(sectionIndex); blockLayer = new DataLayer(lightData.getBlockUpdates().remove(blockLitSections)); hasBlockLight = false; + } + else { + blockNoLightMask.clear(sectionIndex); + } + Debug.log("Post has block light: " + blockLightMask.get(sectionIndex)); + Debug.log("Post has sky light: " + skyLightMask.get(sectionIndex)); + Debug.log("--------------"); + if (blockLayer != null || skyLayer != null) { for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { @@ -175,7 +210,7 @@ public static Packet handleMapChunkPacket(World world, if (isAir && (y == 0 || states.get(x, y - 1, z).isAir())) { continue; } - if (!isAir && blockLayer.get(x, y, z) == 0) { + if (!isAir && (blockLayer == null || blockLayer.get(x, y, z) == 0)) { continue; } // Based on SectionPos#sectionRelativePos @@ -184,23 +219,12 @@ public static Packet handleMapChunkPacket(World world, lightPatch.add(ShortObjectPair.of(offset, state)); if (!isAir) { blockCount--; - states.set(x, y, x, Blocks.AIR.defaultBlockState()); + states.set(x, y, z, AIR); } } } } } - else { - blockNoLightMask.clear(sectionIndex); - } - if (hasSkyLight) { - skyLightMask.clear(sectionIndex); - skyLayer = new DataLayer(lightData.getSkyUpdates().remove(skyLitSections)); - hasSkyLight = false; - } - else { - skyNoLightMask.clear(sectionIndex); - } int size = fakeBlocksInSection.size(); short[] offsets = new short[size]; BlockState[] statesArr = new BlockState[size]; From 752c8ca094cbb88cb6bb9fa3f9206a08ec5b1548 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 12 Jul 2025 23:55:39 +0100 Subject: [PATCH 146/169] Initial cleanups & optimizations --- .../nms/v1_21/ReflectionMappingsInfo.java | 69 ++--- .../network/handlers/FakeBlockHelper.java | 278 ++++++------------ .../packet/FakeBlocksPacketHandlers.java | 190 +++++------- 3 files changed, 207 insertions(+), 330 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 29969e0898..0fbee1ebbe 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -8,42 +8,38 @@ public class ReflectionMappingsInfo { public static String BlockBehaviour_explosionResistance = "G"; // net.minecraft.core.MappedRegistry - public static String MappedRegistry_registrationInfos = "h"; + public static String MappedRegistry_frozen = "l"; + public static String MappedRegistry_unregisteredIntrusiveHolders = "m"; // 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"; + public static String Entity_onGround = "bb"; + public static String Entity_DATA_SHARED_FLAGS_ID = "az"; + public static String Entity_DATA_CUSTOM_NAME = "bl"; + public static String Entity_DATA_CUSTOM_NAME_VISIBLE = "bm"; // net.minecraft.world.entity.LivingEntity - public static String LivingEntity_attackStrengthTicker = "bz"; - public static String LivingEntity_autoSpinAttackTicks = "bW"; + public static String LivingEntity_attackStrengthTicker = "bo"; + public static String LivingEntity_autoSpinAttackTicks = "bL"; public static String LivingEntity_setLivingEntityFlag_method = "c"; // net.minecraft.world.entity.player.Player - public static String Player_DATA_PLAYER_ABSORPTION_ID = "b"; + public static String Player_DATA_PLAYER_ABSORPTION_ID = "d"; + public static String Player_DATA_PLAYER_MODE_CUSTOMISATION = "cg"; // net.minecraft.server.level.ServerPlayer - public static String ServerPlayer_respawnConfig = "dr"; + public static String ServerPlayer_respawnConfig = "dA"; // net.minecraft.world.entity.monster.EnderMan - public static String EnderMan_DATA_CREEPY = "cx"; + public static String EnderMan_DATA_CREEPY = "cl"; - // net.minecraft.world.entity.monster.zombie.Zombie - public static String Zombie_inWaterTime = "cL"; + // net.minecraft.world.entity.monster.Zombie + public static String Zombie_inWaterTime = "cA"; // 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"; + public static String Level_isClientSide = "C"; // net.minecraft.server.level.ThreadedLevelLightEngine public static String ThreadedLevelLightEngine_addTask_method = "a"; @@ -59,19 +55,22 @@ public class ReflectionMappingsInfo { // 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.world.level.biome.BiomeSpecialEffects + public static String BiomeSpecialEffects_foliageColorOverride = "f"; + public static String BiomeSpecialEffects_fogColor = "b"; + public static String BiomeSpecialEffects_waterFogColor = "d"; // net.minecraft.network.Connection - public static String Connection_receiving = "h"; - public static String Connection_packetListener = "n"; + public static String Connection_receiving = "k"; + public static String Connection_packetListener = "q"; // 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"; + public static String ServerGamePacketListenerImpl_aboveGroundTickCount = "J"; + public static String ServerGamePacketListenerImpl_aboveGroundVehicleTickCount = "L"; + public static String ServerGamePacketListenerImpl_awaitingPositionFromClient = "F"; + public static String ServerGamePacketListenerImpl_awaitingTeleport = "G"; + public static String ServerGamePacketListenerImpl_chunkSender = "g"; // net.minecraft.server.network.ServerCommonPacketListenerImpl public static String ServerCommonPacketListenerImpl_connection = "e"; @@ -98,10 +97,6 @@ public class ReflectionMappingsInfo { // net.minecraft.network.protocol.game.ClientboundSetPassengersPacket public static String ClientboundSetPassengersPacket_passengers = "c"; - // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData - public static String ClientboundLevelChunkPacketData_buffer = "d"; - public static String ClientboundLevelChunkPacketData_blockEntitiesData = "e"; - // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo public static String ClientboundLevelChunkPacketDataBlockEntityInfo_create_method = "a"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "c"; @@ -118,8 +113,14 @@ public class ReflectionMappingsInfo { // 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"; + public static String ServerLevel_sleepStatus = "R"; // net.minecraft.world.item.AdventureModePredicate public static String AdventureModePredicate_predicates = "g"; @@ -128,5 +129,5 @@ public class ReflectionMappingsInfo { public static String ServerRecipeBook_addHighlight_method = "e"; // net.minecraft.world.level.block.entity.BlockEntityType - public static String BlockEntityType_validBlocks = "aa"; + public static String BlockEntityType_validBlocks = "Y"; } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 447464371b..286b092508 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -3,63 +3,58 @@ import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; -import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.shorts.ShortArraySet; -import it.unimi.dsi.fastutil.shorts.ShortObjectPair; -import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.LightBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.Strategy; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R6.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R6.block.CraftBlockType; -import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R6.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockType; +import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; import java.lang.invoke.MethodHandle; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.*; public class FakeBlockHelper { - public static final MethodHandle CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_blockEntitiesData, List.class); - public static final MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getSetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_buffer, byte[].class); - public static final Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; - public static final MethodHandle CHUNKDATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); - public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); - public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); - public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); + public static Field CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getFirstOfType(List.class); + public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; + public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); + public static final MethodHandle CHUNK_DATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); + public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); + public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); + public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); + public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); + public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 3).findFirst().get(); + public static Field BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).get(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); - public static final PalettedContainer EMPTY_BLOCKS_CONTAINER = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); - public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); - public static final BlockState MAX_LIGHT_LIGHT_BLOCK = Blocks.LIGHT.defaultBlockState().setValue(LightBlock.LEVEL, 15), AIR = Blocks.AIR.defaultBlockState(); - public static final byte[] MAX_LIGHT_SECTION = new DataLayer(15).getData(), MIN_LIGHT_SECTION = new DataLayer(0).getData(); + public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); static { try { for (BlockEntityType nmsBlockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.invokeExact(nmsBlockEntityType); + Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.get(nmsBlockEntityType); for (Block validBlock : validBlocks) { MATERIAL_BLOCK_ENTITY_TYPES.put(CraftBlockType.minecraftToBukkit(validBlock), nmsBlockEntityType); } @@ -112,174 +107,83 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static Packet handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, Int2ObjectMap> blocksBySection, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { - ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); - copyPacketPaperPatch(copiedChunkPacket); - // TODO pass coord? - boolean isNaturalLoad = !FakeBlock.scheduled.containsKey(new ChunkCoordinate(chunkX, chunkZ, world.getName())); - // A list of ClientboundLevelChunkPacketData$BlockEntityInfo - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invokeExact(copiedChunkPacket.getChunkData()); - LocationTag location = new LocationTag(world, 0, 0, 0); - ListIterator blockEntitiesIterator = blockEntities.listIterator(); - while (blockEntitiesIterator.hasNext()) { - Object blockEnt = blockEntitiesIterator.next(); - int xz = (int) CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.invoke(blockEnt); - int y = (int) CHUNKDATA_BLOCKENTITYINFO_Y.invoke(blockEnt); - int relativeX = SectionPos.sectionRelative(xz >> 4); - int relativeZ = SectionPos.sectionRelative(xz); - int x = SectionPos.sectionToBlockCoord(chunkX, relativeX); - int z = SectionPos.sectionToBlockCoord(chunkZ, relativeZ); - location.setX(x); - location.setY(y); - location.setZ(z); - if (fakeBlockMap.byLocation.containsKey(location)) { - blockEntitiesIterator.remove(); - } - } - List> packets = new ArrayList<>(blocksBySection.size() + 1); - packets.add(copiedChunkPacket); - - // Get the original chunk data to read, and a new buf of the same size to write - FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); - FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); - final int minChunkY = SectionPos.blockToSectionCoord(world.getMinHeight()); - final int maxChunkY = SectionPos.blockToSectionCoord(world.getMaxHeight()); - Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); - ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); - BitSet blockLightMask = lightData.getBlockYMask(), blockNoLightMask = lightData.getEmptyBlockYMask(), skyLightMask = lightData.getSkyYMask(), skyNoLightMask = lightData.getEmptySkyYMask(); - int blockLitSections = 0, skyLitSections = 0; - boolean foundFirstSkyLight = false; - for (int chunkY = minChunkY; chunkY < maxChunkY; chunkY++) { - int blockCount = rawChunkData.readShort(); - PalettedContainer states = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); - states.read(rawChunkData); - PalettedContainer> biomes = new PalettedContainer<>(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry.asHolderIdMap())); - biomes.read(rawChunkData); - List fakeBlocksInSection = blocksBySection.get(chunkY); - // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) - int sectionIndex = chunkY - minChunkY + 1; - boolean hasBlockLight = false, hasSkyLight = false; - if (blockLightMask.get(sectionIndex)) { - hasBlockLight = true; - } - if (skyLightMask.get(sectionIndex)) { - hasSkyLight = true; - } - if (fakeBlocksInSection != null) { - List> lightPatch = new ArrayList<>(); - DataLayer blockLayer = null, skyLayer = null; - Debug.log("--------------"); - Debug.log("Has block light: " + hasBlockLight); - Debug.log("Has sky light: " + hasSkyLight); - if (hasSkyLight) { - skyLightMask.clear(sectionIndex); - skyLayer = new DataLayer(lightData.getSkyUpdates().remove(skyLitSections)); - hasSkyLight = false; - if (!foundFirstSkyLight) { - Debug.log(">>> Found first sky light"); - } - foundFirstSkyLight = true; - } - else { - skyNoLightMask.clear(sectionIndex); - } - if (isNaturalLoad) { - Debug.log(">>> Adding " + (foundFirstSkyLight ? "bright" : "dark") + " sky light"); - lightData.getSkyUpdates().add(skyLitSections, foundFirstSkyLight ? MAX_LIGHT_SECTION : MIN_LIGHT_SECTION); - skyLightMask.set(sectionIndex); - hasSkyLight = true; - skyLayer = new DataLayer(lightData.getSkyUpdates().get(skyLitSections)); - } - if (hasBlockLight) { - blockLightMask.clear(sectionIndex); - blockLayer = new DataLayer(lightData.getBlockUpdates().remove(blockLitSections)); - hasBlockLight = false; - } - else { - blockNoLightMask.clear(sectionIndex); + public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) { + try { + ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(copiedChunkPacket); + // A list of block entities sent with the chunk data + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + LocationTag location = new LocationTag(world, 0, 0, 0); + ListIterator blockEntitiesIterator = blockEntities.listIterator(); + while (blockEntitiesIterator.hasNext()) { + Object blockEnt = blockEntitiesIterator.next(); + int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); + int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int relativeX = SectionPos.sectionRelative(xz >> 4); + int relativeZ = SectionPos.sectionRelative(xz); + int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; + int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; + location.setX(x); + location.setY(y); + location.setZ(z); + if (fakeBlockMap.byLocation.containsKey(location)) { + blockEntitiesIterator.remove(); } - Debug.log("Post has block light: " + blockLightMask.get(sectionIndex)); - Debug.log("Post has sky light: " + skyLightMask.get(sectionIndex)); - Debug.log("--------------"); - if (blockLayer != null || skyLayer != null) { - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - BlockState state = states.get(x, y, z); - boolean isAir = state.isAir(); - if (isAir && (y == 0 || states.get(x, y - 1, z).isAir())) { - continue; - } - if (!isAir && (blockLayer == null || blockLayer.get(x, y, z) == 0)) { - continue; - } - // Based on SectionPos#sectionRelativePos - short offset = (short) (x << 8 | z << 4 | y << 0); - lightPatch.add(ShortObjectPair.of(offset, isAir ? MAX_LIGHT_LIGHT_BLOCK : AIR)); - lightPatch.add(ShortObjectPair.of(offset, state)); - if (!isAir) { - blockCount--; - states.set(x, y, z, AIR); - } + } + // Get the original chunk data to read, and a buf of the same size to write + FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); + int worldMinY = world.getMinHeight(); + int worldMaxY = world.getMaxHeight(); + int minChunkY = SectionPos.blockToSectionCoord(worldMinY); + int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + // These are section coords, iterating through every chunk section + for (int y = minChunkY; y < maxChunkY; y++) { + int blockCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + states.read(rawChunkData); + PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + biomes.read(rawChunkData); + if (anyBlocksInSection(blocksInChunk, y)) { + int minY = SectionPos.sectionToBlockCoord(y); + int maxY = minY + 16; + for (FakeBlock block : blocksInChunk) { + int blockY = block.location.getBlockY(); + if (blockY >= minY && blockY < maxY && block.material != null) { + int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(blockY); + int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); + BlockState newState = getNMSState(block); + if (oldState.isAir() && !newState.isAir()) { + blockCount++; } + else if (newState.isAir() && !oldState.isAir()) { + blockCount--; + } + states.set(relativeX, relativeY, relativeZ, newState); + BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (nmsBlockEntityType == null) { + continue; + } + BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); } } } - int size = fakeBlocksInSection.size(); - short[] offsets = new short[size]; - BlockState[] statesArr = new BlockState[size]; - for (int blockIndex = 0; blockIndex < size; blockIndex++) { - FakeBlock fakeBlock = fakeBlocksInSection.get(blockIndex); - int relativeX = SectionPos.sectionRelative(fakeBlock.location.getBlockX()); - int relativeY = SectionPos.sectionRelative(fakeBlock.location.getBlockY()); - int relativeZ = SectionPos.sectionRelative(fakeBlock.location.getBlockZ()); - BlockState oldState = states.get(relativeX, relativeY, relativeZ); - BlockState newState = ((CraftBlockData) fakeBlock.material.getModernData()).getState(); - short sectionRelativePos = SectionPos.sectionRelativePos(CraftLocation.toBlockPosition(fakeBlock.location)); - offsets[blockIndex] = sectionRelativePos; - statesArr[blockIndex] = newState; - int maxLight = Math.max( - skyLayer != null ? skyLayer.get(relativeX, relativeY, relativeZ) : 0, - blockLayer != null ? blockLayer.get(relativeX, relativeY, relativeZ) : 0 - ); - if (!oldState.isAir()) { - blockCount--; - states.set(relativeX, relativeY, relativeZ, Blocks.AIR.defaultBlockState()); - if (maxLight <= 0 && !newState.isSolidRender()) { - lightPatch.add(ShortObjectPair.of(sectionRelativePos, MAX_LIGHT_LIGHT_BLOCK)); - } - } - } - SectionPos sectionPos = SectionPos.of(chunkX, chunkY, chunkZ); - if (!lightPatch.isEmpty()) { - int lightCount = lightPatch.size(); - short[] lightOffsets = new short[lightCount]; - BlockState[] lightStates = new BlockState[lightCount]; - for (int i = 0; i < lightCount; i++) { - ShortObjectPair pair = lightPatch.get(i); - lightOffsets[i] = pair.leftShort(); - lightStates[i] = pair.right(); - } - packets.add(new ClientboundSectionBlocksUpdatePacket(sectionPos, new ShortArraySet(lightOffsets), lightStates)); - } - packets.add(new ClientboundSectionBlocksUpdatePacket(sectionPos, new ShortArraySet(offsets), statesArr)); - } - if (hasBlockLight) { - blockLitSections++; - } - if (hasSkyLight) { - skyLitSections++; - } - newChunkData.writeShort(blockCount); - if (blockCount > 0) { + newChunkData.writeShort(blockCount); states.write(newChunkData); + biomes.write(newChunkData); } - else { - EMPTY_BLOCKS_CONTAINER.write(newChunkData); - } - biomes.write(newChunkData); + CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + return copiedChunkPacket; + } + catch (Throwable ex) { + Debug.echoError(ex); } - CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); - return new ClientboundBundlePacket(packets); + return null; } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index a3a7ed91c1..52ed0f191d 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -1,140 +1,112 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; -import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.FakeBlockHelper; import com.denizenscript.denizen.objects.LocationTag; -import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.shorts.ShortArraySet; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; +import net.minecraft.network.protocol.game.*; import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.Bukkit; -import org.bukkit.World; -import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; public class FakeBlocksPacketHandlers { public static void registerHandlers() { - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelChunkWithLightPacket.class, FakeBlocksPacketHandlers::processLevelChunkWithLightPacket); - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSectionBlocksUpdatePacket.class, FakeBlocksPacketHandlers::processSectionBlocksUpdatePacket); - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processBlockUpdatePacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelChunkWithLightPacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSectionBlocksUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); } - public static final MethodHandle SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); - public static final MethodHandle OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); - public static final MethodHandle BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); + public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); + public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); + public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); - public static Packet processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { + public static Packet processShowFakeForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { if (FakeBlock.blocks.isEmpty()) { - return chunkPacket; + return packet; } - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return chunkPacket; - } - int chunkX = chunkPacket.getX(); - int chunkZ = chunkPacket.getZ(); - World world = networkManager.player.level().getWorld(); - ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, world.getName()); - Int2ObjectMap> blocksBySection = map.byChunk.get(chunkCoord); - if (blocksBySection == null || blocksBySection.isEmpty()) { - return chunkPacket; - } - return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocksBySection, map); -// List> packets = new ArrayList<>(blocksBySection.size() + 1); -// packets.add(mappedPacket); -// for (Int2ObjectMap.Entry> entry : blocksBySection.int2ObjectEntrySet()) { -// List fakeBlocks = entry.getValue(); -// int size = fakeBlocks.size(); -// short[] offsets = new short[size]; -// BlockState[] states = new BlockState[size]; -// for (int i = 0; i < size; i++) { -// FakeBlock fakeBlock = fakeBlocks.get(i); -// offsets[i] = SectionPos.sectionRelativePos(CraftLocation.toBlockPosition(fakeBlock.location)); -// states[i] = ((CraftBlockData) fakeBlock.material.getModernData()).getState(); -// } -// packets.add(new ClientboundSectionBlocksUpdatePacket(SectionPos.of(chunkX, entry.getIntKey(), chunkZ), new ShortArraySet(offsets), states)); -// } -// return new ClientboundBundlePacket(packets); - } - - public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws Throwable { - if (FakeBlock.blocks.isEmpty()) { - return sectionUpdatePacket; - } - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return sectionUpdatePacket; - } - SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); - ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); - if (!map.byChunk.containsKey(coordinateDenizen)) { - return sectionUpdatePacket; - } - short[] originalOffsetArray = (short[]) OFFSETARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); - BlockState[] originalStatesArray = (BlockState[]) BLOCKARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); - BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); - LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); - boolean hasAny = false; - for (int i = 0; i < originalOffsetArray.length; i++) { - short offset = originalOffsetArray[i]; - location.setX(coord.relativeToBlockX(offset)); - location.setY(coord.relativeToBlockY(offset)); - location.setZ(coord.relativeToBlockZ(offset)); - FakeBlock block = map.byLocation.get(location); - if (block != null) { - statesArray[i] = FakeBlockHelper.getNMSState(block); - hasAny = true; + try { + if (packet instanceof ClientboundLevelChunkWithLightPacket) { + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return packet; + } + int chunkX = ((ClientboundLevelChunkWithLightPacket) packet).getX(); + int chunkZ = ((ClientboundLevelChunkWithLightPacket) packet).getZ(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); + List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); + if (blocks == null || blocks.isEmpty()) { + return packet; + } + ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); + return newPacket; + } + else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return sectionBlocksUpdatePacket; + } + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionBlocksUpdatePacket); + ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); + if (!map.byChunk.containsKey(coordinateDenizen)) { + return sectionBlocksUpdatePacket; + } + ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionBlocksUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); + BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); + short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); + BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); + OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); + BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); + for (int i = 0; i < offsetArray.length; i++) { + short offset = offsetArray[i]; + BlockPos pos = coord.relativeToBlockPos(offset); + location.setX(pos.getX()); + location.setY(pos.getY()); + location.setZ(pos.getZ()); + FakeBlock block = map.byLocation.get(location); + if (block != null) { + dataArray[i] = FakeBlockHelper.getNMSState(block); + } + } + return newPacket; + } + else if (packet instanceof ClientboundBlockUpdatePacket) { + BlockPos pos = ((ClientboundBlockUpdatePacket) packet).getPos(); + LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); + if (block != null) { + ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(((ClientboundBlockUpdatePacket) packet).getPos(), FakeBlockHelper.getNMSState(block)); + return newPacket; + } + } + else if (packet instanceof ClientboundBlockChangedAckPacket) { + // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. + /* + ClientboundBlockChangedAckPacket origPack = (ClientboundBlockChangedAckPacket) packet; + BlockPos pos = origPack.pos(); + LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); + if (block != null) { + ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(origPack.pos(), FakeBlockHelper.getNMSState(block), origPack.action(), false); + oldManager.send(newPacket, genericfuturelistener); + return true; + }*/ } } - if (!hasAny) { - return sectionUpdatePacket; - } - return new ClientboundSectionBlocksUpdatePacket(coord, new ShortArraySet(originalOffsetArray), statesArray); - } - - public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { - if (FakeBlock.blocks.isEmpty()) { - return blockUpdatePacket; - } - BlockPos pos = blockUpdatePacket.getPos(); - LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); - if (block != null) { - return new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); - } - return blockUpdatePacket; - } - - // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. - /* - public static ClientboundBlockChangedAckPacket processBlockChangedAckPacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockChangedAckPacket blockChangedAckPacket) { - if (FakeBlock.blocks.isEmpty()) { - return blockChangedAckPacket; - } - BlockPos pos = blockChangedAckPacket.pos(); - LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); - if (block != null) { - ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(blockChangedAckPacket.pos(), FakeBlockHelper.getNMSState(block), blockChangedAckPacket.action(), false); - oldManager.send(newPacket, genericfuturelistener); - return true; + catch (Throwable ex) { + Debug.echoError(ex); } + return packet; } - */ } From 2ecc45abaf2b10eeef1e1701109da307ce9ae79b Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 12 Jul 2025 23:57:54 +0100 Subject: [PATCH 147/169] Remove unnecessary `try` --- .../network/handlers/FakeBlockHelper.java | 138 +++++++++--------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 286b092508..a01beda1ce 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -107,83 +107,77 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) { - try { - ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); - copyPacketPaperPatch(copiedChunkPacket); - // A list of block entities sent with the chunk data - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); - LocationTag location = new LocationTag(world, 0, 0, 0); - ListIterator blockEntitiesIterator = blockEntities.listIterator(); - while (blockEntitiesIterator.hasNext()) { - Object blockEnt = blockEntitiesIterator.next(); - int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); - int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); - int relativeX = SectionPos.sectionRelative(xz >> 4); - int relativeZ = SectionPos.sectionRelative(xz); - int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; - int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; - location.setX(x); - location.setY(y); - location.setZ(z); - if (fakeBlockMap.byLocation.containsKey(location)) { - blockEntitiesIterator.remove(); - } + public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { + ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(copiedChunkPacket); + // A list of block entities sent with the chunk data + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + LocationTag location = new LocationTag(world, 0, 0, 0); + ListIterator blockEntitiesIterator = blockEntities.listIterator(); + while (blockEntitiesIterator.hasNext()) { + Object blockEnt = blockEntitiesIterator.next(); + int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); + int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int relativeX = SectionPos.sectionRelative(xz >> 4); + int relativeZ = SectionPos.sectionRelative(xz); + int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; + int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; + location.setX(x); + location.setY(y); + location.setZ(z); + if (fakeBlockMap.byLocation.containsKey(location)) { + blockEntitiesIterator.remove(); } - // Get the original chunk data to read, and a buf of the same size to write - FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); - FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); - int worldMinY = world.getMinHeight(); - int worldMaxY = world.getMaxHeight(); - int minChunkY = SectionPos.blockToSectionCoord(worldMinY); - int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); - Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); - // These are section coords, iterating through every chunk section - for (int y = minChunkY; y < maxChunkY; y++) { - int blockCount = rawChunkData.readShort(); - PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - states.read(rawChunkData); - PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); - biomes.read(rawChunkData); - if (anyBlocksInSection(blocksInChunk, y)) { - int minY = SectionPos.sectionToBlockCoord(y); - int maxY = minY + 16; - for (FakeBlock block : blocksInChunk) { - int blockY = block.location.getBlockY(); - if (blockY >= minY && blockY < maxY && block.material != null) { - int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); - int relativeY = SectionPos.sectionRelative(blockY); - int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); - BlockState oldState = states.get(relativeX, relativeY, relativeZ); - BlockState newState = getNMSState(block); - if (oldState.isAir() && !newState.isAir()) { - blockCount++; - } - else if (newState.isAir() && !oldState.isAir()) { - blockCount--; - } - states.set(relativeX, relativeY, relativeZ, newState); - BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); - if (nmsBlockEntityType == null) { - continue; - } - BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); - Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); - blockEntities.add(packetBlockEntityData); + } + // Get the original chunk data to read, and a buf of the same size to write + FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); + int worldMinY = world.getMinHeight(); + int worldMaxY = world.getMaxHeight(); + int minChunkY = SectionPos.blockToSectionCoord(worldMinY); + int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + // These are section coords, iterating through every chunk section + for (int y = minChunkY; y < maxChunkY; y++) { + int blockCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + states.read(rawChunkData); + PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + biomes.read(rawChunkData); + if (anyBlocksInSection(blocksInChunk, y)) { + int minY = SectionPos.sectionToBlockCoord(y); + int maxY = minY + 16; + for (FakeBlock block : blocksInChunk) { + int blockY = block.location.getBlockY(); + if (blockY >= minY && blockY < maxY && block.material != null) { + int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(blockY); + int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); + BlockState newState = getNMSState(block); + if (oldState.isAir() && !newState.isAir()) { + blockCount++; + } + else if (newState.isAir() && !oldState.isAir()) { + blockCount--; } + states.set(relativeX, relativeY, relativeZ, newState); + BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (nmsBlockEntityType == null) { + continue; + } + BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); } } - newChunkData.writeShort(blockCount); - states.write(newChunkData); - biomes.write(newChunkData); } - CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); - return copiedChunkPacket; - } - catch (Throwable ex) { - Debug.echoError(ex); + newChunkData.writeShort(blockCount); + states.write(newChunkData); + biomes.write(newChunkData); } - return null; + CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + return copiedChunkPacket; } } From 84db05eb2eeef755926f82954812b23508524e5c Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 13 Jul 2025 00:27:59 +0100 Subject: [PATCH 148/169] Cleanup reflection --- .../nms/v1_21/ReflectionMappingsInfo.java | 10 +++---- .../network/handlers/FakeBlockHelper.java | 29 ++++++++----------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 0fbee1ebbe..18d5f6e051 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -97,6 +97,10 @@ public class ReflectionMappingsInfo { // net.minecraft.network.protocol.game.ClientboundSetPassengersPacket public static String ClientboundSetPassengersPacket_passengers = "c"; + // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData + public static String ClientboundLevelChunkPacketData_buffer = "d"; + public static String ClientboundLevelChunkPacketData_blockEntitiesData = "e"; + // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo public static String ClientboundLevelChunkPacketDataBlockEntityInfo_create_method = "a"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "c"; @@ -113,12 +117,6 @@ public class ReflectionMappingsInfo { // 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 = "R"; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index a01beda1ce..61a876b8af 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -11,7 +11,6 @@ import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; @@ -32,29 +31,25 @@ import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; import java.lang.invoke.MethodHandle; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.*; public class FakeBlockHelper { - public static Field CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getFirstOfType(List.class); - public static Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; - public static MethodHandle CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR = ReflectionHelper.getConstructor(ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0], int.class, int.class, BlockEntityType.class, CompoundTag.class); - public static final MethodHandle CHUNK_DATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); - public static MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkPacketData.class, byte[].class); - public static Field CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); - public static Field CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).get(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); - public static MethodHandle CHUNKPACKET_CHUNKDATA_SETTER = ReflectionHelper.getFinalSetterForFirstOfType(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class); - public static Constructor PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 3).findFirst().get(); - public static Field BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).get(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); + public static final MethodHandle CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_blockEntitiesData, List.class); + public static final MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getSetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_buffer, byte[].class); + public static final Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; + public static final MethodHandle CHUNKDATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); + public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); + public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); + public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); static { try { for (BlockEntityType nmsBlockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.get(nmsBlockEntityType); + Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.invokeExact(nmsBlockEntityType); for (Block validBlock : validBlocks) { MATERIAL_BLOCK_ENTITY_TYPES.put(CraftBlockType.minecraftToBukkit(validBlock), nmsBlockEntityType); } @@ -111,13 +106,13 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); // A list of block entities sent with the chunk data - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.get(copiedChunkPacket.getChunkData()); + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invoke(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); ListIterator blockEntitiesIterator = blockEntities.listIterator(); while (blockEntitiesIterator.hasNext()) { Object blockEnt = blockEntitiesIterator.next(); - int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); - int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); + int xz = (int) CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.invoke(blockEnt); + int y = (int) CHUNKDATA_BLOCKENTITYINFO_Y.invoke(blockEnt); int relativeX = SectionPos.sectionRelative(xz >> 4); int relativeZ = SectionPos.sectionRelative(xz); int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; @@ -168,7 +163,7 @@ else if (newState.isAir() && !oldState.isAir()) { } BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); - Object packetBlockEntityData = CHUNK_DATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); } } From 78974d309489de5ea6d137894f5d5e9ae4746053 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:01:41 +0100 Subject: [PATCH 149/169] Initial work on fake block light levels --- .../network/handlers/FakeBlockHelper.java | 144 ++++++++++++++++++ .../packet/FakeBlocksPacketHandlers.java | 3 +- 2 files changed, 145 insertions(+), 2 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 61a876b8af..9723a3ca96 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -1,12 +1,17 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; import com.denizenscript.denizen.Denizen; +import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.FakeBlock; +import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; @@ -14,6 +19,9 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.network.protocol.game.ClientboundLightUpdatePacketData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; @@ -21,7 +29,10 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; @@ -132,8 +143,20 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo int minChunkY = SectionPos.blockToSectionCoord(worldMinY); int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + int blocksLit = 0, skyLit = 0; // These are section coords, iterating through every chunk section + ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); + Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); for (int y = minChunkY; y < maxChunkY; y++) { + SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); + int sectionIndex = y + Math.abs(minChunkY) + 1; + boolean hasSky = false, hasBlock = false; + if (lightData.getBlockYMask().get(sectionIndex)) { + hasBlock = true; + } + if (lightData.getSkyYMask().get(sectionIndex)) { + hasSky = true; + } int blockCount = rawChunkData.readShort(); PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); states.read(rawChunkData); @@ -165,9 +188,29 @@ else if (newState.isAir() && !oldState.isAir()) { createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); + DataLayer blockLights; + if (!hasBlock) { + Debug.log(">>>>>>>>>>>>>>>>>>> No light data, adding"); + blockLights = new DataLayer(); + lightData.getBlockUpdates().add(blocksLit, blockLights.getData()); + lightData.getBlockYMask().set(sectionIndex); + lightData.getEmptyBlockYMask().clear(sectionIndex); + hasBlock = true; + } + else { + blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + } + DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); + blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, world, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } + if (hasBlock) { + blocksLit++; + } + if (hasSky) { + skyLit++; + } newChunkData.writeShort(blockCount); states.write(newChunkData); biomes.write(newChunkData); @@ -175,4 +218,105 @@ else if (newState.isAir() && !oldState.isAir()) { CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); return copiedChunkPacket; } + + public static final int[][] directions = { + {0, -1, 0}, + {0, 1, 0}, + {-1, 0, 0}, + {1, 0, 0}, + {0, 0, -1}, + {0, 0, 1} + }; + + public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + int maxLight = Math.max(blockLights.get(relativeX, relativeY, relativeZ), skyLights.get(relativeX, relativeY, relativeZ)); + if (maxLight == 15) { + return 15; + } + List blockLookups = null; + for (int[] direction : directions) { + int yOffest = direction[1]; + int neighborX = relativeX + direction[0]; + int neighborY = relativeY + yOffest; + int neighborZ = relativeZ + direction[2]; + if (coordOutOfSection(neighborX) || coordOutOfSection(neighborZ)) { + if (blockLookups == null) { + blockLookups = new ArrayList<>(2); + } + blockLookups.add(new BlockPos(sectionPos.minBlockX() + neighborX, sectionPos.minBlockY() + neighborY, sectionPos.minBlockZ() + neighborZ)); + continue; + } + int light; + if (coordOutOfSection(neighborY)) { + int adjacentSectionIndex = sectionIndex + yOffest; + boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); + boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); + if (!hasBlockLights && !hasSkyLights) { + Debug.log("No lights in adjacent section"); + continue; + } + int wrappedNeighborY = SectionPos.sectionRelative(neighborY); + light = Math.max( + hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0, + hasBlockLights ? new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0 + ); + Debug.log("Adjacent packet light: " + light); + } + else { + light = Math.max(blockLights.get(neighborX, neighborY, neighborZ), skyLights.get(neighborX, neighborY, neighborZ)); + Debug.log("Packet light: " + light); + } + if (light == 15) { + return 15; + } + if (light > maxLight) { + maxLight = light; + } + } + if (blockLookups == null) { + return maxLight; + } + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + for (BlockPos blockPos : blockLookups) { + SectionPos containingSection = SectionPos.of(blockPos); + SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { + Debug.log("Getting section to cache"); + LevelLightEngine lightEngine = nmsWorld.getLightEngine(); + DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); + DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); + return new SectionLightCache(sectionBlockLights, sectionSkyLights); + }); + int light = sectionLight.getLight(blockPos); + Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { + NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); + }, 1); + Debug.log("Block light: " + light); + if (light == 15) { + return 15; + } + if (light > maxLight) { + maxLight = light; + } + } + return maxLight; + } + + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { + + public int getLight(BlockPos blockPos) { + int relativeX = SectionPos.sectionRelative(blockPos.getX()); + int relativeY = SectionPos.sectionRelative(blockPos.getY()); + int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); + int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) : 0; + if (skyLight == 15) { + return skyLight; + } + int blockLight = blockLights != null ? blockLights.get(relativeX, relativeY, relativeZ) : 0; + return Math.max(skyLight, blockLight); + } + } + + public static boolean coordOutOfSection(int relativeCoord) { + return relativeCoord < 0 || relativeCoord > 15; + } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 52ed0f191d..f8b31d4052 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -47,8 +47,7 @@ public static Packet processShowFakeForPacket(DenizenN if (blocks == null || blocks.isEmpty()) { return packet; } - ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); - return newPacket; + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); } else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); From 16e448a3c82194461a1d0d302385d09f06e47001 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:33:58 +0100 Subject: [PATCH 150/169] Minor optimization to `max` handling --- .../network/handlers/FakeBlockHelper.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 9723a3ca96..2f0180bce4 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -229,7 +229,7 @@ else if (newState.isAir() && !oldState.isAir()) { }; public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int maxLight = Math.max(blockLights.get(relativeX, relativeY, relativeZ), skyLights.get(relativeX, relativeY, relativeZ)); + int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); if (maxLight == 15) { return 15; } @@ -256,14 +256,16 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - light = Math.max( - hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0, - hasBlockLights ? new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0 - ); + int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0; + if (skyLight == 15 || !hasBlockLights) { + return skyLight; + } + int blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + light = Math.max(skyLight, blockLight); Debug.log("Adjacent packet light: " + light); } else { - light = Math.max(blockLights.get(neighborX, neighborY, neighborZ), skyLights.get(neighborX, neighborY, neighborZ)); + light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights); Debug.log("Packet light: " + light); } if (light == 15) { @@ -301,6 +303,15 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat return maxLight; } + public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData) { + int skyLight = skyLightData.get(relativeX, relativeY, relativeZ); + if (skyLight == 15) { + return 15; + } + int blockLight = blockLightData.get(relativeX, relativeY, relativeZ); + return Math.max(skyLight, blockLight); + } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { public int getLight(BlockPos blockPos) { From 9eb49fbe0541c8bafc9e7833f41f53e593934a9f Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:35:19 +0100 Subject: [PATCH 151/169] Pass in NMS world --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 2f0180bce4..e5362bf056 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -185,7 +185,8 @@ else if (newState.isAir() && !oldState.isAir()) { continue; } BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + createdBlockEntity.setLevel(nmsWorld); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); DataLayer blockLights; @@ -201,7 +202,7 @@ else if (newState.isAir() && !oldState.isAir()) { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); } DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); - blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, world, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); + blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } @@ -228,7 +229,7 @@ else if (newState.isAir() && !oldState.isAir()) { {0, 0, 1} }; - public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, World world, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); if (maxLight == 15) { return 15; @@ -278,7 +279,6 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat if (blockLookups == null) { return maxLight; } - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { From ecc24324fb6ca68388c08ccfc26ced87ffa311f6 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:25:47 +0100 Subject: [PATCH 152/169] Account for sky darkness --- .../network/handlers/FakeBlockHelper.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index e5362bf056..fa5bffabbb 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -230,7 +230,8 @@ else if (newState.isAir() && !oldState.isAir()) { }; public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights); + int ambientDarkness = nmsWorld.getSkyDarken(); + int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights, ambientDarkness); if (maxLight == 15) { return 15; } @@ -257,7 +258,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) : 0; + int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness : 0; if (skyLight == 15 || !hasBlockLights) { return skyLight; } @@ -266,7 +267,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat Debug.log("Adjacent packet light: " + light); } else { - light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights); + light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights, ambientDarkness); Debug.log("Packet light: " + light); } if (light == 15) { @@ -288,7 +289,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int light = sectionLight.getLight(blockPos); + int light = sectionLight.getLight(blockPos, ambientDarkness); Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); }, 1); @@ -303,8 +304,8 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat return maxLight; } - public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData) { - int skyLight = skyLightData.get(relativeX, relativeY, relativeZ); + public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData, int ambientDarkness) { + int skyLight = skyLightData.get(relativeX, relativeY, relativeZ) - ambientDarkness; if (skyLight == 15) { return 15; } @@ -314,15 +315,15 @@ public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLaye public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - public int getLight(BlockPos blockPos) { + public int getLight(BlockPos blockPos, int ambientDarkness) { int relativeX = SectionPos.sectionRelative(blockPos.getX()); int relativeY = SectionPos.sectionRelative(blockPos.getY()); int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); - int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) : 0; - if (skyLight == 15) { + int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) - ambientDarkness : 0; + if (skyLight == 15 || blockLights == null) { return skyLight; } - int blockLight = blockLights != null ? blockLights.get(relativeX, relativeY, relativeZ) : 0; + int blockLight = blockLights.get(relativeX, relativeY, relativeZ); return Math.max(skyLight, blockLight); } } From 6a8a7e3bf4d37e48c7b79ec58e35c0935e4db76d Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 22:13:50 +0100 Subject: [PATCH 153/169] Set both block and sky light for smoother visuals --- .../network/handlers/FakeBlockHelper.java | 136 ++++++++++-------- 1 file changed, 78 insertions(+), 58 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index fa5bffabbb..7681e6892e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -189,20 +189,32 @@ else if (newState.isAir() && !oldState.isAir()) { createdBlockEntity.setLevel(nmsWorld); Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); - DataLayer blockLights; - if (!hasBlock) { - Debug.log(">>>>>>>>>>>>>>>>>>> No light data, adding"); - blockLights = new DataLayer(); - lightData.getBlockUpdates().add(blocksLit, blockLights.getData()); - lightData.getBlockYMask().set(sectionIndex); - lightData.getEmptyBlockYMask().clear(sectionIndex); - hasBlock = true; + BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, + getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), + lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); + Debug.log("Final data: " + estimatedLights); + if (estimatedLights.block() > 0) { + DataLayer blockLights; + if (!hasBlock) { + blockLights = addLayer(lightData.getBlockUpdates(), blocksLit, lightData.getBlockYMask(), lightData.getEmptyBlockYMask(), sectionIndex); + hasBlock = true; + } + else { + blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + } + blockLights.set(relativeX, relativeY, relativeZ, estimatedLights.block()); } - else { - blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); + if (estimatedLights.sky() > 0) { + DataLayer skyLights; + if (!hasSky) { + skyLights = addLayer(lightData.getSkyUpdates(), skyLit, lightData.getSkyYMask(), lightData.getEmptySkyYMask(), sectionIndex); + hasSky = true; + } + else { + skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); + } + skyLights.set(relativeX, relativeY, relativeZ, estimatedLights.sky()); } - DataLayer skyLights = hasSky ? new DataLayer(lightData.getSkyUpdates().get(skyLit)) : new DataLayer(); - blockLights.set(relativeX, relativeY, relativeZ, getEstimatedLightLevel(relativeX, relativeY, relativeZ, blockLights, skyLights, lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit)); } } } @@ -220,6 +232,20 @@ else if (newState.isAir() && !oldState.isAir()) { return copiedChunkPacket; } + public static DataLayer addLayer(List layers, int index, BitSet litSections, BitSet unlitSections, int sectionIndex) { + DataLayer newLayer = new DataLayer(); + layers.add(index, newLayer.getData()); + litSections.set(sectionIndex); + unlitSections.clear(sectionIndex); + return newLayer; + } + + public static DataLayer getLayer(boolean has, List layers, int index) { + return has ? new DataLayer(layers.get(index)) : null; + } + + public record BlockLightData(int sky, int block) {} + public static final int[][] directions = { {0, -1, 0}, {0, 1, 0}, @@ -229,12 +255,10 @@ else if (newState.isAir() && !oldState.isAir()) { {0, 0, 1} }; - public static int getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int ambientDarkness = nmsWorld.getSkyDarken(); - int maxLight = maxLight(relativeX, relativeY, relativeZ, blockLights, skyLights, ambientDarkness); - if (maxLight == 15) { - return 15; - } + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + int ambientDarkness = 0; + int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); + int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); List blockLookups = null; for (int[] direction : directions) { int yOffest = direction[1]; @@ -248,7 +272,7 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat blockLookups.add(new BlockPos(sectionPos.minBlockX() + neighborX, sectionPos.minBlockY() + neighborY, sectionPos.minBlockZ() + neighborZ)); continue; } - int light; + int blockLight = -1, skyLight = -1; if (coordOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); @@ -258,27 +282,28 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - int skyLight = hasSkyLights ? new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness : 0; - if (skyLight == 15 || !hasBlockLights) { - return skyLight; + if (hasSkyLights) { + skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness; + } + if (hasBlockLights) { + blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - int blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); - light = Math.max(skyLight, blockLight); - Debug.log("Adjacent packet light: " + light); + Debug.log("Adjacent packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } else { - light = maxLight(neighborX, neighborY, neighborZ, blockLights, skyLights, ambientDarkness); - Debug.log("Packet light: " + light); + skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); + blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); + Debug.log("Packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } - if (light == 15) { - return 15; + if (skyLight > maxSky) { + maxSky = skyLight; } - if (light > maxLight) { - maxLight = light; + if (blockLight > maxBlock) { + maxBlock = blockLight; } } if (blockLookups == null) { - return maxLight; + return new BlockLightData(maxSky, maxBlock); } for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); @@ -289,42 +314,37 @@ public static int getEstimatedLightLevel(int relativeX, int relativeY, int relat DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int light = sectionLight.getLight(blockPos, ambientDarkness); + int skyLight = sectionLight.getSkyLight(blockPos, ambientDarkness); + int blockLight = sectionLight.getBlockLight(blockPos); + if (skyLight > maxSky) { + maxSky = skyLight; + } + if (blockLight > maxBlock) { + maxBlock = blockLight; + } Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); }, 1); - Debug.log("Block light: " + light); - if (light == 15) { - return 15; - } - if (light > maxLight) { - maxLight = light; - } } - return maxLight; + return new BlockLightData(maxSky, maxBlock); } - public static int maxLight(int relativeX, int relativeY, int relativeZ, DataLayer blockLightData, DataLayer skyLightData, int ambientDarkness) { - int skyLight = skyLightData.get(relativeX, relativeY, relativeZ) - ambientDarkness; - if (skyLight == 15) { - return 15; - } - int blockLight = blockLightData.get(relativeX, relativeY, relativeZ); - return Math.max(skyLight, blockLight); + public static int getLight(DataLayer lightData, BlockPos blockPos) { + return lightData != null ? lightData.get(SectionPos.sectionRelative(blockPos.getX()), SectionPos.sectionRelative(blockPos.getY()), SectionPos.sectionRelative(blockPos.getZ())) : -1; + } + + public static int getLight(DataLayer lightData, int relativeX, int relativeY, int relativeZ) { + return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - public int getLight(BlockPos blockPos, int ambientDarkness) { - int relativeX = SectionPos.sectionRelative(blockPos.getX()); - int relativeY = SectionPos.sectionRelative(blockPos.getY()); - int relativeZ = SectionPos.sectionRelative(blockPos.getZ()); - int skyLight = skyLights != null ? skyLights.get(relativeX, relativeY, relativeZ) - ambientDarkness : 0; - if (skyLight == 15 || blockLights == null) { - return skyLight; - } - int blockLight = blockLights.get(relativeX, relativeY, relativeZ); - return Math.max(skyLight, blockLight); + public int getSkyLight(BlockPos blockPos, int ambientDarkness) { + return getLight(skyLights, blockPos) - ambientDarkness; + } + + public int getBlockLight(BlockPos blockPos) { + return getLight(blockLights, blockPos); } } From c1a1541eba77bd16e5c60ea0c4fb7387e3841eef Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 17 Jul 2025 22:16:09 +0100 Subject: [PATCH 154/169] No need for ambient darkness --- .../impl/network/handlers/FakeBlockHelper.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 7681e6892e..bd122da8dd 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -256,7 +256,6 @@ public record BlockLightData(int sky, int block) {} }; public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { - int ambientDarkness = 0; int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); List blockLookups = null; @@ -283,7 +282,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); if (hasSkyLights) { - skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ) - ambientDarkness; + skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } if (hasBlockLights) { blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); @@ -314,8 +313,8 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); - int skyLight = sectionLight.getSkyLight(blockPos, ambientDarkness); - int blockLight = sectionLight.getBlockLight(blockPos); + int skyLight = getLight(sectionLight.skyLights(), blockPos); + int blockLight = getLight(sectionLight.blockLights(), blockPos); if (skyLight > maxSky) { maxSky = skyLight; } @@ -337,16 +336,7 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } - public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) { - - public int getSkyLight(BlockPos blockPos, int ambientDarkness) { - return getLight(skyLights, blockPos) - ambientDarkness; - } - - public int getBlockLight(BlockPos blockPos) { - return getLight(blockLights, blockPos); - } - } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} public static boolean coordOutOfSection(int relativeCoord) { return relativeCoord < 0 || relativeCoord > 15; From 4ecd0ef7183b19ad8919593a2daff0b08b83a414 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 18 Jul 2025 20:22:14 +0100 Subject: [PATCH 155/169] Bring back some short-circuiting --- .../network/handlers/FakeBlockHelper.java | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index bd122da8dd..858cbef6cf 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -244,7 +244,10 @@ public static DataLayer getLayer(boolean has, List layers, int index) { return has ? new DataLayer(layers.get(index)) : null; } - public record BlockLightData(int sky, int block) {} + public record BlockLightData(int sky, int block) { + public static final BlockLightData MAX_BLOCK_LIGHT = new BlockLightData(0, 15); + public static final BlockLightData MAX_SKY_LIGHT = new BlockLightData(15, 0); + } public static final int[][] directions = { {0, -1, 0}, @@ -256,8 +259,15 @@ public record BlockLightData(int sky, int block) {} }; public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + boolean isSkyBright = nmsWorld.getSkyDarken() == 0; int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); + if (isSkyBright && maxSky == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (maxBlock == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } List blockLookups = null; for (int[] direction : directions) { int yOffest = direction[1]; @@ -277,7 +287,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); if (!hasBlockLights && !hasSkyLights) { - Debug.log("No lights in adjacent section"); continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); @@ -287,12 +296,16 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (hasBlockLights) { blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - Debug.log("Adjacent packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); } else { skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); - Debug.log("Packet light, Block(" + blockLight + ") Sky(" + skyLight + ')'); + } + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; } if (skyLight > maxSky) { maxSky = skyLight; @@ -307,7 +320,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { - Debug.log("Getting section to cache"); + Debug.log(">>>>>>>> Getting section to cache"); LevelLightEngine lightEngine = nmsWorld.getLightEngine(); DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); @@ -315,6 +328,12 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY }); int skyLight = getLight(sectionLight.skyLights(), blockPos); int blockLight = getLight(sectionLight.blockLights(), blockPos); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } if (skyLight > maxSky) { maxSky = skyLight; } From 7d952c34552eb09b77c5dda2fab4445acd4e3853 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 24 Jul 2025 20:15:23 +0100 Subject: [PATCH 156/169] Handle all semi-transparent blocks' lighting --- .../network/handlers/FakeBlockHelper.java | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 858cbef6cf..b36f7d88a6 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -1,11 +1,9 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers; import com.denizenscript.denizen.Denizen; -import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.utilities.blocks.FakeBlock; -import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; @@ -32,7 +30,6 @@ import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; @@ -180,19 +177,19 @@ else if (newState.isAir() && !oldState.isAir()) { blockCount--; } states.set(relativeX, relativeY, relativeZ, newState); - BlockEntityType nmsBlockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); - if (nmsBlockEntityType == null) { + BlockEntityType blockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); + if (blockEntityType != null) { + BlockEntity createdBlockEntity = blockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); + createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); + Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); + blockEntities.add(packetBlockEntityData); + } + if (blockEntityType == null && newState.isSolidRender()) { continue; } - BlockEntity createdBlockEntity = nmsBlockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); - createdBlockEntity.setLevel(nmsWorld); - Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); - blockEntities.add(packetBlockEntityData); BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), - lightData, nmsWorld, sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); - Debug.log("Final data: " + estimatedLights); + lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); if (estimatedLights.block() > 0) { DataLayer blockLights; if (!hasBlock) { @@ -274,7 +271,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int neighborX = relativeX + direction[0]; int neighborY = relativeY + yOffest; int neighborZ = relativeZ + direction[2]; - if (coordOutOfSection(neighborX) || coordOutOfSection(neighborZ)) { + if (posOutOfSection(neighborX) || posOutOfSection(neighborZ)) { if (blockLookups == null) { blockLookups = new ArrayList<>(2); } @@ -282,7 +279,7 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY continue; } int blockLight = -1, skyLight = -1; - if (coordOutOfSection(neighborY)) { + if (posOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); @@ -320,7 +317,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { - Debug.log(">>>>>>>> Getting section to cache"); LevelLightEngine lightEngine = nmsWorld.getLightEngine(); DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); @@ -340,9 +336,6 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight > maxBlock) { maxBlock = blockLight; } - Bukkit.getScheduler().runTaskLater(Denizen.getInstance(), () -> { - NMSHandler.packetHelper.showDebugTestMarker(Bukkit.getOnlinePlayers().iterator().next(), CraftLocation.toBukkit(blockPos), ColorTag.valueOf("red", null), "", 4000); - }, 1); } return new BlockLightData(maxSky, maxBlock); } @@ -357,7 +350,7 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} - public static boolean coordOutOfSection(int relativeCoord) { - return relativeCoord < 0 || relativeCoord > 15; + public static boolean posOutOfSection(int relativePos) { + return relativePos < 0 || relativePos > 15; } } From 29378c1bca0c6b4b8b3ee3f33b810aa39403aa0c Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 27 Jul 2025 13:00:52 +0100 Subject: [PATCH 157/169] Naming, comments --- .../network/handlers/FakeBlockHelper.java | 81 +++++++++---------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index b36f7d88a6..b18b4da774 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -113,7 +113,7 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); - // A list of block entities sent with the chunk data + // A list of ClientboundLevelChunkPacketData$BlockEntityInfo List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invoke(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); ListIterator blockEntitiesIterator = blockEntities.listIterator(); @@ -132,27 +132,26 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo blockEntitiesIterator.remove(); } } - // Get the original chunk data to read, and a buf of the same size to write + // Get the original chunk data to read, and a new buf of the same size to write FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); - int worldMinY = world.getMinHeight(); - int worldMaxY = world.getMaxHeight(); - int minChunkY = SectionPos.blockToSectionCoord(worldMinY); - int maxChunkY = SectionPos.blockToSectionCoord(worldMaxY); + final int minChunkY = SectionPos.blockToSectionCoord(world.getMinHeight()); + final int maxChunkY = SectionPos.blockToSectionCoord(world.getMaxHeight()); Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); int blocksLit = 0, skyLit = 0; - // These are section coords, iterating through every chunk section ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); + // These are section coords, iterating through every chunk section for (int y = minChunkY; y < maxChunkY; y++) { SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); + // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) int sectionIndex = y + Math.abs(minChunkY) + 1; - boolean hasSky = false, hasBlock = false; + boolean hasSkyLight = false, hasBlockLight = false; if (lightData.getBlockYMask().get(sectionIndex)) { - hasBlock = true; + hasBlockLight = true; } if (lightData.getSkyYMask().get(sectionIndex)) { - hasSky = true; + hasSkyLight = true; } int blockCount = rawChunkData.readShort(); PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); @@ -188,13 +187,13 @@ else if (newState.isAir() && !oldState.isAir()) { continue; } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, - getLayer(hasBlock, lightData.getBlockUpdates(), blocksLit), getLayer(hasSky, lightData.getSkyUpdates(), skyLit), + getLayer(hasBlockLight, lightData.getBlockUpdates(), blocksLit), getLayer(hasSkyLight, lightData.getSkyUpdates(), skyLit), lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); if (estimatedLights.block() > 0) { DataLayer blockLights; - if (!hasBlock) { + if (!hasBlockLight) { blockLights = addLayer(lightData.getBlockUpdates(), blocksLit, lightData.getBlockYMask(), lightData.getEmptyBlockYMask(), sectionIndex); - hasBlock = true; + hasBlockLight = true; } else { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); @@ -203,9 +202,9 @@ else if (newState.isAir() && !oldState.isAir()) { } if (estimatedLights.sky() > 0) { DataLayer skyLights; - if (!hasSky) { + if (!hasSkyLight) { skyLights = addLayer(lightData.getSkyUpdates(), skyLit, lightData.getSkyYMask(), lightData.getEmptySkyYMask(), sectionIndex); - hasSky = true; + hasSkyLight = true; } else { skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); @@ -215,10 +214,10 @@ else if (newState.isAir() && !oldState.isAir()) { } } } - if (hasBlock) { + if (hasBlockLight) { blocksLit++; } - if (hasSky) { + if (hasSkyLight) { skyLit++; } newChunkData.writeShort(blockCount); @@ -246,6 +245,8 @@ public record BlockLightData(int sky, int block) { public static final BlockLightData MAX_SKY_LIGHT = new BlockLightData(15, 0); } + public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} + public static final int[][] directions = { {0, -1, 0}, {0, 1, 0}, @@ -255,14 +256,14 @@ public record BlockLightData(int sky, int block) { {0, 0, 1} }; - public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightPacket, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { boolean isSkyBright = nmsWorld.getSkyDarken() == 0; - int maxSky = getLight(skyLights, relativeX, relativeY, relativeZ); - int maxBlock = getLight(blockLights, relativeX, relativeY, relativeZ); - if (isSkyBright && maxSky == 15) { + int maxSkyLight = getLight(skyLights, relativeX, relativeY, relativeZ); + int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); + if (isSkyBright && maxSkyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } - if (maxBlock == 15) { + if (maxBlockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } List blockLookups = null; @@ -281,17 +282,17 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int blockLight = -1, skyLight = -1; if (posOutOfSection(neighborY)) { int adjacentSectionIndex = sectionIndex + yOffest; - boolean hasSkyLights = lightPacket.getSkyYMask().get(adjacentSectionIndex); - boolean hasBlockLights = lightPacket.getBlockYMask().get(adjacentSectionIndex); - if (!hasBlockLights && !hasSkyLights) { + boolean hasSkyLight = lightData.getSkyYMask().get(adjacentSectionIndex); + boolean hasBlockLight = lightData.getBlockYMask().get(adjacentSectionIndex); + if (!hasBlockLight && !hasSkyLight) { continue; } int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - if (hasSkyLights) { - skyLight = new DataLayer(lightPacket.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (hasSkyLight) { + skyLight = new DataLayer(lightData.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } - if (hasBlockLights) { - blockLight = new DataLayer(lightPacket.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (hasBlockLight) { + blockLight = new DataLayer(lightData.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); } } else { @@ -304,15 +305,15 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } - if (skyLight > maxSky) { - maxSky = skyLight; + if (skyLight > maxSkyLight) { + maxSkyLight = skyLight; } - if (blockLight > maxBlock) { - maxBlock = blockLight; + if (blockLight > maxBlockLight) { + maxBlockLight = blockLight; } } if (blockLookups == null) { - return new BlockLightData(maxSky, maxBlock); + return new BlockLightData(maxSkyLight, maxBlockLight); } for (BlockPos blockPos : blockLookups) { SectionPos containingSection = SectionPos.of(blockPos); @@ -330,14 +331,14 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } - if (skyLight > maxSky) { - maxSky = skyLight; + if (skyLight > maxSkyLight) { + maxSkyLight = skyLight; } - if (blockLight > maxBlock) { - maxBlock = blockLight; + if (blockLight > maxBlockLight) { + maxBlockLight = blockLight; } } - return new BlockLightData(maxSky, maxBlock); + return new BlockLightData(maxSkyLight, maxBlockLight); } public static int getLight(DataLayer lightData, BlockPos blockPos) { @@ -348,8 +349,6 @@ public static int getLight(DataLayer lightData, int relativeX, int relativeY, in return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; } - public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} - public static boolean posOutOfSection(int relativePos) { return relativePos < 0 || relativePos > 15; } From 6ccc2e5d1be7f8ef557622076fb02a386d72b4c5 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 27 Jul 2025 18:11:20 +0100 Subject: [PATCH 158/169] Skip lighting if the existing state isn't solid --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index b18b4da774..deba5a6b61 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -183,7 +183,7 @@ else if (newState.isAir() && !oldState.isAir()) { Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); blockEntities.add(packetBlockEntityData); } - if (blockEntityType == null && newState.isSolidRender()) { + if (!oldState.isSolidRender() || (blockEntityType == null && newState.isSolidRender())) { continue; } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, From 3aeb675fd2ccd5e77b939d99f5eeffd519c19a16 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:39:33 +0100 Subject: [PATCH 159/169] Split up fake block packet handlers --- .../packet/FakeBlocksPacketHandlers.java | 155 +++++++++--------- 1 file changed, 80 insertions(+), 75 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index f8b31d4052..e7e76b3723 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -21,91 +21,96 @@ public class FakeBlocksPacketHandlers { public static void registerHandlers() { - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelChunkWithLightPacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSectionBlocksUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelChunkWithLightPacket.class, FakeBlocksPacketHandlers::processLevelChunkWithLightPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSectionBlocksUpdatePacket.class, FakeBlocksPacketHandlers::processSectionBlocksUpdatePacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processBlockUpdatePacket); } public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); - public static Packet processShowFakeForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { - return packet; + return chunkPacket; } - try { - if (packet instanceof ClientboundLevelChunkWithLightPacket) { - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return packet; - } - int chunkX = ((ClientboundLevelChunkWithLightPacket) packet).getX(); - int chunkZ = ((ClientboundLevelChunkWithLightPacket) packet).getZ(); - ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); - List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); - if (blocks == null || blocks.isEmpty()) { - return packet; - } - return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks, map); - } - else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return sectionBlocksUpdatePacket; - } - SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionBlocksUpdatePacket); - ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); - if (!map.byChunk.containsKey(coordinateDenizen)) { - return sectionBlocksUpdatePacket; - } - ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionBlocksUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); - LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); - BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); - short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); - BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); - OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); - BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); - for (int i = 0; i < offsetArray.length; i++) { - short offset = offsetArray[i]; - BlockPos pos = coord.relativeToBlockPos(offset); - location.setX(pos.getX()); - location.setY(pos.getY()); - location.setZ(pos.getZ()); - FakeBlock block = map.byLocation.get(location); - if (block != null) { - dataArray[i] = FakeBlockHelper.getNMSState(block); - } - } - return newPacket; - } - else if (packet instanceof ClientboundBlockUpdatePacket) { - BlockPos pos = ((ClientboundBlockUpdatePacket) packet).getPos(); - LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); - if (block != null) { - ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(((ClientboundBlockUpdatePacket) packet).getPos(), FakeBlockHelper.getNMSState(block)); - return newPacket; - } - } - else if (packet instanceof ClientboundBlockChangedAckPacket) { - // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. - /* - ClientboundBlockChangedAckPacket origPack = (ClientboundBlockChangedAckPacket) packet; - BlockPos pos = origPack.pos(); - LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); - if (block != null) { - ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(origPack.pos(), FakeBlockHelper.getNMSState(block), origPack.action(), false); - oldManager.send(newPacket, genericfuturelistener); - return true; - }*/ + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return chunkPacket; + } + int chunkX = chunkPacket.getX(); + int chunkZ = chunkPacket.getZ(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); + List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); + if (blocks == null || blocks.isEmpty()) { + return chunkPacket; + } + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocks, map); + } + + public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws IllegalAccessException { + if (FakeBlock.blocks.isEmpty()) { + return sectionUpdatePacket; + } + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return sectionUpdatePacket; + } + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); + if (!map.byChunk.containsKey(coordinateDenizen)) { + return sectionUpdatePacket; + } + ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); + BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); + short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); + BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); + OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); + BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); + for (int i = 0; i < offsetArray.length; i++) { + short offset = offsetArray[i]; + BlockPos pos = coord.relativeToBlockPos(offset); + location.setX(pos.getX()); + location.setY(pos.getY()); + location.setZ(pos.getZ()); + FakeBlock block = map.byLocation.get(location); + if (block != null) { + dataArray[i] = FakeBlockHelper.getNMSState(block); } } - catch (Throwable ex) { - Debug.echoError(ex); + return newPacket; + } + + public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { + if (FakeBlock.blocks.isEmpty()) { + return blockUpdatePacket; + } + BlockPos pos = blockUpdatePacket.getPos(); + LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); + if (block != null) { + ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); + return newPacket; + } + return blockUpdatePacket; + } + + // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. + /* + public static ClientboundBlockChangedAckPacket processBlockChangedAckPacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockChangedAckPacket blockChangedAckPacket) { + if (FakeBlock.blocks.isEmpty()) { + return blockChangedAckPacket; + } + BlockPos pos = blockChangedAckPacket.pos(); + LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); + if (block != null) { + ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(blockChangedAckPacket.pos(), FakeBlockHelper.getNMSState(block), blockChangedAckPacket.action(), false); + oldManager.send(newPacket, genericfuturelistener); + return true; } - return packet; } + */ } From 8256874ce1f31d180b23d29397ae15e5bb395a40 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:11:45 +0100 Subject: [PATCH 160/169] Cleanup fake block handlers --- .../packet/FakeBlocksPacketHandlers.java | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index e7e76b3723..c74d60d2c7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -7,11 +7,12 @@ import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; +import it.unimi.dsi.fastutil.shorts.ShortArraySet; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; import java.lang.reflect.Field; @@ -61,26 +62,21 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac if (!map.byChunk.containsKey(coordinateDenizen)) { return sectionUpdatePacket; } - ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); + short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); - BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); - short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); - BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); - OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); - BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); - for (int i = 0; i < offsetArray.length; i++) { - short offset = offsetArray[i]; - BlockPos pos = coord.relativeToBlockPos(offset); - location.setX(pos.getX()); - location.setY(pos.getY()); - location.setZ(pos.getZ()); + for (int i = 0; i < originalOffsetArray.length; i++) { + short offset = originalOffsetArray[i]; + location.setX(coord.relativeToBlockX(offset)); + location.setY(coord.relativeToBlockY(offset)); + location.setZ(coord.relativeToBlockZ(offset)); FakeBlock block = map.byLocation.get(location); if (block != null) { - dataArray[i] = FakeBlockHelper.getNMSState(block); + statesArray[i] = FakeBlockHelper.getNMSState(block); } } - return newPacket; + return new ClientboundSectionBlocksUpdatePacket(coord, new ShortArraySet(originalOffsetArray), statesArray); } public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { @@ -91,8 +87,7 @@ public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetwo LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); if (block != null) { - ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); - return newPacket; + return new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); } return blockUpdatePacket; } From 1388b8c7565aeff81e9bf64dfcd9994fc5e0f4d8 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:53:51 +0100 Subject: [PATCH 161/169] Don't make new section blocks packet unless needed --- .../network/handlers/packet/FakeBlocksPacketHandlers.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index c74d60d2c7..e5e10d49b2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -66,6 +66,7 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + boolean hasAny = false; for (int i = 0; i < originalOffsetArray.length; i++) { short offset = originalOffsetArray[i]; location.setX(coord.relativeToBlockX(offset)); @@ -74,8 +75,12 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac FakeBlock block = map.byLocation.get(location); if (block != null) { statesArray[i] = FakeBlockHelper.getNMSState(block); + hasAny = true; } } + if (!hasAny) { + return sectionUpdatePacket; + } return new ClientboundSectionBlocksUpdatePacket(coord, new ShortArraySet(originalOffsetArray), statesArray); } From 6145b05a1031863b6bdbb61626a35cad792dba4b Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 28 Jul 2025 17:20:42 +0100 Subject: [PATCH 162/169] Section block packets: use `MethodHandle`s --- .../packet/FakeBlocksPacketHandlers.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index e5e10d49b2..7f513acd96 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -15,7 +15,7 @@ import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; -import java.lang.reflect.Field; +import java.lang.invoke.MethodHandle; import java.util.Arrays; import java.util.List; @@ -27,9 +27,9 @@ public static void registerHandlers() { DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processBlockUpdatePacket); } - public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); - public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); - public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); + public static final MethodHandle SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_sectionPos, SectionPos.class); + public static final MethodHandle OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); + public static final MethodHandle BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { @@ -49,7 +49,7 @@ public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPac return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocks, map); } - public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws IllegalAccessException { + public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { return sectionUpdatePacket; } @@ -57,13 +57,13 @@ public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePac if (map == null) { return sectionUpdatePacket; } - SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); if (!map.byChunk.containsKey(coordinateDenizen)) { return sectionUpdatePacket; } - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); - BlockState[] originalStatesArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(sectionUpdatePacket); + short[] originalOffsetArray = (short[]) OFFSETARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); + BlockState[] originalStatesArray = (BlockState[]) BLOCKARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); boolean hasAny = false; From bb1bbfb52458d506a53cb998cf35f9d6401bdd2a Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:38:59 +0100 Subject: [PATCH 163/169] Minor change --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index deba5a6b61..23bb735dd7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -143,7 +143,6 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); // These are section coords, iterating through every chunk section for (int y = minChunkY; y < maxChunkY; y++) { - SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) int sectionIndex = y + Math.abs(minChunkY) + 1; boolean hasSkyLight = false, hasBlockLight = false; @@ -159,6 +158,7 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); biomes.read(rawChunkData); if (anyBlocksInSection(blocksInChunk, y)) { + SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); int minY = SectionPos.sectionToBlockCoord(y); int maxY = minY + 16; for (FakeBlock block : blocksInChunk) { From 77bd15759475b07a2a1af0e8c9871b6ea1aa3491 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:46:31 +0100 Subject: [PATCH 164/169] Reflection fixup --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 23bb735dd7..74b1ec1912 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -224,7 +224,7 @@ else if (newState.isAir() && !oldState.isAir()) { states.write(newChunkData); biomes.write(newChunkData); } - CHUNKDATA_BUFFER_SETTER.invoke(copiedChunkPacket.getChunkData(), newChunkData.array()); + CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); return copiedChunkPacket; } From b84da18d0fd330e188f42a43595c9f76fd284705 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 27 Sep 2025 11:16:10 +0100 Subject: [PATCH 165/169] Persist light through fake blocks between sections --- .../denizen/utilities/blocks/FakeBlock.java | 2 + .../network/handlers/FakeBlockHelper.java | 41 ++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java index 86eccab4a4..4f7dd0cabe 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java @@ -92,6 +92,8 @@ public static List getFakeBlocksFor(UUID id, ChunkCoordinate chunkCoo public final int sectionY; public MaterialTag material; public BukkitTask currentTask = null; + public int lastBlockLight = -1; + public int lastSkyLight = -1; private FakeBlock(PlayerTag player, LocationTag location) { this.player = player; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 74b1ec1912..433632bac2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -188,7 +188,7 @@ else if (newState.isAir() && !oldState.isAir()) { } BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, getLayer(hasBlockLight, lightData.getBlockUpdates(), blocksLit), getLayer(hasSkyLight, lightData.getSkyUpdates(), skyLit), - lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit); + lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit, fakeBlockMap); if (estimatedLights.block() > 0) { DataLayer blockLights; if (!hasBlockLight) { @@ -199,6 +199,7 @@ else if (newState.isAir() && !oldState.isAir()) { blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); } blockLights.set(relativeX, relativeY, relativeZ, estimatedLights.block()); + block.lastBlockLight = estimatedLights.block(); } if (estimatedLights.sky() > 0) { DataLayer skyLights; @@ -210,6 +211,7 @@ else if (newState.isAir() && !oldState.isAir()) { skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); } skyLights.set(relativeX, relativeY, relativeZ, estimatedLights.sky()); + block.lastSkyLight = estimatedLights.sky(); } } } @@ -256,13 +258,13 @@ public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} {0, 0, 1} }; - public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit) { + public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit, FakeBlock.FakeBlockMap fakeBlockMap) { boolean isSkyBright = nmsWorld.getSkyDarken() == 0; int maxSkyLight = getLight(skyLights, relativeX, relativeY, relativeZ); - int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); if (isSkyBright && maxSkyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } + int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); if (maxBlockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } @@ -290,20 +292,26 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY int wrappedNeighborY = SectionPos.sectionRelative(neighborY); if (hasSkyLight) { skyLight = new DataLayer(lightData.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } } if (hasBlockLight) { blockLight = new DataLayer(lightData.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } } } else { skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); - } - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } } if (skyLight > maxSkyLight) { maxSkyLight = skyLight; @@ -324,13 +332,26 @@ public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY return new SectionLightCache(sectionBlockLights, sectionSkyLights); }); int skyLight = getLight(sectionLight.skyLights(), blockPos); - int blockLight = getLight(sectionLight.blockLights(), blockPos); if (isSkyBright && skyLight == 15) { return BlockLightData.MAX_SKY_LIGHT; } + int blockLight = getLight(sectionLight.blockLights(), blockPos); if (blockLight == 15) { return BlockLightData.MAX_BLOCK_LIGHT; } + FakeBlock fakeBlock = fakeBlockMap.byLocation.get(new LocationTag(nmsWorld.getWorld(), blockPos.getX(), blockPos.getY(), blockPos.getZ())); + if (fakeBlock.lastSkyLight > skyLight) { + skyLight = fakeBlock.lastSkyLight; + if (isSkyBright && skyLight == 15) { + return BlockLightData.MAX_SKY_LIGHT; + } + } + if (fakeBlock.lastBlockLight > blockLight) { + blockLight = fakeBlock.lastBlockLight; + if (blockLight == 15) { + return BlockLightData.MAX_BLOCK_LIGHT; + } + } if (skyLight > maxSkyLight) { maxSkyLight = skyLight; } From 10e784eb355837e5cbf0dccb4b1e0f90a0bf6ff1 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 27 Sep 2025 11:23:09 +0100 Subject: [PATCH 166/169] No `EnumMap` --- .../nms/v1_21/impl/network/handlers/FakeBlockHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 433632bac2..1b0f11f0d0 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -52,7 +52,7 @@ public class FakeBlockHelper { public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); - public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new EnumMap<>(Material.class); + public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); static { try { From 97896b740f035090bd57c582ef1de668be2cc067 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 25 Aug 2026 08:14:59 +0100 Subject: [PATCH 167/169] Rewrite 2.0 --- .../denizen/utilities/blocks/FakeBlock.java | 2 - .../nms/v1_21/ReflectionMappingsInfo.java | 64 +-- .../network/handlers/FakeBlockHelper.java | 371 +++++++----------- .../packet/FakeBlocksPacketHandlers.java | 30 +- .../handlers/DenizenNetworkManagerImpl.java | 4 +- .../network/handlers/FakeBlockHelper.java | 326 ++++++++++----- .../packet/FakeBlocksPacketHandlers.java | 173 ++++---- 7 files changed, 518 insertions(+), 452 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java index 4f7dd0cabe..86eccab4a4 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/blocks/FakeBlock.java @@ -92,8 +92,6 @@ public static List getFakeBlocksFor(UUID id, ChunkCoordinate chunkCoo public final int sectionY; public MaterialTag material; public BukkitTask currentTask = null; - public int lastBlockLight = -1; - public int lastSkyLight = -1; private FakeBlock(PlayerTag player, LocationTag location) { this.player = player; diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 18d5f6e051..72456a27ee 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -12,34 +12,39 @@ public class ReflectionMappingsInfo { public static String MappedRegistry_unregisteredIntrusiveHolders = "m"; // net.minecraft.world.entity.Entity - public static String Entity_onGround = "bb"; - public static String Entity_DATA_SHARED_FLAGS_ID = "az"; - public static String Entity_DATA_CUSTOM_NAME = "bl"; - public static String Entity_DATA_CUSTOM_NAME_VISIBLE = "bm"; + 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 = "bo"; - public static String LivingEntity_autoSpinAttackTicks = "bL"; + 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 = "d"; - public static String Player_DATA_PLAYER_MODE_CUSTOMISATION = "cg"; + public static String Player_DATA_PLAYER_ABSORPTION_ID = "b"; // net.minecraft.server.level.ServerPlayer - public static String ServerPlayer_respawnConfig = "dA"; + public static String ServerPlayer_respawnConfig = "dr"; // net.minecraft.world.entity.monster.EnderMan - public static String EnderMan_DATA_CREEPY = "cl"; + public static String EnderMan_DATA_CREEPY = "cx"; - // net.minecraft.world.entity.monster.Zombie - public static String Zombie_inWaterTime = "cA"; + // 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 = "C"; + public static String Level_isClientSide = "D"; // net.minecraft.server.level.ThreadedLevelLightEngine public static String ThreadedLevelLightEngine_addTask_method = "a"; @@ -55,22 +60,19 @@ public class ReflectionMappingsInfo { // net.minecraft.world.level.biome.Biome public static String Biome_climateSettings = "i"; - - // net.minecraft.world.level.biome.BiomeSpecialEffects - public static String BiomeSpecialEffects_foliageColorOverride = "f"; - public static String BiomeSpecialEffects_fogColor = "b"; - public static String BiomeSpecialEffects_waterFogColor = "d"; + public static String Biome_attributes = "l"; + public static String Biome_specialEffects = "m"; // net.minecraft.network.Connection - public static String Connection_receiving = "k"; - public static String Connection_packetListener = "q"; + public static String Connection_receiving = "h"; + public static String Connection_packetListener = "n"; // net.minecraft.server.network.ServerGamePacketListenerImpl - public static String ServerGamePacketListenerImpl_aboveGroundTickCount = "J"; - public static String ServerGamePacketListenerImpl_aboveGroundVehicleTickCount = "L"; - public static String ServerGamePacketListenerImpl_awaitingPositionFromClient = "F"; - public static String ServerGamePacketListenerImpl_awaitingTeleport = "G"; - public static String ServerGamePacketListenerImpl_chunkSender = "g"; + 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"; @@ -117,8 +119,14 @@ public class ReflectionMappingsInfo { // 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 = "R"; + public static String ServerLevel_sleepStatus = "O"; // net.minecraft.world.item.AdventureModePredicate public static String AdventureModePredicate_predicates = "g"; @@ -127,5 +135,5 @@ public class ReflectionMappingsInfo { public static String ServerRecipeBook_addHighlight_method = "e"; // net.minecraft.world.level.block.entity.BlockEntityType - public static String BlockEntityType_validBlocks = "Y"; -} + public static String BlockEntityType_validBlocks = "aa"; +} \ No newline at end of file diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 1b0f11f0d0..48a45edbbd 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -3,40 +3,39 @@ import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.nms.v1_21.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.LocationTag; +import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import net.minecraft.core.BlockPos; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.shorts.ShortArraySet; +import it.unimi.dsi.fastutil.shorts.ShortObjectPair; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.network.protocol.game.ClientboundLightUpdatePacketData; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.LightLayer; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LightBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.chunk.Strategy; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_21_R5.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; -import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockType; -import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R5.util.CraftLocation; +import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; +import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockType; +import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; @@ -52,7 +51,10 @@ public class FakeBlockHelper { public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); + public static final PalettedContainer EMPTY_BLOCKS_CONTAINER = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); + public static final BlockState MAX_LIGHT_LIGHT_BLOCK = Blocks.LIGHT.defaultBlockState().setValue(LightBlock.LEVEL, 15), AIR = Blocks.AIR.defaultBlockState(); + public static final byte[] MAX_LIGHT_SECTION = new DataLayer(15).getData(), MIN_LIGHT_SECTION = new DataLayer(0).getData(); static { try { @@ -110,11 +112,13 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, List blocksInChunk, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { + public static Packet handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, Int2ObjectMap> blocksBySection, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); copyPacketPaperPatch(copiedChunkPacket); + // TODO pass coord? + boolean isNaturalLoad = !FakeBlock.scheduled.containsKey(new ChunkCoordinate(chunkX, chunkZ, world.getName())); // A list of ClientboundLevelChunkPacketData$BlockEntityInfo - List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invoke(copiedChunkPacket.getChunkData()); + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invokeExact(copiedChunkPacket.getChunkData()); LocationTag location = new LocationTag(world, 0, 0, 0); ListIterator blockEntitiesIterator = blockEntities.listIterator(); while (blockEntitiesIterator.hasNext()) { @@ -123,8 +127,8 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo int y = (int) CHUNKDATA_BLOCKENTITYINFO_Y.invoke(blockEnt); int relativeX = SectionPos.sectionRelative(xz >> 4); int relativeZ = SectionPos.sectionRelative(xz); - int x = SectionPos.sectionToBlockCoord(chunkX) + relativeX; - int z = SectionPos.sectionToBlockCoord(chunkZ) + relativeZ; + int x = SectionPos.sectionToBlockCoord(chunkX, relativeX); + int z = SectionPos.sectionToBlockCoord(chunkZ, relativeZ); location.setX(x); location.setY(y); location.setZ(z); @@ -132,245 +136,150 @@ public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World wo blockEntitiesIterator.remove(); } } + List> packets = new ArrayList<>(blocksBySection.size() + 1); + packets.add(copiedChunkPacket); + // Get the original chunk data to read, and a new buf of the same size to write FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); final int minChunkY = SectionPos.blockToSectionCoord(world.getMinHeight()); final int maxChunkY = SectionPos.blockToSectionCoord(world.getMaxHeight()); Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); - int blocksLit = 0, skyLit = 0; ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); - Long2ObjectMap sectionLightCache = new Long2ObjectOpenHashMap<>(); - // These are section coords, iterating through every chunk section - for (int y = minChunkY; y < maxChunkY; y++) { + BitSet blockLightMask = lightData.getBlockYMask(), blockNoLightMask = lightData.getEmptyBlockYMask(), skyLightMask = lightData.getSkyYMask(), skyNoLightMask = lightData.getEmptySkyYMask(); + int blockLitSections = 0, skyLitSections = 0; + boolean foundFirstSkyLight = false; + for (int chunkY = minChunkY; chunkY < maxChunkY; chunkY++) { + int blockCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); + states.read(rawChunkData); + PalettedContainer> biomes = new PalettedContainer<>(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry.asHolderIdMap())); + biomes.read(rawChunkData); + List fakeBlocksInSection = blocksBySection.get(chunkY); // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) - int sectionIndex = y + Math.abs(minChunkY) + 1; - boolean hasSkyLight = false, hasBlockLight = false; - if (lightData.getBlockYMask().get(sectionIndex)) { + int sectionIndex = chunkY - minChunkY + 1; + boolean hasBlockLight = false, hasSkyLight = false; + if (blockLightMask.get(sectionIndex)) { hasBlockLight = true; } - if (lightData.getSkyYMask().get(sectionIndex)) { + if (skyLightMask.get(sectionIndex)) { hasSkyLight = true; } - int blockCount = rawChunkData.readShort(); - PalettedContainer states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - states.read(rawChunkData); - PalettedContainer biomes = new PalettedContainer<>(biomeRegistry, biomeRegistry.getValueOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); - biomes.read(rawChunkData); - if (anyBlocksInSection(blocksInChunk, y)) { - SectionPos sectionPos = SectionPos.of(chunkX, y, chunkZ); - int minY = SectionPos.sectionToBlockCoord(y); - int maxY = minY + 16; - for (FakeBlock block : blocksInChunk) { - int blockY = block.location.getBlockY(); - if (blockY >= minY && blockY < maxY && block.material != null) { - int relativeX = SectionPos.sectionRelative(block.location.getBlockX()); - int relativeY = SectionPos.sectionRelative(blockY); - int relativeZ = SectionPos.sectionRelative(block.location.getBlockZ()); - BlockState oldState = states.get(relativeX, relativeY, relativeZ); - BlockState newState = getNMSState(block); - if (oldState.isAir() && !newState.isAir()) { - blockCount++; - } - else if (newState.isAir() && !oldState.isAir()) { - blockCount--; - } - states.set(relativeX, relativeY, relativeZ, newState); - BlockEntityType blockEntityType = MATERIAL_BLOCK_ENTITY_TYPES.get(block.material.getMaterial()); - if (blockEntityType != null) { - BlockEntity createdBlockEntity = blockEntityType.create(CraftLocation.toBlockPosition(block.location), newState); - createdBlockEntity.setLevel(((CraftWorld) world).getHandle()); - Object packetBlockEntityData = CHUNKDATA_BLOCK_ENTITY_CREATE.invoke(createdBlockEntity); - blockEntities.add(packetBlockEntityData); - } - if (!oldState.isSolidRender() || (blockEntityType == null && newState.isSolidRender())) { - continue; - } - BlockLightData estimatedLights = getEstimatedLightLevel(relativeX, relativeY, relativeZ, - getLayer(hasBlockLight, lightData.getBlockUpdates(), blocksLit), getLayer(hasSkyLight, lightData.getSkyUpdates(), skyLit), - lightData, ((CraftWorld) world).getHandle(), sectionPos, sectionLightCache, sectionIndex, blocksLit, skyLit, fakeBlockMap); - if (estimatedLights.block() > 0) { - DataLayer blockLights; - if (!hasBlockLight) { - blockLights = addLayer(lightData.getBlockUpdates(), blocksLit, lightData.getBlockYMask(), lightData.getEmptyBlockYMask(), sectionIndex); - hasBlockLight = true; - } - else { - blockLights = new DataLayer(lightData.getBlockUpdates().get(blocksLit)); - } - blockLights.set(relativeX, relativeY, relativeZ, estimatedLights.block()); - block.lastBlockLight = estimatedLights.block(); - } - if (estimatedLights.sky() > 0) { - DataLayer skyLights; - if (!hasSkyLight) { - skyLights = addLayer(lightData.getSkyUpdates(), skyLit, lightData.getSkyYMask(), lightData.getEmptySkyYMask(), sectionIndex); - hasSkyLight = true; - } - else { - skyLights = new DataLayer(lightData.getSkyUpdates().get(skyLit)); - } - skyLights.set(relativeX, relativeY, relativeZ, estimatedLights.sky()); - block.lastSkyLight = estimatedLights.sky(); - } + if (fakeBlocksInSection != null) { + List> lightPatch = new ArrayList<>(); + DataLayer blockLayer = null, skyLayer = null; + Debug.log("--------------"); + Debug.log("Has block light: " + hasBlockLight); + Debug.log("Has sky light: " + hasSkyLight); + if (hasSkyLight) { + skyLightMask.clear(sectionIndex); + skyLayer = new DataLayer(lightData.getSkyUpdates().remove(skyLitSections)); + hasSkyLight = false; + if (!foundFirstSkyLight) { + Debug.log(">>> Found first sky light"); } + foundFirstSkyLight = true; } - } - if (hasBlockLight) { - blocksLit++; - } - if (hasSkyLight) { - skyLit++; - } - newChunkData.writeShort(blockCount); - states.write(newChunkData); - biomes.write(newChunkData); - } - CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); - return copiedChunkPacket; - } - - public static DataLayer addLayer(List layers, int index, BitSet litSections, BitSet unlitSections, int sectionIndex) { - DataLayer newLayer = new DataLayer(); - layers.add(index, newLayer.getData()); - litSections.set(sectionIndex); - unlitSections.clear(sectionIndex); - return newLayer; - } - - public static DataLayer getLayer(boolean has, List layers, int index) { - return has ? new DataLayer(layers.get(index)) : null; - } - - public record BlockLightData(int sky, int block) { - public static final BlockLightData MAX_BLOCK_LIGHT = new BlockLightData(0, 15); - public static final BlockLightData MAX_SKY_LIGHT = new BlockLightData(15, 0); - } - - public record SectionLightCache(DataLayer blockLights, DataLayer skyLights) {} - - public static final int[][] directions = { - {0, -1, 0}, - {0, 1, 0}, - {-1, 0, 0}, - {1, 0, 0}, - {0, 0, -1}, - {0, 0, 1} - }; - - public static BlockLightData getEstimatedLightLevel(int relativeX, int relativeY, int relativeZ, DataLayer blockLights, DataLayer skyLights, ClientboundLightUpdatePacketData lightData, ServerLevel nmsWorld, SectionPos sectionPos, Long2ObjectMap sectionLightsCache, int sectionIndex, int blocksLit, int skyLit, FakeBlock.FakeBlockMap fakeBlockMap) { - boolean isSkyBright = nmsWorld.getSkyDarken() == 0; - int maxSkyLight = getLight(skyLights, relativeX, relativeY, relativeZ); - if (isSkyBright && maxSkyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } - int maxBlockLight = getLight(blockLights, relativeX, relativeY, relativeZ); - if (maxBlockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; - } - List blockLookups = null; - for (int[] direction : directions) { - int yOffest = direction[1]; - int neighborX = relativeX + direction[0]; - int neighborY = relativeY + yOffest; - int neighborZ = relativeZ + direction[2]; - if (posOutOfSection(neighborX) || posOutOfSection(neighborZ)) { - if (blockLookups == null) { - blockLookups = new ArrayList<>(2); - } - blockLookups.add(new BlockPos(sectionPos.minBlockX() + neighborX, sectionPos.minBlockY() + neighborY, sectionPos.minBlockZ() + neighborZ)); - continue; - } - int blockLight = -1, skyLight = -1; - if (posOutOfSection(neighborY)) { - int adjacentSectionIndex = sectionIndex + yOffest; - boolean hasSkyLight = lightData.getSkyYMask().get(adjacentSectionIndex); - boolean hasBlockLight = lightData.getBlockYMask().get(adjacentSectionIndex); - if (!hasBlockLight && !hasSkyLight) { - continue; + else { + skyNoLightMask.clear(sectionIndex); } - int wrappedNeighborY = SectionPos.sectionRelative(neighborY); - if (hasSkyLight) { - skyLight = new DataLayer(lightData.getSkyUpdates().get(skyLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } + if (isNaturalLoad) { + Debug.log(">>> Adding " + (foundFirstSkyLight ? "bright" : "dark") + " sky light"); + lightData.getSkyUpdates().add(skyLitSections, foundFirstSkyLight ? MAX_LIGHT_SECTION : MIN_LIGHT_SECTION); + skyLightMask.set(sectionIndex); + hasSkyLight = true; + skyLayer = new DataLayer(lightData.getSkyUpdates().get(skyLitSections)); } if (hasBlockLight) { - blockLight = new DataLayer(lightData.getBlockUpdates().get(blocksLit + yOffest)).get(neighborX, wrappedNeighborY, neighborZ); - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; + blockLightMask.clear(sectionIndex); + blockLayer = new DataLayer(lightData.getBlockUpdates().remove(blockLitSections)); + hasBlockLight = false; + } + else { + blockNoLightMask.clear(sectionIndex); + } + Debug.log("Post has block light: " + blockLightMask.get(sectionIndex)); + Debug.log("Post has sky light: " + skyLightMask.get(sectionIndex)); + Debug.log("--------------"); + if (blockLayer != null || skyLayer != null) { + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + BlockState state = states.get(x, y, z); + boolean isAir = state.isAir(); + if (isAir && (y == 0 || states.get(x, y - 1, z).isAir())) { + continue; + } + if (!isAir && (blockLayer == null || blockLayer.get(x, y, z) == 0)) { + continue; + } + // Based on SectionPos#sectionRelativePos + short offset = (short) (x << 8 | z << 4 | y << 0); + lightPatch.add(ShortObjectPair.of(offset, isAir ? MAX_LIGHT_LIGHT_BLOCK : AIR)); + lightPatch.add(ShortObjectPair.of(offset, state)); + if (!isAir) { + blockCount--; + states.set(x, y, z, AIR); + } + } + } } } - } - else { - skyLight = getLight(skyLights, neighborX, neighborY, neighborZ); - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; + int size = fakeBlocksInSection.size(); + short[] offsets = new short[size]; + BlockState[] statesArr = new BlockState[size]; + for (int blockIndex = 0; blockIndex < size; blockIndex++) { + FakeBlock fakeBlock = fakeBlocksInSection.get(blockIndex); + int relativeX = SectionPos.sectionRelative(fakeBlock.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(fakeBlock.location.getBlockY()); + int relativeZ = SectionPos.sectionRelative(fakeBlock.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); + BlockState newState = ((CraftBlockData) fakeBlock.material.getModernData()).getState(); + short sectionRelativePos = SectionPos.sectionRelativePos(CraftLocation.toBlockPosition(fakeBlock.location)); + offsets[blockIndex] = sectionRelativePos; + statesArr[blockIndex] = newState; + int maxLight = Math.max( + skyLayer != null ? skyLayer.get(relativeX, relativeY, relativeZ) : 0, + blockLayer != null ? blockLayer.get(relativeX, relativeY, relativeZ) : 0 + ); + if (!oldState.isAir()) { + blockCount--; + states.set(relativeX, relativeY, relativeZ, Blocks.AIR.defaultBlockState()); + if (maxLight <= 0 && !newState.isSolidRender()) { + lightPatch.add(ShortObjectPair.of(sectionRelativePos, MAX_LIGHT_LIGHT_BLOCK)); + } + } } - blockLight = getLight(blockLights, neighborX, neighborY, neighborZ); - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; + SectionPos sectionPos = SectionPos.of(chunkX, chunkY, chunkZ); + if (!lightPatch.isEmpty()) { + int lightCount = lightPatch.size(); + short[] lightOffsets = new short[lightCount]; + BlockState[] lightStates = new BlockState[lightCount]; + for (int i = 0; i < lightCount; i++) { + ShortObjectPair pair = lightPatch.get(i); + lightOffsets[i] = pair.leftShort(); + lightStates[i] = pair.right(); + } + packets.add(new ClientboundSectionBlocksUpdatePacket(sectionPos, new ShortArraySet(lightOffsets), lightStates)); } + packets.add(new ClientboundSectionBlocksUpdatePacket(sectionPos, new ShortArraySet(offsets), statesArr)); } - if (skyLight > maxSkyLight) { - maxSkyLight = skyLight; - } - if (blockLight > maxBlockLight) { - maxBlockLight = blockLight; - } - } - if (blockLookups == null) { - return new BlockLightData(maxSkyLight, maxBlockLight); - } - for (BlockPos blockPos : blockLookups) { - SectionPos containingSection = SectionPos.of(blockPos); - SectionLightCache sectionLight = sectionLightsCache.computeIfAbsent(containingSection.asLong(), k -> { - LevelLightEngine lightEngine = nmsWorld.getLightEngine(); - DataLayer sectionBlockLights = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(containingSection); - DataLayer sectionSkyLights = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(containingSection); - return new SectionLightCache(sectionBlockLights, sectionSkyLights); - }); - int skyLight = getLight(sectionLight.skyLights(), blockPos); - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } - int blockLight = getLight(sectionLight.blockLights(), blockPos); - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; - } - FakeBlock fakeBlock = fakeBlockMap.byLocation.get(new LocationTag(nmsWorld.getWorld(), blockPos.getX(), blockPos.getY(), blockPos.getZ())); - if (fakeBlock.lastSkyLight > skyLight) { - skyLight = fakeBlock.lastSkyLight; - if (isSkyBright && skyLight == 15) { - return BlockLightData.MAX_SKY_LIGHT; - } + if (hasBlockLight) { + blockLitSections++; } - if (fakeBlock.lastBlockLight > blockLight) { - blockLight = fakeBlock.lastBlockLight; - if (blockLight == 15) { - return BlockLightData.MAX_BLOCK_LIGHT; - } + if (hasSkyLight) { + skyLitSections++; } - if (skyLight > maxSkyLight) { - maxSkyLight = skyLight; + newChunkData.writeShort(blockCount); + if (blockCount > 0) { + states.write(newChunkData); } - if (blockLight > maxBlockLight) { - maxBlockLight = blockLight; + else { + EMPTY_BLOCKS_CONTAINER.write(newChunkData); } + biomes.write(newChunkData); } - return new BlockLightData(maxSkyLight, maxBlockLight); - } - - public static int getLight(DataLayer lightData, BlockPos blockPos) { - return lightData != null ? lightData.get(SectionPos.sectionRelative(blockPos.getX()), SectionPos.sectionRelative(blockPos.getY()), SectionPos.sectionRelative(blockPos.getZ())) : -1; - } - - public static int getLight(DataLayer lightData, int relativeX, int relativeY, int relativeZ) { - return lightData != null ? lightData.get(relativeX, relativeY, relativeZ) : -1; - } - - public static boolean posOutOfSection(int relativePos) { - return relativePos < 0 || relativePos > 15; + CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); + return new ClientboundBundlePacket(packets); } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 7f513acd96..75c5142acf 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -7,13 +7,17 @@ import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.shorts.ShortArraySet; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.World; import java.lang.invoke.MethodHandle; import java.util.Arrays; @@ -31,7 +35,7 @@ public static void registerHandlers() { public static final MethodHandle OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_positions, short[].class); public static final MethodHandle BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter(ReflectionMappingsInfo.ClientboundSectionBlocksUpdatePacket_states, BlockState[].class); - public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { + public static Packet processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { return chunkPacket; } @@ -41,12 +45,28 @@ public static ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPac } int chunkX = chunkPacket.getX(); int chunkZ = chunkPacket.getZ(); - ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); - List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); - if (blocks == null || blocks.isEmpty()) { + World world = networkManager.player.level().getWorld(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, world.getName()); + Int2ObjectMap> blocksBySection = map.byChunk.get(chunkCoord); + if (blocksBySection == null || blocksBySection.isEmpty()) { return chunkPacket; } - return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocks, map); + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocksBySection, map); +// List> packets = new ArrayList<>(blocksBySection.size() + 1); +// packets.add(mappedPacket); +// for (Int2ObjectMap.Entry> entry : blocksBySection.int2ObjectEntrySet()) { +// List fakeBlocks = entry.getValue(); +// int size = fakeBlocks.size(); +// short[] offsets = new short[size]; +// BlockState[] states = new BlockState[size]; +// for (int i = 0; i < size; i++) { +// FakeBlock fakeBlock = fakeBlocks.get(i); +// offsets[i] = SectionPos.sectionRelativePos(CraftLocation.toBlockPosition(fakeBlock.location)); +// states[i] = ((CraftBlockData) fakeBlock.material.getModernData()).getState(); +// } +// packets.add(new ClientboundSectionBlocksUpdatePacket(SectionPos.of(chunkX, entry.getIntKey(), chunkZ), new ShortArraySet(offsets), states)); +// } +// return new ClientboundBundlePacket(packets); } public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws Throwable { diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java index da4f6aa456..4689bbe78d 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -62,7 +62,7 @@ public static > T copyPacket(T original, StreamCodec> { - Packet handlePacket(DenizenNetworkManagerImpl networkManager, T packet) throws Exception; + Packet handlePacket(DenizenNetworkManagerImpl networkManager, T packet) throws Throwable; } public static final Map>, List>> packetHandlers = new HashMap<>(); @@ -372,7 +372,7 @@ public Packet processPacketHandlersFor(Packet PALETTEDCONTAINER_CTOR = Arrays.stream(PalettedContainer.class.getConstructors()).filter(c -> c.getParameterCount() == 2).findFirst().get(); + public static final MethodHandle CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getGetter("blockEntitiesData", List.class); + public static final MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getSetter("buffer", byte[].class); + public static final Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; + public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter("packedXZ"); + public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter("y"); + + public static final PalettedContainer EMPTY_BLOCKS_CONTAINER = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); + public static final BlockState MAX_LIGHT_BLOCK = Blocks.LIGHT.defaultBlockState().setValue(LightBlock.LEVEL, 15), AIR = Blocks.AIR.defaultBlockState(); + public static final byte[] MAX_LIGHT_SECTION = new DataLayer(15).getData(), MIN_LIGHT_SECTION = new DataLayer(0).getData(); public static BlockState getNMSState(FakeBlock block) { return ((CraftBlockData) block.material.getModernData()).getState(); } - public static boolean anyBlocksInSection(List blocks, int y) { - int minY = y << 4; - int maxY = (y << 4) + 16; - for (FakeBlock block : blocks) { - int blockY = block.location.getBlockY(); - if (blockY >= minY && blockY < maxY) { - return true; - } - } - return false; - } - public static Field PAPER_CHUNK_READY; public static boolean tryPaperPatch = true; - public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket newPacket, ClientboundLevelChunkWithLightPacket oldPacket) { + public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket newPacket) { if (!Denizen.supportsPaper || !tryPaperPatch) { return; } @@ -88,82 +77,215 @@ public static void copyPacketPaperPatch(ClientboundLevelChunkWithLightPacket new } } - public static ClientboundLevelChunkWithLightPacket handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalPacket, int chunkX, int chunkZ, List blocks) { - try { - ClientboundLevelChunkWithLightPacket duplicateCorePacket = DenizenNetworkManagerImpl.copyPacket(originalPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); - copyPacketPaperPatch(duplicateCorePacket, originalPacket); - RegistryFriendlyByteBuf copier = new RegistryFriendlyByteBuf(Unpooled.buffer(), CraftRegistry.getMinecraftRegistry()); - originalPacket.getChunkData().write(copier); - ClientboundLevelChunkPacketData packet = new ClientboundLevelChunkPacketData(copier, chunkX, chunkZ); - FriendlyByteBuf serial = originalPacket.getChunkData().getReadBuffer(); - FriendlyByteBuf outputSerial = new FriendlyByteBuf(Unpooled.buffer(serial.readableBytes())); - List blockEntities = new ArrayList((List) CHUNKDATA_BLOCK_ENTITIES.get(originalPacket.getChunkData())); - CHUNKDATA_BLOCK_ENTITIES.set(packet, blockEntities); - for (int i = 0; i < blockEntities.size(); i++) { - Object blockEnt = blockEntities.get(i); - int xz = CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.getInt(blockEnt); - int y = CHUNKDATA_BLOCKENTITYINFO_Y.getInt(blockEnt); - int x = (chunkX << 4) + ((xz >> 4) & 15); - int z = (chunkZ << 4) + (xz & 15); - for (FakeBlock block : blocks) { - LocationTag loc = block.location; - if (loc.getBlockX() == x && loc.getBlockY() == y && loc.getBlockZ() == z && block.material != null) { - BlockEntity newBlockEnt = CraftBlockStates.createNewTileEntity(block.material.getMaterial()); - Object newData = CHUNKDATA_BLOCK_ENTITY_CONSTRUCTOR.invoke(xz, y, newBlockEnt.getType(), newBlockEnt.getUpdateTag(CraftRegistry.getMinecraftRegistry())); - blockEntities.set(i, newData); - break; + public static boolean hasLight(DataLayer lightData) { + if (lightData == null || lightData.isEmpty()) { + return false; + } + // Sometimes Mojang sends "0" for every block instead of an empty layer?? + // Reproduction: fully underground chunk section, place a single torch & fake block, reload chunk + for (byte value : lightData.getData()) { + if (value != 0) { + return true; + } + } + return false; + } + + public static Packet handleMapChunkPacket(World world, ClientboundLevelChunkWithLightPacket originalChunkPacket, int chunkX, int chunkZ, Int2ObjectMap> blocksBySection, FakeBlock.FakeBlockMap fakeBlockMap) throws Throwable { + ClientboundLevelChunkWithLightPacket copiedChunkPacket = DenizenNetworkManagerImpl.copyPacket(originalChunkPacket, ClientboundLevelChunkWithLightPacket.STREAM_CODEC); + copyPacketPaperPatch(copiedChunkPacket); + // TODO pass coord? + boolean isNaturalLoad = !FakeBlock.scheduled.containsKey(new ChunkCoordinate(chunkX, chunkZ, world.getName())); + // A list of ClientboundLevelChunkPacketData$BlockEntityInfo, every block entity in the chunk + List blockEntities = (List) CHUNKDATA_BLOCK_ENTITIES.invokeExact(copiedChunkPacket.getChunkData()); + LocationTag location = new LocationTag(world, 0, 0, 0); + ListIterator blockEntitiesIterator = blockEntities.listIterator(); + // Clear every block entity being replaced by a fake block + while (blockEntitiesIterator.hasNext()) { + Object blockEnt = blockEntitiesIterator.next(); + int xz = (int) CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ.invoke(blockEnt); + int y = (int) CHUNKDATA_BLOCKENTITYINFO_Y.invoke(blockEnt); + int relativeX = SectionPos.sectionRelative(xz >> 4); + int relativeZ = SectionPos.sectionRelative(xz); + int x = SectionPos.sectionToBlockCoord(chunkX, relativeX); + int z = SectionPos.sectionToBlockCoord(chunkZ, relativeZ); + location.setX(x); + location.setY(y); + location.setZ(z); + if (fakeBlockMap.byLocation.containsKey(location)) { + blockEntitiesIterator.remove(); + } + } + // This list will contain at least the (modified) chunk packet, and one "patch" packet for every chunk section + List> packets = new ArrayList<>(blocksBySection.size() + 1); + packets.add(copiedChunkPacket); + + // Get the original chunk data to read, and a new buffer of the same size to write + FriendlyByteBuf rawChunkData = originalChunkPacket.getChunkData().getReadBuffer(); + FriendlyByteBuf newChunkData = new FriendlyByteBuf(Unpooled.buffer(rawChunkData.readableBytes())); + final int minChunkY = SectionPos.blockToSectionCoord(world.getMinHeight()); + final int maxChunkY = SectionPos.blockToSectionCoord(world.getMaxHeight()); + Registry biomeRegistry = CraftRegistry.getMinecraftRegistry(Registries.BIOME); + ClientboundLightUpdatePacketData lightData = copiedChunkPacket.getLightData(); + BitSet blockLightMask = lightData.getBlockYMask(), blockNoLightMask = lightData.getEmptyBlockYMask(), skyLightMask = lightData.getSkyYMask(), skyNoLightMask = lightData.getEmptySkyYMask(); + // The list of light data per section only has entries for sections with lighting, need to know how many sections had lighting to know what index to remove + int blockLitSections = 0, skyLitSections = 0; + boolean hadFirstSkyLight = false; + for (int chunkY = minChunkY; chunkY < maxChunkY; chunkY++) { + int blockCount = rawChunkData.readShort(); + int fluidCount = rawChunkData.readShort(); + PalettedContainer states = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); + states.read(rawChunkData); + PalettedContainer> biomes = new PalettedContainer<>(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry.asHolderIdMap())); + biomes.read(rawChunkData); + List fakeBlocksInSection = blocksBySection.get(chunkY); + // The light data counts up from 0 instead of minChunkY, and has a buffer of 1 extra section above and below the world (hence + 1) + int lightingIndex = chunkY - minChunkY + 1; + boolean hasBlockLight = blockLightMask.get(lightingIndex), hasSkyLight = skyLightMask.get(lightingIndex); + boolean hasEffectiveSkyLight = false; + if (fakeBlocksInSection != null) { + List> lightPatch = new ArrayList<>(); + DataLayer blockLayer = null, skyLayer = null; + Debug.log("--------------"); + Debug.log("Has block light: " + hasBlockLight); + Debug.log("Has sky light: " + hasSkyLight); + // Chunk packets schedule light updates for the next render tick, delete all lighting data for these sections so that they don't get scheduled and override the lighting from the fake block patches + // Clears both the "has light" mask and the "has no light" mask to make this section effectively non-existent + if (hasSkyLight) { + skyLightMask.clear(lightingIndex); + skyLayer = new DataLayer(lightData.getSkyUpdates().remove(skyLitSections)); + hasSkyLight = false; + if (!hadFirstSkyLight) { + Debug.log(">>> Found first sky light"); + } + hasEffectiveSkyLight = hasLight(skyLayer); + if (hasEffectiveSkyLight) { + hadFirstSkyLight = true; } } - } - int worldMinY = world.getMinHeight(); - int worldMaxY = world.getMaxHeight(); - int minChunkY = worldMinY >> 4; - int maxChunkY = worldMaxY >> 4; - Registry biomeRegistry = ((CraftWorld) world).getHandle().registryAccess().lookupOrThrow(Registries.BIOME); - for (int y = minChunkY; y < maxChunkY; y++) { - int blockCount = serial.readShort(); - int fluidCount = serial.readShort(); - // reflected constructors as workaround for spigot remapper bug - Mojang "IdMap" became Spigot "IRegistry" but should be "Registry" - PalettedContainer states = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); - states.read(serial); - PalettedContainer biomes = (PalettedContainer) PALETTEDCONTAINER_CTOR.newInstance(biomeRegistry.getOrThrow(Biomes.PLAINS), Strategy.createForBiomes(biomeRegistry)); - biomes.read(serial); - if (anyBlocksInSection(blocks, y)) { - int minY = y << 4; - int maxY = (y << 4) + 16; - for (FakeBlock block : blocks) { - int blockY = block.location.getBlockY(); - if (blockY >= minY && blockY < maxY && block.material != null) { - int blockX = block.location.getBlockX(); - int blockZ = block.location.getBlockZ(); - blockX -= (blockX >> 4) * 16; - blockY -= (blockY >> 4) * 16; - blockZ -= (blockZ >> 4) * 16; - BlockState oldState = states.get(blockX, blockY, blockZ); - BlockState newState = getNMSState(block); - if (oldState.isAir() && !newState.isAir()) { - blockCount++; - } - else if (newState.isAir() && !oldState.isAir()) { - blockCount--; + else { + skyNoLightMask.clear(lightingIndex); + } + if (hasBlockLight) { + blockLightMask.clear(lightingIndex); + blockLayer = new DataLayer(lightData.getBlockUpdates().remove(blockLitSections)); + hasBlockLight = false; + } + else { + blockNoLightMask.clear(lightingIndex); + } + // On natural loads the client is receiving the chunk for the first time and has no lighting data for the world around it, making generating lighting for the fake block patches impossible + // Provide best-effort dark/bright lights on first load based on whether we've reached the first sky lit section + if (isNaturalLoad) { + Debug.log(">>> Adding " + (hadFirstSkyLight ? "bright" : "dark") + " sky light"); + byte[] newLightData = hadFirstSkyLight ? MAX_LIGHT_SECTION : MIN_LIGHT_SECTION; + lightData.getSkyUpdates().add(skyLitSections, newLightData); + skyLightMask.set(lightingIndex); + hasSkyLight = true; + hasEffectiveSkyLight = hadFirstSkyLight; + skyLayer = new DataLayer(newLightData); + } + Debug.log("Post has block light: " + blockLightMask.get(lightingIndex)); + Debug.log("Post has sky light: " + skyLightMask.get(lightingIndex)); + Debug.log("--------------"); + // We're removing lighting data to allow lighting from the fake block patches, but that means we need to make the client update lighting for the real blocks in the section too (where needed) + if (hasLight(blockLayer) || hasEffectiveSkyLight) { + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + BlockState state = states.get(x, y, z); + boolean isAir = state.isAir(); + // Air blocks only need an update if they have non-air blocks below them + if (isAir && (y == 0 || states.get(x, y - 1, z).isAir())) { + continue; + } + // Solid blocks only need an update if they had any sort of lighting in the first place + if (!isAir && (!hasLight(blockLayer) || blockLayer.get(x, y, z) == 0)) { + continue; + } + // Based on SectionPos#sectionRelativePos + short offset = (short) (x << 8 | z << 4 | y << 0); + // "Toggle" the block to update it + lightPatch.add(ShortObjectPair.of(offset, isAir ? MAX_LIGHT_BLOCK : AIR)); + lightPatch.add(ShortObjectPair.of(offset, state)); + if (!isAir) { + if (state.getFluidState().isEmpty()) { + blockCount--; + } + else { + fluidCount--; + } + // No need to send the block in the chunk packet as it is sent in the lighting patch + states.set(x, y, z, AIR); + } } - states.set(blockX, blockY, blockZ, newState); } } } - outputSerial.writeShort(blockCount); - outputSerial.writeShort(fluidCount); - states.write(outputSerial); - biomes.write(outputSerial); + int fakesCount = fakeBlocksInSection.size(); + short[] offsets = new short[fakesCount]; + BlockState[] statesArr = new BlockState[fakesCount]; + for (int blockIndex = 0; blockIndex < fakesCount; blockIndex++) { + FakeBlock fakeBlock = fakeBlocksInSection.get(blockIndex); + int relativeX = SectionPos.sectionRelative(fakeBlock.location.getBlockX()); + int relativeY = SectionPos.sectionRelative(fakeBlock.location.getBlockY()); + int relativeZ = SectionPos.sectionRelative(fakeBlock.location.getBlockZ()); + BlockState oldState = states.get(relativeX, relativeY, relativeZ); + BlockState newState = ((CraftBlockData) fakeBlock.material.getModernData()).getState(); + short sectionRelativePos = SectionPos.sectionRelativePos(Handler.toBlockPos(fakeBlock.location)); + offsets[blockIndex] = sectionRelativePos; + statesArr[blockIndex] = newState; +// int maxLight = Math.max( +// skyLayer != null ? skyLayer.get(relativeX, relativeY, relativeZ) : 0, +// blockLayer != null ? blockLayer.get(relativeX, relativeY, relativeZ) : 0 +// ); + if (!oldState.isAir()) { + if (oldState.getFluidState().isEmpty()) { + blockCount--; + } + else { + fluidCount--; + } + states.set(relativeX, relativeY, relativeZ, AIR); +// if (maxLight <= 0 && !newState.isSolidRender()) { +// lightPatch.add(ShortObjectPair.of(sectionRelativePos, MAX_LIGHT_BLOCK)); +// } + } + } + SectionPos sectionPos = SectionPos.of(chunkX, chunkY, chunkZ); + if (!lightPatch.isEmpty()) { + int lightCount = lightPatch.size(); + short[] lightOffsets = new short[lightCount]; + BlockState[] lightStates = new BlockState[lightCount]; + for (int i = 0; i < lightCount; i++) { + ShortObjectPair pair = lightPatch.get(i); + lightOffsets[i] = pair.leftShort(); + lightStates[i] = pair.right(); + } + packets.add(new ClientboundSectionBlocksUpdatePacket(sectionPos, new ShortArraySet(lightOffsets), lightStates)); + } + packets.add(new ClientboundSectionBlocksUpdatePacket(sectionPos, new ShortArraySet(offsets), statesArr)); } - byte[] outputBytes = outputSerial.array(); - CHUNKDATA_BUFFER_SETTER.invoke(packet, outputBytes); - CHUNKPACKET_CHUNKDATA_SETTER.invoke(duplicateCorePacket, packet); - return duplicateCorePacket; - } - catch (Throwable ex) { - Debug.echoError(ex); + // Now that we have the final decision on the section having light or not, update the counters + if (hasBlockLight) { + blockLitSections++; + } + if (hasSkyLight) { + skyLitSections++; + } + newChunkData.writeShort(blockCount); + newChunkData.writeShort(fluidCount); + // A section that has been cleared out seemingly carries more data than a section that never had anything (SimpleBitStorage vs ZeroBitStorage) + if (blockCount > 0 || fluidCount > 0) { + states.write(newChunkData); + } + else { + EMPTY_BLOCKS_CONTAINER.write(newChunkData); + } + biomes.write(newChunkData); } - return null; + // The instance is already in the list, just update the underlying data + CHUNKDATA_BUFFER_SETTER.invokeExact(copiedChunkPacket.getChunkData(), newChunkData.array()); + return new ClientboundBundlePacket(packets); } } diff --git a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java index 55ffea84b7..245fcc155c 100644 --- a/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java +++ b/v26_2/src/main/java/com/denizenscript/denizen/nms/v26_2/impl/network/handlers/packet/FakeBlocksPacketHandlers.java @@ -6,106 +6,115 @@ import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.shorts.ShortArraySet; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.World; -import java.lang.reflect.Field; +import java.lang.invoke.MethodHandle; import java.util.Arrays; import java.util.List; public class FakeBlocksPacketHandlers { public static void registerHandlers() { - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelChunkWithLightPacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSectionBlocksUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); - DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processShowFakeForPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundLevelChunkWithLightPacket.class, FakeBlocksPacketHandlers::processLevelChunkWithLightPacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundSectionBlocksUpdatePacket.class, FakeBlocksPacketHandlers::processSectionBlocksUpdatePacket); + DenizenNetworkManagerImpl.registerPacketHandler(ClientboundBlockUpdatePacket.class, FakeBlocksPacketHandlers::processBlockUpdatePacket); } - public static Field SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("sectionPos", SectionPos.class); - public static Field OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("positions", short[].class); - public static Field BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).get("states", BlockState[].class); + public static final MethodHandle SECTIONPOS_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter("sectionPos", SectionPos.class); + public static final MethodHandle OFFSETARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter("positions", short[].class); + public static final MethodHandle BLOCKARRAY_MULTIBLOCKCHANGE = ReflectionHelper.getFields(ClientboundSectionBlocksUpdatePacket.class).getGetter("states", BlockState[].class); - public static Packet processShowFakeForPacket(DenizenNetworkManagerImpl networkManager, Packet packet) { + public static Packet processLevelChunkWithLightPacket(DenizenNetworkManagerImpl networkManager, ClientboundLevelChunkWithLightPacket chunkPacket) throws Throwable { if (FakeBlock.blocks.isEmpty()) { - return packet; + return chunkPacket; } - try { - if (packet instanceof ClientboundLevelChunkWithLightPacket) { - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return packet; - } - int chunkX = ((ClientboundLevelChunkWithLightPacket) packet).getX(); - int chunkZ = ((ClientboundLevelChunkWithLightPacket) packet).getZ(); - ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, networkManager.player.level().getWorld().getName()); - List blocks = FakeBlock.getFakeBlocksFor(networkManager.player.getUUID(), chunkCoord); - if (blocks == null || blocks.isEmpty()) { - return packet; - } - ClientboundLevelChunkWithLightPacket newPacket = FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), (ClientboundLevelChunkWithLightPacket) packet, chunkX, chunkZ, blocks); - return newPacket; - } - else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionBlocksUpdatePacket) { - FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); - if (map == null) { - return sectionBlocksUpdatePacket; - } - SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.get(sectionBlocksUpdatePacket); - ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); - if (!map.byChunk.containsKey(coordinateDenizen)) { - return sectionBlocksUpdatePacket; - } - ClientboundSectionBlocksUpdatePacket newPacket = DenizenNetworkManagerImpl.copyPacket(sectionBlocksUpdatePacket, ClientboundSectionBlocksUpdatePacket.STREAM_CODEC); - LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); - short[] originalOffsetArray = (short[])OFFSETARRAY_MULTIBLOCKCHANGE.get(newPacket); - BlockState[] originalDataArray = (BlockState[])BLOCKARRAY_MULTIBLOCKCHANGE.get(newPacket); - short[] offsetArray = Arrays.copyOf(originalOffsetArray, originalOffsetArray.length); - BlockState[] dataArray = Arrays.copyOf(originalDataArray, originalDataArray.length); - OFFSETARRAY_MULTIBLOCKCHANGE.set(newPacket, offsetArray); - BLOCKARRAY_MULTIBLOCKCHANGE.set(newPacket, dataArray); - for (int i = 0; i < offsetArray.length; i++) { - short offset = offsetArray[i]; - BlockPos pos = coord.relativeToBlockPos(offset); - location.setX(pos.getX()); - location.setY(pos.getY()); - location.setZ(pos.getZ()); - FakeBlock block = map.byLocation.get(location); - if (block != null) { - dataArray[i] = FakeBlockHelper.getNMSState(block); - } - } - return newPacket; - } - else if (packet instanceof ClientboundBlockUpdatePacket) { - BlockPos pos = ((ClientboundBlockUpdatePacket) packet).getPos(); - LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); - if (block != null) { - ClientboundBlockUpdatePacket newPacket = new ClientboundBlockUpdatePacket(((ClientboundBlockUpdatePacket) packet).getPos(), FakeBlockHelper.getNMSState(block)); - return newPacket; - } - } - else if (packet instanceof ClientboundBlockChangedAckPacket) { - // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. - /* - ClientboundBlockChangedAckPacket origPack = (ClientboundBlockChangedAckPacket) packet; - BlockPos pos = origPack.pos(); - LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); - FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); - if (block != null) { - ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(origPack.pos(), FakeBlockHelper.getNMSState(block), origPack.action(), false); - oldManager.send(newPacket, genericfuturelistener); - return true; - }*/ + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return chunkPacket; + } + int chunkX = chunkPacket.getX(); + int chunkZ = chunkPacket.getZ(); + World world = networkManager.player.level().getWorld(); + ChunkCoordinate chunkCoord = new ChunkCoordinate(chunkX, chunkZ, world.getName()); + Int2ObjectMap> blocksBySection = map.byChunk.get(chunkCoord); + if (blocksBySection == null || blocksBySection.isEmpty()) { + return chunkPacket; + } + return FakeBlockHelper.handleMapChunkPacket(networkManager.player.getBukkitEntity().getWorld(), chunkPacket, chunkX, chunkZ, blocksBySection, map); + } + + public static ClientboundSectionBlocksUpdatePacket processSectionBlocksUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundSectionBlocksUpdatePacket sectionUpdatePacket) throws Throwable { + if (FakeBlock.blocks.isEmpty()) { + return sectionUpdatePacket; + } + FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(networkManager.player.getUUID()); + if (map == null) { + return sectionUpdatePacket; + } + SectionPos coord = (SectionPos) SECTIONPOS_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); + ChunkCoordinate coordinateDenizen = new ChunkCoordinate(coord.getX(), coord.getZ(), networkManager.player.level().getWorld().getName()); + if (!map.byChunk.containsKey(coordinateDenizen)) { + return sectionUpdatePacket; + } + short[] originalOffsetArray = (short[]) OFFSETARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); + BlockState[] originalStatesArray = (BlockState[]) BLOCKARRAY_MULTIBLOCKCHANGE.invokeExact(sectionUpdatePacket); + BlockState[] statesArray = Arrays.copyOf(originalStatesArray, originalStatesArray.length); + LocationTag location = new LocationTag(networkManager.player.level().getWorld(), 0, 0, 0); + boolean hasAny = false; + for (int i = 0; i < originalOffsetArray.length; i++) { + short offset = originalOffsetArray[i]; + location.setX(coord.relativeToBlockX(offset)); + location.setY(coord.relativeToBlockY(offset)); + location.setZ(coord.relativeToBlockZ(offset)); + FakeBlock block = map.byLocation.get(location); + if (block != null) { + statesArray[i] = FakeBlockHelper.getNMSState(block); + hasAny = true; } } - catch (Throwable ex) { - Debug.echoError(ex); + if (!hasAny) { + return sectionUpdatePacket; + } + return new ClientboundSectionBlocksUpdatePacket(coord, new ShortArraySet(originalOffsetArray), statesArray); + } + + public static ClientboundBlockUpdatePacket processBlockUpdatePacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockUpdatePacket blockUpdatePacket) { + if (FakeBlock.blocks.isEmpty()) { + return blockUpdatePacket; + } + BlockPos pos = blockUpdatePacket.getPos(); + LocationTag loc = new LocationTag(networkManager.player.level().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(networkManager.player.getUUID(), loc); + if (block != null) { + return new ClientboundBlockUpdatePacket(blockUpdatePacket.getPos(), FakeBlockHelper.getNMSState(block)); + } + return blockUpdatePacket; + } + + // TODO: 1.19: Can no longer determine what block this packet is for. Would have to track separately? Possibly from the inbound packet rather than the outbound one. + /* + public static ClientboundBlockChangedAckPacket processBlockChangedAckPacket(DenizenNetworkManagerImpl networkManager, ClientboundBlockChangedAckPacket blockChangedAckPacket) { + if (FakeBlock.blocks.isEmpty()) { + return blockChangedAckPacket; + } + BlockPos pos = blockChangedAckPacket.pos(); + LocationTag loc = new LocationTag(player.getLevel().getWorld(), pos.getX(), pos.getY(), pos.getZ()); + FakeBlock block = FakeBlock.getFakeBlockFor(player.getUUID(), loc); + if (block != null) { + ClientboundBlockChangedAckPacket newPacket = new ClientboundBlockChangedAckPacket(blockChangedAckPacket.pos(), FakeBlockHelper.getNMSState(block), blockChangedAckPacket.action(), false); + oldManager.send(newPacket, genericfuturelistener); + return true; } - return packet; } + */ } From 06d94b4a2c69abe46e3839d55a9892803c2f889f Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 25 Aug 2026 08:21:23 +0100 Subject: [PATCH 168/169] Reflection Mappings fix --- .../nms/v1_21/ReflectionMappingsInfo.java | 9 ++----- .../network/handlers/FakeBlockHelper.java | 27 +++---------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index 72456a27ee..a9d446ba71 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -8,8 +8,7 @@ public class ReflectionMappingsInfo { public static String BlockBehaviour_explosionResistance = "G"; // net.minecraft.core.MappedRegistry - public static String MappedRegistry_frozen = "l"; - public static String MappedRegistry_unregisteredIntrusiveHolders = "m"; + public static String MappedRegistry_registrationInfos = "h"; // net.minecraft.world.entity.Entity public static String Entity_onGround = "bc"; @@ -104,7 +103,6 @@ public class ReflectionMappingsInfo { public static String ClientboundLevelChunkPacketData_blockEntitiesData = "e"; // net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo - public static String ClientboundLevelChunkPacketDataBlockEntityInfo_create_method = "a"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "c"; public static String ClientboundLevelChunkPacketDataBlockEntityInfo_y = "d"; @@ -133,7 +131,4 @@ public class ReflectionMappingsInfo { // net.minecraft.stats.ServerRecipeBook public static String ServerRecipeBook_addHighlight_method = "e"; - - // net.minecraft.world.level.block.entity.BlockEntityType - public static String BlockEntityType_validBlocks = "aa"; -} \ No newline at end of file +} diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java index 48a45edbbd..81b080b4d8 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/FakeBlockHelper.java @@ -14,7 +14,6 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.Packet; @@ -24,52 +23,34 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.LightBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.Strategy; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_21_R7.CraftRegistry; -import org.bukkit.craftbukkit.v1_21_R7.block.CraftBlockType; import org.bukkit.craftbukkit.v1_21_R7.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_21_R7.util.CraftLocation; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; -import java.util.*; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; +import java.util.ListIterator; public class FakeBlockHelper { public static final MethodHandle CHUNKDATA_BLOCK_ENTITIES = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_blockEntitiesData, List.class); public static final MethodHandle CHUNKDATA_BUFFER_SETTER = ReflectionHelper.getFields(ClientboundLevelChunkPacketData.class).getSetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketData_buffer, byte[].class); public static final Class CHUNKDATA_BLOCKENTITYINFO_CLASS = ClientboundLevelChunkPacketData.class.getDeclaredClasses()[0]; - public static final MethodHandle CHUNKDATA_BLOCK_ENTITY_CREATE = ReflectionHelper.getMethodHandle(CHUNKDATA_BLOCKENTITYINFO_CLASS, ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_create_method, BlockEntity.class); public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_PACKEDXZ = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ); public static final MethodHandle CHUNKDATA_BLOCKENTITYINFO_Y = ReflectionHelper.getFields(CHUNKDATA_BLOCKENTITYINFO_CLASS).getGetter(ReflectionMappingsInfo.ClientboundLevelChunkPacketDataBlockEntityInfo_y); - public static final MethodHandle BLOCK_ENTITY_TYPE_VALID_BLOCKS = ReflectionHelper.getFields(BlockEntityType.class).getGetter(ReflectionMappingsInfo.BlockEntityType_validBlocks, Set.class); public static final PalettedContainer EMPTY_BLOCKS_CONTAINER = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY)); - public static final Map> MATERIAL_BLOCK_ENTITY_TYPES = new HashMap<>(); public static final BlockState MAX_LIGHT_LIGHT_BLOCK = Blocks.LIGHT.defaultBlockState().setValue(LightBlock.LEVEL, 15), AIR = Blocks.AIR.defaultBlockState(); public static final byte[] MAX_LIGHT_SECTION = new DataLayer(15).getData(), MIN_LIGHT_SECTION = new DataLayer(0).getData(); - static { - try { - for (BlockEntityType nmsBlockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - Set validBlocks = (Set) BLOCK_ENTITY_TYPE_VALID_BLOCKS.invokeExact(nmsBlockEntityType); - for (Block validBlock : validBlocks) { - MATERIAL_BLOCK_ENTITY_TYPES.put(CraftBlockType.minecraftToBukkit(validBlock), nmsBlockEntityType); - } - } - } - catch (Throwable e) { - throw new RuntimeException(e); - } - } - public static BlockState getNMSState(FakeBlock block) { return ((CraftBlockData) block.material.getModernData()).getState(); } From c998cbc2818c3cc3ec9c82b823d0e6b896645b9e Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Tue, 25 Aug 2026 08:24:29 +0100 Subject: [PATCH 169/169] Minor cleanup --- .../denizen/nms/v1_21/ReflectionMappingsInfo.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java index a1e50ac985..1eefe598b5 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/ReflectionMappingsInfo.java @@ -126,7 +126,4 @@ public class ReflectionMappingsInfo { // net.minecraft.stats.ServerRecipeBook public static String ServerRecipeBook_addHighlight_method = "e"; - - // net.minecraft.world.level.block.entity.BlockEntityType - public static String BlockEntityType_validBlocks = "Y"; }