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);
+ }
+
+}