From 2a306f513c26e81615e5a7d8e3be9b7bbfb0b623 Mon Sep 17 00:00:00 2001 From: Brody Beckwith Date: Thu, 20 Jan 2022 12:50:50 -0500 Subject: [PATCH] Add Multi Block Change API (#7333) --- patches/api/0358-Multi-Block-Change-API.patch | 38 ++++++++++ ...ulti-Block-Change-API-Implementation.patch | 74 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 patches/api/0358-Multi-Block-Change-API.patch create mode 100644 patches/server/0854-Multi-Block-Change-API-Implementation.patch diff --git a/patches/api/0358-Multi-Block-Change-API.patch b/patches/api/0358-Multi-Block-Change-API.patch new file mode 100644 index 0000000000..97236f5da8 --- /dev/null +++ b/patches/api/0358-Multi-Block-Change-API.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brody Beckwith +Date: Fri, 14 Jan 2022 00:40:42 -0500 +Subject: [PATCH] Multi Block Change API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 7eda2ba17e39b8183e572c1cefa8afffbf17afcb..fb8bd05a0204740ec323e9b657916de6ccbf6f90 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -584,6 +584,27 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public void sendBlockDamage(@NotNull Location loc, float progress); + ++ // Paper start ++ /** ++ * Send multiple block changes. This fakes a multi block change packet for each ++ * chunk section that a block change occurs. This will not actually change the world in any way. ++ * ++ * @param blockChanges A map of the locations you want to change to their new block data ++ */ ++ public default void sendMultiBlockChange(@NotNull java.util.Map blockChanges) { ++ sendMultiBlockChange(blockChanges, false); ++ } ++ ++ /** ++ * Send multiple block changes. This fakes a multi block change packet for each ++ * chunk section that a block change occurs. This will not actually change the world in any way. ++ * ++ * @param blockChanges A map of the locations you want to change to their new block data ++ * @param suppressLightUpdates Whether to suppress light updates or not ++ */ ++ public void sendMultiBlockChange(@NotNull java.util.Map blockChanges, boolean suppressLightUpdates); ++ // Paper end ++ + /** + * Send the equipment change of an entity. This fakes the equipment change + * of an entity for a user. This will not actually change the inventory of diff --git a/patches/server/0854-Multi-Block-Change-API-Implementation.patch b/patches/server/0854-Multi-Block-Change-API-Implementation.patch new file mode 100644 index 0000000000..de38bf489f --- /dev/null +++ b/patches/server/0854-Multi-Block-Change-API-Implementation.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brody Beckwith +Date: Fri, 14 Jan 2022 00:41:11 -0500 +Subject: [PATCH] Multi Block Change API Implementation + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java +index 82ea4fabd5732052a286d50bcff8bbcc2c4aa7d7..652bea6868a03a5315965f79c76172fb9dbb93fb 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java +@@ -54,6 +54,15 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet blockChanges, boolean suppressLightUpdates) { ++ this.sectionPos = sectionPos; ++ this.positions = blockChanges.keySet().toShortArray(); ++ this.states = blockChanges.values().toArray(new BlockState[0]); ++ this.suppressLightUpdates = suppressLightUpdates; ++ } ++ // Paper end ++ + @Override + public void write(FriendlyByteBuf buf) { + buf.writeLong(this.sectionPos.asLong()); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 148e1985017f6955267b5c970730645394d700f6..43d96760828e4c9683398f3f6925701d003556e4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -30,6 +30,7 @@ import javax.annotation.Nullable; + import net.minecraft.Util; + import net.minecraft.advancements.AdvancementProgress; + import net.minecraft.core.BlockPos; ++import net.minecraft.core.SectionPos; // Paper + import net.minecraft.nbt.CompoundTag; + import net.minecraft.network.FriendlyByteBuf; + import net.minecraft.network.chat.ChatType; +@@ -836,6 +837,35 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + this.getHandle().connection.send(packet); + } + ++ // Paper start ++ @Override ++ public void sendMultiBlockChange(Map blockChanges, boolean suppressLightUpdates) { ++ if (this.getHandle().connection == null) return; ++ ++ Map> sectionMap = new HashMap<>(); ++ ++ for (Map.Entry entry : blockChanges.entrySet()) { ++ Location location = entry.getKey(); ++ if (!location.getWorld().equals(this.getWorld())) continue; ++ ++ BlockData blockData = entry.getValue(); ++ BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); ++ SectionPos sectionPos = SectionPos.of(blockPos); ++ ++ it.unimi.dsi.fastutil.shorts.Short2ObjectMap sectionData = sectionMap.computeIfAbsent(sectionPos, key -> new it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap<>()); ++ sectionData.put(SectionPos.sectionRelativePos(blockPos), ((CraftBlockData) blockData).getState()); ++ } ++ ++ for (Map.Entry> entry : sectionMap.entrySet()) { ++ SectionPos sectionPos = entry.getKey(); ++ it.unimi.dsi.fastutil.shorts.Short2ObjectMap blockData = entry.getValue(); ++ ++ net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket packet = new net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket(sectionPos, blockData, suppressLightUpdates); ++ this.getHandle().connection.send(packet); ++ } ++ } ++ // Paper end ++ + @Override + public void sendBlockDamage(Location loc, float progress) { + Preconditions.checkArgument(loc != null, "loc must not be null");