diff --git a/patches/api/0449-Add-raw-byte-block-state-serialization.patch b/patches/api/0449-Add-raw-byte-block-state-serialization.patch new file mode 100644 index 000000000..8250910ad --- /dev/null +++ b/patches/api/0449-Add-raw-byte-block-state-serialization.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TrollyLoki +Date: Thu, 12 Oct 2023 11:05:20 -0400 +Subject: [PATCH] Add raw byte block state serialization + + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index a4b38f284d4fea7df7f9df9bf44e4f68fefaf20f..dbf2faae25a260d6c2c6bb353415756448d7bfe6 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -147,6 +147,10 @@ public interface UnsafeValues { + + org.bukkit.entity.Entity deserializeEntity(byte[] data, World world, boolean preserveUUID); + ++ byte[] serializeBlock(org.bukkit.block.BlockState blockState); ++ ++ org.bukkit.block.BlockState deserializeBlock(byte[] data, org.bukkit.block.Block block); ++ + /** + * Creates and returns the next EntityId available. + *

diff --git a/patches/server/1052-Add-raw-byte-block-state-serialization.patch b/patches/server/1052-Add-raw-byte-block-state-serialization.patch new file mode 100644 index 000000000..2d6ba8d79 --- /dev/null +++ b/patches/server/1052-Add-raw-byte-block-state-serialization.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TrollyLoki +Date: Thu, 12 Oct 2023 11:05:19 -0400 +Subject: [PATCH] Add raw byte block state serialization + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +index 9271ff2a9ea05569e3c81886399aa7ab47efb05d..78234964c1e2107ff73d4f31b060ca6a5c38ea27 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +@@ -235,13 +235,18 @@ public final class CraftBlockStates { + return CraftBlockStates.getBlockState(block, true); + } + public static BlockState getBlockState(Block block, boolean useSnapshot) { ++ return CraftBlockStates.getBlockState(block, useSnapshot, null, null); ++ } ++ // if customBlockData is null, customTileEntity is ignored and the state is populated from the world ++ // otherwise, the state is populated using the values of customBlockData and customTileEntity, ignoring the current state of the world ++ public static BlockState getBlockState(Block block, boolean useSnapshot, net.minecraft.world.level.block.state.BlockState customBlockData, BlockEntity customTileEntity) { + // Paper end + Preconditions.checkNotNull(block, "block is null"); + CraftBlock craftBlock = (CraftBlock) block; + CraftWorld world = (CraftWorld) block.getWorld(); + BlockPos blockPosition = craftBlock.getPosition(); +- net.minecraft.world.level.block.state.BlockState blockData = craftBlock.getNMS(); +- BlockEntity tileEntity = craftBlock.getHandle().getBlockEntity(blockPosition); ++ net.minecraft.world.level.block.state.BlockState blockData = customBlockData != null ? customBlockData : craftBlock.getNMS(); // Paper - use customBlockData if provided ++ BlockEntity tileEntity = customBlockData != null ? customTileEntity : craftBlock.getHandle().getBlockEntity(blockPosition); // Paper - use customTileEntity if customBlockData provided + // Paper start - block state snapshots + boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT; + CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot; +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index ec2396f0e5d62b10450eaa7239a8c5479638b3c3..866d1f5cee46594475717b247902b8832bcb315b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -526,6 +526,42 @@ public final class CraftMagicNumbers implements UnsafeValues { + .orElseThrow(() -> new IllegalArgumentException("An ID was not found for the data. Did you downgrade?")).getBukkitEntity(); + } + ++ @Override ++ public byte[] serializeBlock(org.bukkit.block.BlockState blockState) { ++ Preconditions.checkNotNull(blockState, "null cannot be serialized"); ++ Preconditions.checkArgument(blockState instanceof org.bukkit.craftbukkit.block.CraftBlockState, "only CraftBlockStates can be serialized"); ++ org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = (org.bukkit.craftbukkit.block.CraftBlockState) blockState; ++ ++ CompoundTag compound = new CompoundTag(); ++ compound.put("BlockState", net.minecraft.nbt.NbtUtils.writeBlockState(craftBlockState.getHandle())); ++ if (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState) { ++ compound.put("BlockEntity", ((org.bukkit.craftbukkit.block.CraftBlockEntityState) craftBlockState).getSnapshotNBT()); ++ } ++ return serializeNbtToBytes(compound); ++ } ++ ++ @Override ++ public org.bukkit.block.BlockState deserializeBlock(byte[] data, org.bukkit.block.Block block) { ++ Preconditions.checkNotNull(data, "null cannot be deserialized"); ++ Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing"); ++ Preconditions.checkArgument(block instanceof org.bukkit.craftbukkit.block.CraftBlock, "can only deserialize to CraftBlocks"); ++ org.bukkit.craftbukkit.block.CraftBlock craftBlock = (org.bukkit.craftbukkit.block.CraftBlock) block; ++ ++ CompoundTag compound = deserializeNbtFromBytes(data); ++ int dataVersion = compound.getInt("DataVersion"); ++ ++ CompoundTag blockStateCompound = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.BLOCK_STATE, compound.getCompound("BlockState"), dataVersion, getDataVersion()); ++ BlockState blockData = net.minecraft.nbt.NbtUtils.readBlockState(craftBlock.getCraftWorld().getHandle().holderLookup(net.minecraft.core.registries.Registries.BLOCK), blockStateCompound); ++ ++ net.minecraft.world.level.block.entity.BlockEntity tileEntity = null; ++ if (compound.contains("BlockEntity", NBT.TAG_COMPOUND)) { ++ CompoundTag blockEntityCompound = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.TILE_ENTITY, compound.getCompound("BlockEntity"), dataVersion, getDataVersion()); ++ tileEntity = net.minecraft.world.level.block.entity.BlockEntity.loadStatic(craftBlock.getPosition(), blockData, blockEntityCompound); ++ } ++ ++ return org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(craftBlock, false, blockData, tileEntity); ++ } ++ + private byte[] serializeNbtToBytes(CompoundTag compound) { + compound.putInt("DataVersion", getDataVersion()); + java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();