From 860543cf5e8d93db4f739991d6a9be11d6dfa65c Mon Sep 17 00:00:00 2001 From: Kaapo Date: Sun, 24 Dec 2023 01:27:54 +0200 Subject: [PATCH] Just adding 1.20 supports --- nms/pom.xml | 4 +- plugin/pom.xml | 36 ++- pom.xml | 8 +- v1_16_R3/pom.xml | 6 +- v1_17_R1/pom.xml | 6 +- v1_18_R1/pom.xml | 6 +- v1_18_R2/pom.xml | 6 +- v1_19_R1/pom.xml | 6 +- v1_20_R1/pom.xml | 94 +++++++ .../tileculling/adapter/Adapter_1_20_R1.java | 249 ++++++++++++++++++ v1_20_R2/pom.xml | 94 +++++++ .../tileculling/adapter/Adapter_1_20_R2.java | 249 ++++++++++++++++++ v1_20_R3/pom.xml | 94 +++++++ .../tileculling/adapter/Adapter_1_20_R3.java | 249 ++++++++++++++++++ v1_20_R4/pom.xml | 94 +++++++ .../tileculling/adapter/Adapter_1_20_R4.java | 249 ++++++++++++++++++ 16 files changed, 1423 insertions(+), 27 deletions(-) create mode 100644 v1_20_R1/pom.xml create mode 100644 v1_20_R1/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R1.java create mode 100644 v1_20_R2/pom.xml create mode 100644 v1_20_R2/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R2.java create mode 100644 v1_20_R3/pom.xml create mode 100644 v1_20_R3/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R3.java create mode 100644 v1_20_R4/pom.xml create mode 100644 v1_20_R4/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R4.java diff --git a/nms/pom.xml b/nms/pom.xml index c35f139..98bc043 100644 --- a/nms/pom.xml +++ b/nms/pom.xml @@ -7,11 +7,11 @@ it.feargames.tileculling tileculling-parent - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT ../pom.xml tileculling-nms - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT diff --git a/plugin/pom.xml b/plugin/pom.xml index 9bd6127..2797bb4 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -7,38 +7,58 @@ it.feargames.tileculling tileculling-parent - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT ../pom.xml tileculling-plugin - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-v1_16_R3 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-v1_17_R1 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-v1_18_R1 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-v1_18_R2 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-v1_19_R1 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT + + + it.feargames.tileculling + tileculling-v1_20_R1 + 1.2.6-SNAPSHOT + + + it.feargames.tileculling + tileculling-v1_20_R2 + 1.2.6-SNAPSHOT + + + it.feargames.tileculling + tileculling-v1_20_R3 + 1.2.6-SNAPSHOT + + + it.feargames.tileculling + tileculling-v1_20_R4 + 1.2.6-SNAPSHOT it.unimi.dsi @@ -49,7 +69,7 @@ com.logisticscraft occlusionculling - 0.0.6-SNAPSHOT + 0.0.7-SNAPSHOT diff --git a/pom.xml b/pom.xml index 680fe0a..ca974f3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ it.feargames.tileculling tileculling-parent - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT pom @@ -16,6 +16,10 @@ v1_18_R1 v1_18_R2 v1_19_R1 + v1_20_R1 + v1_20_R2 + v1_20_R3 + v1_20_R4 plugin @@ -61,7 +65,7 @@ com.comphenix.protocol ProtocolLib - 4.6.0 + 5.1.0 provided diff --git a/v1_16_R3/pom.xml b/v1_16_R3/pom.xml index 8b0fad3..e773e3e 100644 --- a/v1_16_R3/pom.xml +++ b/v1_16_R3/pom.xml @@ -7,18 +7,18 @@ it.feargames.tileculling tileculling-parent - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT ../pom.xml tileculling-v1_16_R3 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-nms - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT org.spigotmc diff --git a/v1_17_R1/pom.xml b/v1_17_R1/pom.xml index b61e0a5..0ecc5b4 100644 --- a/v1_17_R1/pom.xml +++ b/v1_17_R1/pom.xml @@ -7,18 +7,18 @@ it.feargames.tileculling tileculling-parent - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT ../pom.xml tileculling-v1_17_R1 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-nms - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT org.spigotmc diff --git a/v1_18_R1/pom.xml b/v1_18_R1/pom.xml index ed89aba..a8f8e6d 100644 --- a/v1_18_R1/pom.xml +++ b/v1_18_R1/pom.xml @@ -7,18 +7,18 @@ it.feargames.tileculling tileculling-parent - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT ../pom.xml tileculling-v1_18_R1 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-nms - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT org.spigotmc diff --git a/v1_18_R2/pom.xml b/v1_18_R2/pom.xml index 2289986..21f91c5 100644 --- a/v1_18_R2/pom.xml +++ b/v1_18_R2/pom.xml @@ -7,18 +7,18 @@ it.feargames.tileculling tileculling-parent - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT ../pom.xml tileculling-v1_18_R2 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-nms - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT org.spigotmc diff --git a/v1_19_R1/pom.xml b/v1_19_R1/pom.xml index 386543e..737fd9d 100644 --- a/v1_19_R1/pom.xml +++ b/v1_19_R1/pom.xml @@ -7,18 +7,18 @@ it.feargames.tileculling tileculling-parent - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT ../pom.xml tileculling-v1_19_R1 - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT it.feargames.tileculling tileculling-nms - 1.2.5-SNAPSHOT + 1.2.6-SNAPSHOT org.spigotmc diff --git a/v1_20_R1/pom.xml b/v1_20_R1/pom.xml new file mode 100644 index 0000000..9d4bffa --- /dev/null +++ b/v1_20_R1/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + + it.feargames.tileculling + tileculling-parent + 1.2.6-SNAPSHOT + ../pom.xml + + + tileculling-v1_20_R1 + 1.2.6-SNAPSHOT + + + + it.feargames.tileculling + tileculling-nms + 1.2.6-SNAPSHOT + + + org.spigotmc + spigot + 1.20.1-R0.1-SNAPSHOT + remapped-mojang + provided + + + org.spigotmc + spigot-api + 1.20.1-R0.1-SNAPSHOT + provided + + + io.netty + netty-all + 4.1.77.Final + provided + + + it.unimi.dsi + fastutil + 8.5.6 + provided + + + com.comphenix.protocol + ProtocolLib + 5.0.0-SNAPSHOT + provided + + + + + + + net.md-5 + specialsource-maven-plugin + 1.2.4 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.20.1-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.20.1-R0.1-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.20.1-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.20.1-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + + diff --git a/v1_20_R1/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R1.java b/v1_20_R1/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R1.java new file mode 100644 index 0000000..007379e --- /dev/null +++ b/v1_20_R1/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R1.java @@ -0,0 +1,249 @@ +package it.feargames.tileculling.adapter; + +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.WrappedLevelChunkData; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CherryLeavesBlock; +import net.minecraft.world.level.block.ChiseledBookShelfBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; + +@SuppressWarnings({"unused"}) +public class Adapter_1_20_R1 implements IAdapter { + + private static final Constructor BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR; + + static { + try { + BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR = ClientboundBlockEntityDataPacket.class.getDeclaredConstructor( + BlockPos.class, BlockEntityType.class, CompoundTag.class); + BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void updateBlockState(Player player, Location location, BlockData blockData) { + CraftPlayer craftPlayer = (CraftPlayer) player; + ServerPlayer handlePlayer = craftPlayer.getHandle(); + ServerPlayerConnection connection = handlePlayer.connection; + if (connection == null) { + return; + } + + BlockPos blockPosition = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockState handleData = blockData == null ? Blocks.AIR.defaultBlockState() : ((CraftBlockData) blockData).getState(); + ClientboundBlockUpdatePacket blockChange = new ClientboundBlockUpdatePacket(blockPosition, handleData); + connection.send(blockChange); + } + + @Override + public void updateBlockData(Player player, Location location, org.bukkit.block.BlockState block) { + CraftPlayer craftPlayer = (CraftPlayer) player; + ServerPlayer handlePlayer = craftPlayer.getHandle(); + ServerPlayerConnection connection = handlePlayer.connection; + if (connection == null) { + return; + } + + BlockEntityType type; + if (block instanceof Smoker) { + type = BlockEntityType.SMOKER; + } else if (block instanceof BlastFurnace) { + type = BlockEntityType.BLAST_FURNACE; + } else if (block instanceof Furnace) { + type = BlockEntityType.FURNACE; + } else if (block instanceof Chest) { + type = block.getType() == Material.TRAPPED_CHEST ? BlockEntityType.TRAPPED_CHEST : BlockEntityType.CHEST; // FIXME + } else if (block instanceof EnderChest) { + type = BlockEntityType.ENDER_CHEST; + } else if (block instanceof Jukebox) { + type = BlockEntityType.JUKEBOX; + } else if (block instanceof Dispenser) { + type = BlockEntityType.DISPENSER; + } else if (block instanceof Dropper) { + type = BlockEntityType.DROPPER; + } else if (block instanceof Sign) { + type = BlockEntityType.SIGN; + } else if (block instanceof CreatureSpawner) { + type = BlockEntityType.MOB_SPAWNER; + } else if (block.getType() == Material.PISTON_HEAD) { // FIXME + type = BlockEntityType.PISTON; + } else if (block instanceof BrewingStand) { + type = BlockEntityType.BREWING_STAND; + } else if (block instanceof EnchantingTable) { + type = BlockEntityType.ENCHANTING_TABLE; + } else if (block.getType() == Material.END_PORTAL) { // FIXME + type = BlockEntityType.END_PORTAL; + } else if (block instanceof Beacon) { + type = BlockEntityType.BEACON; + } else if (block instanceof Skull) { + type = BlockEntityType.SKULL; + } else if (block instanceof DaylightDetector) { + type = BlockEntityType.DAYLIGHT_DETECTOR; + } else if (block instanceof Hopper) { + type = BlockEntityType.HOPPER; + } else if (block instanceof Comparator) { + type = BlockEntityType.COMPARATOR; + } else if (block instanceof Banner) { + type = BlockEntityType.BANNER; + } else if (block instanceof Structure) { + type = BlockEntityType.STRUCTURE_BLOCK; + } else if (block instanceof EndGateway) { + type = BlockEntityType.END_GATEWAY; + } else if (block instanceof CommandBlock) { + type = BlockEntityType.COMMAND_BLOCK; + } else if (block instanceof ShulkerBox) { + type = BlockEntityType.SHULKER_BOX; + } else if (block instanceof Bed) { // FIXME + type = BlockEntityType.BED; + } else if (block instanceof Conduit) { + type = BlockEntityType.CONDUIT; + } else if (block instanceof Barrel) { + type = BlockEntityType.BARREL; + } else if (block instanceof Lectern) { + type = BlockEntityType.LECTERN; + } else if (block instanceof Bell) { + type = BlockEntityType.BELL; + } else if (block instanceof Jigsaw) { + type = BlockEntityType.JIGSAW; + } else if (block instanceof Campfire) { + type = BlockEntityType.CAMPFIRE; + } else if (block instanceof Beehive) { + type = BlockEntityType.BEEHIVE; + } else if (block instanceof SculkSensor) { + type = BlockEntityType.SCULK_SENSOR; + } else if (block instanceof SculkCatalyst) { + type = BlockEntityType.SCULK_CATALYST; + } else if (block instanceof SculkShrieker) { + type = BlockEntityType.SCULK_SHRIEKER; + } else if (block instanceof ChiseledBookshelf) { + type = BlockEntityType.CHISELED_BOOKSHELF; + } else if (block instanceof BrushableBlock) { + type = BlockEntityType.BRUSHABLE_BLOCK; + } else if (block instanceof DecoratedPot) { + type = BlockEntityType.DECORATED_POT; + } else { + return; + } + + CraftBlockEntityState craftBlockEntityState = (CraftBlockEntityState) block; + CompoundTag nbt = craftBlockEntityState.getSnapshotNBT(); + BlockPos blockPosition = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + ClientboundBlockEntityDataPacket packet; + try { + packet = BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR.newInstance(blockPosition, type, nbt); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + connection.send(packet); + } + + @Override + public void transformPacket(Player player, PacketContainer container, Function tileEntityTypeFilter) { + CraftWorld craftWorld = (CraftWorld) player.getWorld(); + ServerLevel vanillaWorld = craftWorld.getHandle(); + + WrappedLevelChunkData.ChunkData data = container.getLevelChunkData().read(0); + + List blockTileEntities = data.getBlockEntityInfo(); + + IntList removedBlocks = null; + for (Iterator iterator = blockTileEntities.iterator(); iterator.hasNext(); ) { + WrappedLevelChunkData.BlockEntityInfo tileEntity = iterator.next(); + + String type = tileEntity.getTypeKey().getKey(); + if (!tileEntityTypeFilter.apply(type)) { + continue; + } + + iterator.remove(); + + if (removedBlocks == null) { + removedBlocks = new IntArrayList(); + } + + short y = (short) tileEntity.getY(); + + byte x = (byte) tileEntity.getSectionX(); + byte z = (byte) tileEntity.getSectionZ(); + + // Y, X, Z + int key = (y & 0xFFFF) | ((x & 0xF) << 16) | ((z & 0xF) << 20); + removedBlocks.add(key); + } + + if (removedBlocks == null) { + return; + } + + byte[] readerBuffer = data.getBuffer(); + FriendlyByteBuf reader = new FriendlyByteBuf(Unpooled.wrappedBuffer(readerBuffer)); + + int bufferSize = 0; + LevelChunkSection[] sections = new LevelChunkSection[vanillaWorld.getSectionsCount()]; + for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) { + int yOffset = vanillaWorld.getSectionYFromSectionIndex(sectionIndex); + LevelChunkSection section = new LevelChunkSection(vanillaWorld.registryAccess().registryOrThrow(Registries.BIOME)); + section.read(reader); + + for (byte y = 0; y < 16; y++) { + for (byte z = 0; z < 16; z++) { + for (byte x = 0; x < 16; x++) { + int key = ((yOffset + y) & 0xFFFF) | ((x & 0xF) << 16) | ((z & 0xF) << 20); + if (!removedBlocks.contains(key)) { + continue; + } + section.setBlockState(x, y, z, Blocks.AIR.defaultBlockState(), false); + } + } + } + + sections[sectionIndex] = section; + bufferSize += section.getSerializedSize(); + } + + byte[] writerBuffer = new byte[bufferSize]; + FriendlyByteBuf writer = new FriendlyByteBuf(Unpooled.wrappedBuffer(writerBuffer)); + writer.writerIndex(0); + + for (LevelChunkSection section : sections) { + section.write(writer); + } + + data.setBuffer(writerBuffer); + + container.getLevelChunkData().write(0, data); + } + +} diff --git a/v1_20_R2/pom.xml b/v1_20_R2/pom.xml new file mode 100644 index 0000000..49b6f19 --- /dev/null +++ b/v1_20_R2/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + + it.feargames.tileculling + tileculling-parent + 1.2.6-SNAPSHOT + ../pom.xml + + + tileculling-v1_20_R2 + 1.2.6-SNAPSHOT + + + + it.feargames.tileculling + tileculling-nms + 1.2.6-SNAPSHOT + + + org.spigotmc + spigot + 1.20.2-R0.1-SNAPSHOT + remapped-mojang + provided + + + org.spigotmc + spigot-api + 1.20.2-R0.1-SNAPSHOT + provided + + + io.netty + netty-all + 4.1.77.Final + provided + + + it.unimi.dsi + fastutil + 8.5.6 + provided + + + com.comphenix.protocol + ProtocolLib + 5.0.0-SNAPSHOT + provided + + + + + + + net.md-5 + specialsource-maven-plugin + 1.2.4 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.20.2-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.20.2-R0.1-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.20.2-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.20.2-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + + diff --git a/v1_20_R2/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R2.java b/v1_20_R2/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R2.java new file mode 100644 index 0000000..fbfad85 --- /dev/null +++ b/v1_20_R2/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R2.java @@ -0,0 +1,249 @@ +package it.feargames.tileculling.adapter; + +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.WrappedLevelChunkData; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CherryLeavesBlock; +import net.minecraft.world.level.block.ChiseledBookShelfBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; + +@SuppressWarnings({"unused"}) +public class Adapter_1_20_R2 implements IAdapter { + + private static final Constructor BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR; + + static { + try { + BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR = ClientboundBlockEntityDataPacket.class.getDeclaredConstructor( + BlockPos.class, BlockEntityType.class, CompoundTag.class); + BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void updateBlockState(Player player, Location location, BlockData blockData) { + CraftPlayer craftPlayer = (CraftPlayer) player; + ServerPlayer handlePlayer = craftPlayer.getHandle(); + ServerPlayerConnection connection = handlePlayer.connection; + if (connection == null) { + return; + } + + BlockPos blockPosition = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockState handleData = blockData == null ? Blocks.AIR.defaultBlockState() : ((CraftBlockData) blockData).getState(); + ClientboundBlockUpdatePacket blockChange = new ClientboundBlockUpdatePacket(blockPosition, handleData); + connection.send(blockChange); + } + + @Override + public void updateBlockData(Player player, Location location, org.bukkit.block.BlockState block) { + CraftPlayer craftPlayer = (CraftPlayer) player; + ServerPlayer handlePlayer = craftPlayer.getHandle(); + ServerPlayerConnection connection = handlePlayer.connection; + if (connection == null) { + return; + } + + BlockEntityType type; + if (block instanceof Smoker) { + type = BlockEntityType.SMOKER; + } else if (block instanceof BlastFurnace) { + type = BlockEntityType.BLAST_FURNACE; + } else if (block instanceof Furnace) { + type = BlockEntityType.FURNACE; + } else if (block instanceof Chest) { + type = block.getType() == Material.TRAPPED_CHEST ? BlockEntityType.TRAPPED_CHEST : BlockEntityType.CHEST; // FIXME + } else if (block instanceof EnderChest) { + type = BlockEntityType.ENDER_CHEST; + } else if (block instanceof Jukebox) { + type = BlockEntityType.JUKEBOX; + } else if (block instanceof Dispenser) { + type = BlockEntityType.DISPENSER; + } else if (block instanceof Dropper) { + type = BlockEntityType.DROPPER; + } else if (block instanceof Sign) { + type = BlockEntityType.SIGN; + } else if (block instanceof CreatureSpawner) { + type = BlockEntityType.MOB_SPAWNER; + } else if (block.getType() == Material.PISTON_HEAD) { // FIXME + type = BlockEntityType.PISTON; + } else if (block instanceof BrewingStand) { + type = BlockEntityType.BREWING_STAND; + } else if (block instanceof EnchantingTable) { + type = BlockEntityType.ENCHANTING_TABLE; + } else if (block.getType() == Material.END_PORTAL) { // FIXME + type = BlockEntityType.END_PORTAL; + } else if (block instanceof Beacon) { + type = BlockEntityType.BEACON; + } else if (block instanceof Skull) { + type = BlockEntityType.SKULL; + } else if (block instanceof DaylightDetector) { + type = BlockEntityType.DAYLIGHT_DETECTOR; + } else if (block instanceof Hopper) { + type = BlockEntityType.HOPPER; + } else if (block instanceof Comparator) { + type = BlockEntityType.COMPARATOR; + } else if (block instanceof Banner) { + type = BlockEntityType.BANNER; + } else if (block instanceof Structure) { + type = BlockEntityType.STRUCTURE_BLOCK; + } else if (block instanceof EndGateway) { + type = BlockEntityType.END_GATEWAY; + } else if (block instanceof CommandBlock) { + type = BlockEntityType.COMMAND_BLOCK; + } else if (block instanceof ShulkerBox) { + type = BlockEntityType.SHULKER_BOX; + } else if (block instanceof Bed) { // FIXME + type = BlockEntityType.BED; + } else if (block instanceof Conduit) { + type = BlockEntityType.CONDUIT; + } else if (block instanceof Barrel) { + type = BlockEntityType.BARREL; + } else if (block instanceof Lectern) { + type = BlockEntityType.LECTERN; + } else if (block instanceof Bell) { + type = BlockEntityType.BELL; + } else if (block instanceof Jigsaw) { + type = BlockEntityType.JIGSAW; + } else if (block instanceof Campfire) { + type = BlockEntityType.CAMPFIRE; + } else if (block instanceof Beehive) { + type = BlockEntityType.BEEHIVE; + } else if (block instanceof SculkSensor) { + type = BlockEntityType.SCULK_SENSOR; + } else if (block instanceof SculkCatalyst) { + type = BlockEntityType.SCULK_CATALYST; + } else if (block instanceof SculkShrieker) { + type = BlockEntityType.SCULK_SHRIEKER; + } else if (block instanceof ChiseledBookshelf) { + type = BlockEntityType.CHISELED_BOOKSHELF; + } else if (block instanceof BrushableBlock) { + type = BlockEntityType.BRUSHABLE_BLOCK; + } else if (block instanceof DecoratedPot) { + type = BlockEntityType.DECORATED_POT; + } else { + return; + } + + CraftBlockEntityState craftBlockEntityState = (CraftBlockEntityState) block; + CompoundTag nbt = craftBlockEntityState.getSnapshotNBT(); + BlockPos blockPosition = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + ClientboundBlockEntityDataPacket packet; + try { + packet = BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR.newInstance(blockPosition, type, nbt); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + connection.send(packet); + } + + @Override + public void transformPacket(Player player, PacketContainer container, Function tileEntityTypeFilter) { + CraftWorld craftWorld = (CraftWorld) player.getWorld(); + ServerLevel vanillaWorld = craftWorld.getHandle(); + + WrappedLevelChunkData.ChunkData data = container.getLevelChunkData().read(0); + + List blockTileEntities = data.getBlockEntityInfo(); + + IntList removedBlocks = null; + for (Iterator iterator = blockTileEntities.iterator(); iterator.hasNext(); ) { + WrappedLevelChunkData.BlockEntityInfo tileEntity = iterator.next(); + + String type = tileEntity.getTypeKey().getKey(); + if (!tileEntityTypeFilter.apply(type)) { + continue; + } + + iterator.remove(); + + if (removedBlocks == null) { + removedBlocks = new IntArrayList(); + } + + short y = (short) tileEntity.getY(); + + byte x = (byte) tileEntity.getSectionX(); + byte z = (byte) tileEntity.getSectionZ(); + + // Y, X, Z + int key = (y & 0xFFFF) | ((x & 0xF) << 16) | ((z & 0xF) << 20); + removedBlocks.add(key); + } + + if (removedBlocks == null) { + return; + } + + byte[] readerBuffer = data.getBuffer(); + FriendlyByteBuf reader = new FriendlyByteBuf(Unpooled.wrappedBuffer(readerBuffer)); + + int bufferSize = 0; + LevelChunkSection[] sections = new LevelChunkSection[vanillaWorld.getSectionsCount()]; + for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) { + int yOffset = vanillaWorld.getSectionYFromSectionIndex(sectionIndex); + LevelChunkSection section = new LevelChunkSection(vanillaWorld.registryAccess().registryOrThrow(Registries.BIOME)); + section.read(reader); + + for (byte y = 0; y < 16; y++) { + for (byte z = 0; z < 16; z++) { + for (byte x = 0; x < 16; x++) { + int key = ((yOffset + y) & 0xFFFF) | ((x & 0xF) << 16) | ((z & 0xF) << 20); + if (!removedBlocks.contains(key)) { + continue; + } + section.setBlockState(x, y, z, Blocks.AIR.defaultBlockState(), false); + } + } + } + + sections[sectionIndex] = section; + bufferSize += section.getSerializedSize(); + } + + byte[] writerBuffer = new byte[bufferSize]; + FriendlyByteBuf writer = new FriendlyByteBuf(Unpooled.wrappedBuffer(writerBuffer)); + writer.writerIndex(0); + + for (LevelChunkSection section : sections) { + section.write(writer); + } + + data.setBuffer(writerBuffer); + + container.getLevelChunkData().write(0, data); + } + +} diff --git a/v1_20_R3/pom.xml b/v1_20_R3/pom.xml new file mode 100644 index 0000000..8b61b23 --- /dev/null +++ b/v1_20_R3/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + + it.feargames.tileculling + tileculling-parent + 1.2.6-SNAPSHOT + ../pom.xml + + + tileculling-v1_20_R3 + 1.2.6-SNAPSHOT + + + + it.feargames.tileculling + tileculling-nms + 1.2.6-SNAPSHOT + + + org.spigotmc + spigot + 1.20.3-R0.1-SNAPSHOT + remapped-mojang + provided + + + org.spigotmc + spigot-api + 1.20.3-R0.1-SNAPSHOT + provided + + + io.netty + netty-all + 4.1.77.Final + provided + + + it.unimi.dsi + fastutil + 8.5.6 + provided + + + com.comphenix.protocol + ProtocolLib + 5.0.0-SNAPSHOT + provided + + + + + + + net.md-5 + specialsource-maven-plugin + 1.2.4 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.20.3-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.20.3-R0.1-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.20.3-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.20.3-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + + diff --git a/v1_20_R3/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R3.java b/v1_20_R3/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R3.java new file mode 100644 index 0000000..7c391cf --- /dev/null +++ b/v1_20_R3/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R3.java @@ -0,0 +1,249 @@ +package it.feargames.tileculling.adapter; + +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.WrappedLevelChunkData; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CherryLeavesBlock; +import net.minecraft.world.level.block.ChiseledBookShelfBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; + +@SuppressWarnings({"unused"}) +public class Adapter_1_20_R3 implements IAdapter { + + private static final Constructor BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR; + + static { + try { + BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR = ClientboundBlockEntityDataPacket.class.getDeclaredConstructor( + BlockPos.class, BlockEntityType.class, CompoundTag.class); + BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void updateBlockState(Player player, Location location, BlockData blockData) { + CraftPlayer craftPlayer = (CraftPlayer) player; + ServerPlayer handlePlayer = craftPlayer.getHandle(); + ServerPlayerConnection connection = handlePlayer.connection; + if (connection == null) { + return; + } + + BlockPos blockPosition = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockState handleData = blockData == null ? Blocks.AIR.defaultBlockState() : ((CraftBlockData) blockData).getState(); + ClientboundBlockUpdatePacket blockChange = new ClientboundBlockUpdatePacket(blockPosition, handleData); + connection.send(blockChange); + } + + @Override + public void updateBlockData(Player player, Location location, org.bukkit.block.BlockState block) { + CraftPlayer craftPlayer = (CraftPlayer) player; + ServerPlayer handlePlayer = craftPlayer.getHandle(); + ServerPlayerConnection connection = handlePlayer.connection; + if (connection == null) { + return; + } + + BlockEntityType type; + if (block instanceof Smoker) { + type = BlockEntityType.SMOKER; + } else if (block instanceof BlastFurnace) { + type = BlockEntityType.BLAST_FURNACE; + } else if (block instanceof Furnace) { + type = BlockEntityType.FURNACE; + } else if (block instanceof Chest) { + type = block.getType() == Material.TRAPPED_CHEST ? BlockEntityType.TRAPPED_CHEST : BlockEntityType.CHEST; // FIXME + } else if (block instanceof EnderChest) { + type = BlockEntityType.ENDER_CHEST; + } else if (block instanceof Jukebox) { + type = BlockEntityType.JUKEBOX; + } else if (block instanceof Dispenser) { + type = BlockEntityType.DISPENSER; + } else if (block instanceof Dropper) { + type = BlockEntityType.DROPPER; + } else if (block instanceof Sign) { + type = BlockEntityType.SIGN; + } else if (block instanceof CreatureSpawner) { + type = BlockEntityType.MOB_SPAWNER; + } else if (block.getType() == Material.PISTON_HEAD) { // FIXME + type = BlockEntityType.PISTON; + } else if (block instanceof BrewingStand) { + type = BlockEntityType.BREWING_STAND; + } else if (block instanceof EnchantingTable) { + type = BlockEntityType.ENCHANTING_TABLE; + } else if (block.getType() == Material.END_PORTAL) { // FIXME + type = BlockEntityType.END_PORTAL; + } else if (block instanceof Beacon) { + type = BlockEntityType.BEACON; + } else if (block instanceof Skull) { + type = BlockEntityType.SKULL; + } else if (block instanceof DaylightDetector) { + type = BlockEntityType.DAYLIGHT_DETECTOR; + } else if (block instanceof Hopper) { + type = BlockEntityType.HOPPER; + } else if (block instanceof Comparator) { + type = BlockEntityType.COMPARATOR; + } else if (block instanceof Banner) { + type = BlockEntityType.BANNER; + } else if (block instanceof Structure) { + type = BlockEntityType.STRUCTURE_BLOCK; + } else if (block instanceof EndGateway) { + type = BlockEntityType.END_GATEWAY; + } else if (block instanceof CommandBlock) { + type = BlockEntityType.COMMAND_BLOCK; + } else if (block instanceof ShulkerBox) { + type = BlockEntityType.SHULKER_BOX; + } else if (block instanceof Bed) { // FIXME + type = BlockEntityType.BED; + } else if (block instanceof Conduit) { + type = BlockEntityType.CONDUIT; + } else if (block instanceof Barrel) { + type = BlockEntityType.BARREL; + } else if (block instanceof Lectern) { + type = BlockEntityType.LECTERN; + } else if (block instanceof Bell) { + type = BlockEntityType.BELL; + } else if (block instanceof Jigsaw) { + type = BlockEntityType.JIGSAW; + } else if (block instanceof Campfire) { + type = BlockEntityType.CAMPFIRE; + } else if (block instanceof Beehive) { + type = BlockEntityType.BEEHIVE; + } else if (block instanceof SculkSensor) { + type = BlockEntityType.SCULK_SENSOR; + } else if (block instanceof SculkCatalyst) { + type = BlockEntityType.SCULK_CATALYST; + } else if (block instanceof SculkShrieker) { + type = BlockEntityType.SCULK_SHRIEKER; + } else if (block instanceof ChiseledBookshelf) { + type = BlockEntityType.CHISELED_BOOKSHELF; + } else if (block instanceof BrushableBlock) { + type = BlockEntityType.BRUSHABLE_BLOCK; + } else if (block instanceof DecoratedPot) { + type = BlockEntityType.DECORATED_POT; + } else { + return; + } + + CraftBlockEntityState craftBlockEntityState = (CraftBlockEntityState) block; + CompoundTag nbt = craftBlockEntityState.getSnapshotNBT(); + BlockPos blockPosition = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + ClientboundBlockEntityDataPacket packet; + try { + packet = BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR.newInstance(blockPosition, type, nbt); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + connection.send(packet); + } + + @Override + public void transformPacket(Player player, PacketContainer container, Function tileEntityTypeFilter) { + CraftWorld craftWorld = (CraftWorld) player.getWorld(); + ServerLevel vanillaWorld = craftWorld.getHandle(); + + WrappedLevelChunkData.ChunkData data = container.getLevelChunkData().read(0); + + List blockTileEntities = data.getBlockEntityInfo(); + + IntList removedBlocks = null; + for (Iterator iterator = blockTileEntities.iterator(); iterator.hasNext(); ) { + WrappedLevelChunkData.BlockEntityInfo tileEntity = iterator.next(); + + String type = tileEntity.getTypeKey().getKey(); + if (!tileEntityTypeFilter.apply(type)) { + continue; + } + + iterator.remove(); + + if (removedBlocks == null) { + removedBlocks = new IntArrayList(); + } + + short y = (short) tileEntity.getY(); + + byte x = (byte) tileEntity.getSectionX(); + byte z = (byte) tileEntity.getSectionZ(); + + // Y, X, Z + int key = (y & 0xFFFF) | ((x & 0xF) << 16) | ((z & 0xF) << 20); + removedBlocks.add(key); + } + + if (removedBlocks == null) { + return; + } + + byte[] readerBuffer = data.getBuffer(); + FriendlyByteBuf reader = new FriendlyByteBuf(Unpooled.wrappedBuffer(readerBuffer)); + + int bufferSize = 0; + LevelChunkSection[] sections = new LevelChunkSection[vanillaWorld.getSectionsCount()]; + for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) { + int yOffset = vanillaWorld.getSectionYFromSectionIndex(sectionIndex); + LevelChunkSection section = new LevelChunkSection(vanillaWorld.registryAccess().registryOrThrow(Registries.BIOME)); + section.read(reader); + + for (byte y = 0; y < 16; y++) { + for (byte z = 0; z < 16; z++) { + for (byte x = 0; x < 16; x++) { + int key = ((yOffset + y) & 0xFFFF) | ((x & 0xF) << 16) | ((z & 0xF) << 20); + if (!removedBlocks.contains(key)) { + continue; + } + section.setBlockState(x, y, z, Blocks.AIR.defaultBlockState(), false); + } + } + } + + sections[sectionIndex] = section; + bufferSize += section.getSerializedSize(); + } + + byte[] writerBuffer = new byte[bufferSize]; + FriendlyByteBuf writer = new FriendlyByteBuf(Unpooled.wrappedBuffer(writerBuffer)); + writer.writerIndex(0); + + for (LevelChunkSection section : sections) { + section.write(writer); + } + + data.setBuffer(writerBuffer); + + container.getLevelChunkData().write(0, data); + } + +} diff --git a/v1_20_R4/pom.xml b/v1_20_R4/pom.xml new file mode 100644 index 0000000..44256fb --- /dev/null +++ b/v1_20_R4/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + + it.feargames.tileculling + tileculling-parent + 1.2.6-SNAPSHOT + ../pom.xml + + + tileculling-v1_20_R4 + 1.2.6-SNAPSHOT + + + + it.feargames.tileculling + tileculling-nms + 1.2.6-SNAPSHOT + + + org.spigotmc + spigot + 1.20.4-R0.1-SNAPSHOT + remapped-mojang + provided + + + org.spigotmc + spigot-api + 1.20.4-R0.1-SNAPSHOT + provided + + + io.netty + netty-all + 4.1.77.Final + provided + + + it.unimi.dsi + fastutil + 8.5.6 + provided + + + com.comphenix.protocol + ProtocolLib + 5.0.0-SNAPSHOT + provided + + + + + + + net.md-5 + specialsource-maven-plugin + 1.2.4 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.20.4-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.20.4-R0.1-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.20.4-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + + diff --git a/v1_20_R4/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R4.java b/v1_20_R4/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R4.java new file mode 100644 index 0000000..d555026 --- /dev/null +++ b/v1_20_R4/src/main/java/it/feargames/tileculling/adapter/Adapter_1_20_R4.java @@ -0,0 +1,249 @@ +package it.feargames.tileculling.adapter; + +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.WrappedLevelChunkData; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CherryLeavesBlock; +import net.minecraft.world.level.block.ChiseledBookShelfBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; + +@SuppressWarnings({"unused"}) +public class Adapter_1_20_R4 implements IAdapter { + + private static final Constructor BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR; + + static { + try { + BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR = ClientboundBlockEntityDataPacket.class.getDeclaredConstructor( + BlockPos.class, BlockEntityType.class, CompoundTag.class); + BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void updateBlockState(Player player, Location location, BlockData blockData) { + CraftPlayer craftPlayer = (CraftPlayer) player; + ServerPlayer handlePlayer = craftPlayer.getHandle(); + ServerPlayerConnection connection = handlePlayer.connection; + if (connection == null) { + return; + } + + BlockPos blockPosition = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockState handleData = blockData == null ? Blocks.AIR.defaultBlockState() : ((CraftBlockData) blockData).getState(); + ClientboundBlockUpdatePacket blockChange = new ClientboundBlockUpdatePacket(blockPosition, handleData); + connection.send(blockChange); + } + + @Override + public void updateBlockData(Player player, Location location, org.bukkit.block.BlockState block) { + CraftPlayer craftPlayer = (CraftPlayer) player; + ServerPlayer handlePlayer = craftPlayer.getHandle(); + ServerPlayerConnection connection = handlePlayer.connection; + if (connection == null) { + return; + } + + BlockEntityType type; + if (block instanceof Smoker) { + type = BlockEntityType.SMOKER; + } else if (block instanceof BlastFurnace) { + type = BlockEntityType.BLAST_FURNACE; + } else if (block instanceof Furnace) { + type = BlockEntityType.FURNACE; + } else if (block instanceof Chest) { + type = block.getType() == Material.TRAPPED_CHEST ? BlockEntityType.TRAPPED_CHEST : BlockEntityType.CHEST; // FIXME + } else if (block instanceof EnderChest) { + type = BlockEntityType.ENDER_CHEST; + } else if (block instanceof Jukebox) { + type = BlockEntityType.JUKEBOX; + } else if (block instanceof Dispenser) { + type = BlockEntityType.DISPENSER; + } else if (block instanceof Dropper) { + type = BlockEntityType.DROPPER; + } else if (block instanceof Sign) { + type = BlockEntityType.SIGN; + } else if (block instanceof CreatureSpawner) { + type = BlockEntityType.MOB_SPAWNER; + } else if (block.getType() == Material.PISTON_HEAD) { // FIXME + type = BlockEntityType.PISTON; + } else if (block instanceof BrewingStand) { + type = BlockEntityType.BREWING_STAND; + } else if (block instanceof EnchantingTable) { + type = BlockEntityType.ENCHANTING_TABLE; + } else if (block.getType() == Material.END_PORTAL) { // FIXME + type = BlockEntityType.END_PORTAL; + } else if (block instanceof Beacon) { + type = BlockEntityType.BEACON; + } else if (block instanceof Skull) { + type = BlockEntityType.SKULL; + } else if (block instanceof DaylightDetector) { + type = BlockEntityType.DAYLIGHT_DETECTOR; + } else if (block instanceof Hopper) { + type = BlockEntityType.HOPPER; + } else if (block instanceof Comparator) { + type = BlockEntityType.COMPARATOR; + } else if (block instanceof Banner) { + type = BlockEntityType.BANNER; + } else if (block instanceof Structure) { + type = BlockEntityType.STRUCTURE_BLOCK; + } else if (block instanceof EndGateway) { + type = BlockEntityType.END_GATEWAY; + } else if (block instanceof CommandBlock) { + type = BlockEntityType.COMMAND_BLOCK; + } else if (block instanceof ShulkerBox) { + type = BlockEntityType.SHULKER_BOX; + } else if (block instanceof Bed) { // FIXME + type = BlockEntityType.BED; + } else if (block instanceof Conduit) { + type = BlockEntityType.CONDUIT; + } else if (block instanceof Barrel) { + type = BlockEntityType.BARREL; + } else if (block instanceof Lectern) { + type = BlockEntityType.LECTERN; + } else if (block instanceof Bell) { + type = BlockEntityType.BELL; + } else if (block instanceof Jigsaw) { + type = BlockEntityType.JIGSAW; + } else if (block instanceof Campfire) { + type = BlockEntityType.CAMPFIRE; + } else if (block instanceof Beehive) { + type = BlockEntityType.BEEHIVE; + } else if (block instanceof SculkSensor) { + type = BlockEntityType.SCULK_SENSOR; + } else if (block instanceof SculkCatalyst) { + type = BlockEntityType.SCULK_CATALYST; + } else if (block instanceof SculkShrieker) { + type = BlockEntityType.SCULK_SHRIEKER; + } else if (block instanceof ChiseledBookshelf) { + type = BlockEntityType.CHISELED_BOOKSHELF; + } else if (block instanceof BrushableBlock) { + type = BlockEntityType.BRUSHABLE_BLOCK; + } else if (block instanceof DecoratedPot) { + type = BlockEntityType.DECORATED_POT; + } else { + return; + } + + CraftBlockEntityState craftBlockEntityState = (CraftBlockEntityState) block; + CompoundTag nbt = craftBlockEntityState.getSnapshotNBT(); + BlockPos blockPosition = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + ClientboundBlockEntityDataPacket packet; + try { + packet = BLOCK_ENTITY_DATA_PACKET_CONSTRUCTOR.newInstance(blockPosition, type, nbt); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + connection.send(packet); + } + + @Override + public void transformPacket(Player player, PacketContainer container, Function tileEntityTypeFilter) { + CraftWorld craftWorld = (CraftWorld) player.getWorld(); + ServerLevel vanillaWorld = craftWorld.getHandle(); + + WrappedLevelChunkData.ChunkData data = container.getLevelChunkData().read(0); + + List blockTileEntities = data.getBlockEntityInfo(); + + IntList removedBlocks = null; + for (Iterator iterator = blockTileEntities.iterator(); iterator.hasNext(); ) { + WrappedLevelChunkData.BlockEntityInfo tileEntity = iterator.next(); + + String type = tileEntity.getTypeKey().getKey(); + if (!tileEntityTypeFilter.apply(type)) { + continue; + } + + iterator.remove(); + + if (removedBlocks == null) { + removedBlocks = new IntArrayList(); + } + + short y = (short) tileEntity.getY(); + + byte x = (byte) tileEntity.getSectionX(); + byte z = (byte) tileEntity.getSectionZ(); + + // Y, X, Z + int key = (y & 0xFFFF) | ((x & 0xF) << 16) | ((z & 0xF) << 20); + removedBlocks.add(key); + } + + if (removedBlocks == null) { + return; + } + + byte[] readerBuffer = data.getBuffer(); + FriendlyByteBuf reader = new FriendlyByteBuf(Unpooled.wrappedBuffer(readerBuffer)); + + int bufferSize = 0; + LevelChunkSection[] sections = new LevelChunkSection[vanillaWorld.getSectionsCount()]; + for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) { + int yOffset = vanillaWorld.getSectionYFromSectionIndex(sectionIndex); + LevelChunkSection section = new LevelChunkSection(vanillaWorld.registryAccess().registryOrThrow(Registries.BIOME)); + section.read(reader); + + for (byte y = 0; y < 16; y++) { + for (byte z = 0; z < 16; z++) { + for (byte x = 0; x < 16; x++) { + int key = ((yOffset + y) & 0xFFFF) | ((x & 0xF) << 16) | ((z & 0xF) << 20); + if (!removedBlocks.contains(key)) { + continue; + } + section.setBlockState(x, y, z, Blocks.AIR.defaultBlockState(), false); + } + } + } + + sections[sectionIndex] = section; + bufferSize += section.getSerializedSize(); + } + + byte[] writerBuffer = new byte[bufferSize]; + FriendlyByteBuf writer = new FriendlyByteBuf(Unpooled.wrappedBuffer(writerBuffer)); + writer.writerIndex(0); + + for (LevelChunkSection section : sections) { + section.write(writer); + } + + data.setBuffer(writerBuffer); + + container.getLevelChunkData().write(0, data); + } + +}