diff --git a/build-data/dev-imports.txt b/build-data/dev-imports.txt index 885a6ff..0d3e7ee 100644 --- a/build-data/dev-imports.txt +++ b/build-data/dev-imports.txt @@ -20,4 +20,6 @@ minecraft net.minecraft.nbt.StringTagVisitor minecraft net.minecraft.nbt.TextComponentTagVisitor minecraft net.minecraft.world.level.block.entity.StructureBlockEntity minecraft net.minecraft.world.ContainerHelper -minecraft net.minecraft.advancements.critereon.MinMaxBounds \ No newline at end of file +minecraft net.minecraft.advancements.critereon.MinMaxBounds +minecraft net.minecraft.network.protocol.game.ServerboundSetCommandMinecartPacket +minecraft net.minecraft.world.entity.boss.enderdragon.phases.DragonChargePlayerPhase \ No newline at end of file diff --git a/patches/server/0021-Prevent-invalid-container-events.patch b/patches/server/0021-Prevent-invalid-container-events.patch index 3a4031b..fd2fe93 100644 --- a/patches/server/0021-Prevent-invalid-container-events.patch +++ b/patches/server/0021-Prevent-invalid-container-events.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Prevent invalid container events diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 31a6be18075723eb53fd1cbb664429e49909cf66..65284355b6fc97eb1967e5c6fd51bc5b018e3e29 100644 +index 2b93d90da92559da021bac81bb3bc0a4e556ffb6..f8c6d5e2e384e3cf549c68b71c77b0f376cf32f0 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -31,6 +31,7 @@ import java.util.stream.Stream; @@ -16,7 +16,7 @@ index 31a6be18075723eb53fd1cbb664429e49909cf66..65284355b6fc97eb1967e5c6fd51bc5b import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.advancements.AdvancementHolder; -@@ -2981,6 +2982,18 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2964,6 +2965,18 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl return; } diff --git a/patches/server/0023-Refuse-to-convert-legacy-messages-over-1k-characters.patch b/patches/server/0023-Refuse-to-convert-legacy-messages-over-1k-characters.patch index 0b27961..189841a 100644 --- a/patches/server/0023-Refuse-to-convert-legacy-messages-over-1k-characters.patch +++ b/patches/server/0023-Refuse-to-convert-legacy-messages-over-1k-characters.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Refuse to convert legacy messages over 1k characters diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java -index 42ab6e0ba77fb2f0350bee72488e905074989b4d..4785dc2467ade8cad5c92c3d734cf6b2877a2693 100644 +index 70f207f016959402ff3cba9de924f906fea28110..f4751469d925f350a7eda9ae6a1f340d41636b2c 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java -@@ -207,6 +207,7 @@ public final class CraftChatMessage { +@@ -216,6 +216,7 @@ public final class CraftChatMessage { } public static Component[] fromString(String message, boolean keepNewlines, boolean plain) { diff --git a/patches/server/0026-Patch-invalid-entity-rotation-log-spam.patch b/patches/server/0026-Patch-invalid-entity-rotation-log-spam.patch new file mode 100644 index 0000000..854b5d5 --- /dev/null +++ b/patches/server/0026-Patch-invalid-entity-rotation-log-spam.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:07:11 -0500 +Subject: [PATCH] Patch invalid entity rotation log spam + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 6ee2d11e4f3fbc8424a2ffbe6a7ebd1832a25503..6bfe06748df9e36c20dc276471f209c1072ad3e4 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -4812,7 +4812,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + + public void setXRot(float pitch) { + if (!Float.isFinite(pitch)) { +- Util.logAndPauseIfInIde("Invalid entity rotation: " + pitch + ", discarding."); ++ // Scissors - Patch invalid entity rotation log spam + } else { + this.xRot = pitch; + } diff --git a/patches/server/0027-Add-configuration-option-to-disable-chat-signatures.patch b/patches/server/0027-Add-configuration-option-to-disable-chat-signatures.patch new file mode 100644 index 0000000..1443e0b --- /dev/null +++ b/patches/server/0027-Add-configuration-option-to-disable-chat-signatures.patch @@ -0,0 +1,116 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:12:12 -0500 +Subject: [PATCH] Add configuration option to disable chat signatures + + +diff --git a/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java b/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java +index c87b708c368713a23a10ad97704575ee4df27891..72b22821165efaecf9e2fa243d0ce3e45931d00c 100644 +--- a/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java ++++ b/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java +@@ -1,5 +1,6 @@ + package net.minecraft.network.chat; + ++import me.totalfreedom.scissors.ScissorsConfig; + import net.minecraft.server.level.ServerPlayer; + + public interface OutgoingChatMessage { +@@ -46,9 +47,19 @@ public interface OutgoingChatMessage { + // Paper end + PlayerChatMessage playerChatMessage = this.message.filter(filterMaskEnabled); + playerChatMessage = unsigned != null ? playerChatMessage.withUnsignedContent(unsigned) : playerChatMessage; // Paper +- if (!playerChatMessage.isFullyFiltered()) { ++ // Scissors start ++ if (!playerChatMessage.isFullyFiltered() && ScissorsConfig.chatSignaturesEnabled) { + sender.connection.sendPlayerChatMessage(playerChatMessage, params); ++ return; + } ++ sender.connection.sendPlayerChatMessage(new PlayerChatMessage( ++ SignedMessageLink.unsigned(playerChatMessage.sender()), ++ null, ++ SignedMessageBody.unsigned(playerChatMessage.signedContent()), ++ unsigned, ++ playerChatMessage.filterMask() ++ ), params); ++ // Scissors end + } + } + } +diff --git a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java +index 300929a406905f5ff1ede664d5b99fb0938d4d2e..769da86c130354f8c31642f5d87196b68ccd2dd5 100644 +--- a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java ++++ b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java +@@ -5,6 +5,8 @@ import java.time.Instant; + import java.util.UUID; + import java.util.function.BooleanSupplier; + import javax.annotation.Nullable; ++ ++import me.totalfreedom.scissors.ScissorsConfig; + import net.minecraft.util.SignatureValidator; + import net.minecraft.util.Signer; + import net.minecraft.world.entity.player.ProfilePublicKey; +@@ -55,7 +57,7 @@ public class SignedMessageChain { + this.setChainBroken(); + throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.INVALID_SIGNATURE); + } else { +- if (playerChatMessage.hasExpiredServer(Instant.now())) { ++ if (playerChatMessage.hasExpiredServer(Instant.now()) && ScissorsConfig.chatSignaturesEnabled) { // Scissors + SignedMessageChain.LOGGER.warn("Received expired chat: '{}'. Is the client/server system time unsynchronized?", body.content()); + } + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 703a4ea4c303b28d9cebb0bec86777529ef970da..779d44f878e3ae48f1808d1f48bf2b3120cc97ed 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -30,6 +30,7 @@ import java.util.stream.Collectors; + import java.util.stream.Stream; + import javax.annotation.Nullable; + ++import me.totalfreedom.scissors.ScissorsConfig; + import me.totalfreedom.scissors.event.player.SpectatorTeleportEvent; + import net.kyori.adventure.text.format.NamedTextColor; + import net.minecraft.ChatFormatting; +@@ -2268,6 +2269,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + + private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) { ++ if (!ScissorsConfig.chatSignaturesEnabled) return; // Scissors + ServerGamePacketListenerImpl.LOGGER.warn("Failed to update secure chat state for {}: '{}'", this.player.getGameProfile().getName(), exception.getComponent().getString()); + this.player.sendSystemMessage(exception.getComponent().copy().withStyle(ChatFormatting.RED)); + } +@@ -2364,6 +2366,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + Optional optional = this.lastSeenMessages.applyUpdate(acknowledgment); + + if (optional.isEmpty()) { ++ if (!ScissorsConfig.chatSignaturesEnabled) return optional; // Scissors + ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); + this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes + } +@@ -2549,6 +2552,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + synchronized (this.lastSeenMessages) { + if (!this.lastSeenMessages.applyOffset(packet.offset())) { ++ if (!ScissorsConfig.chatSignaturesEnabled) return; // Scissors + ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); + this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes + } +@@ -3532,6 +3536,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + @Override + public void handleChatSessionUpdate(ServerboundChatSessionUpdatePacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); ++ if (!ScissorsConfig.chatSignaturesEnabled) return; // Scissors + RemoteChatSession.Data remotechatsession_a = packet.chatSession(); + ProfilePublicKey.Data profilepublickey_a = this.chatSession != null ? this.chatSession.profilePublicKey().data() : null; + ProfilePublicKey.Data profilepublickey_a1 = remotechatsession_a.profilePublicKey(); +diff --git a/src/main/java/net/minecraft/world/level/block/SculkSpreader.java b/src/main/java/net/minecraft/world/level/block/SculkSpreader.java +index dbdd9cb76f9e2d0962001d9a1e82896c907d7aea..1a3417361960f470faafe0d28aa08b49b463bba4 100644 +--- a/src/main/java/net/minecraft/world/level/block/SculkSpreader.java ++++ b/src/main/java/net/minecraft/world/level/block/SculkSpreader.java +@@ -182,6 +182,7 @@ public class SculkSpreader { + while (iterator.hasNext()) { + SculkSpreader.ChargeCursor sculkspreader_a = (SculkSpreader.ChargeCursor) iterator.next(); + ++ if (!world.getMinecraftWorld().isLoadedAndInBounds(sculkspreader_a.getPos())) continue; // Scissors + sculkspreader_a.update(world, pos, random, this, shouldConvertToBlock); + if (sculkspreader_a.charge <= 0) { + world.levelEvent(3006, sculkspreader_a.getPos(), 0); diff --git a/patches/server/0028-Limit-map-decorations.patch b/patches/server/0028-Limit-map-decorations.patch new file mode 100644 index 0000000..0505c52 --- /dev/null +++ b/patches/server/0028-Limit-map-decorations.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:20:01 -0500 +Subject: [PATCH] Limit map decorations + + +diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +index cf8ae635fce7ea66d4e1ab1dc05575f035fa95ef..6983cf8ecf299285db200ce519c781882c0d2a9b 100644 +--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java ++++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +@@ -366,6 +366,11 @@ public class MapItemSavedData extends SavedData { + } + + private void addDecoration(Holder type, @Nullable LevelAccessor world, String key, double x, double z, double rotation, @Nullable Component text) { ++ // Scissors start - Limit decoration count ++ if (this.decorations.size() > 32) { ++ return; ++ } ++ // Scissors end + int i = 1 << this.scale; + float f = (float) (x - (double) this.centerX) / (float) i; + float f1 = (float) (z - (double) this.centerZ) / (float) i; diff --git a/patches/server/0029-Prevent-player-banning-using-duplicate-UUIDs.patch b/patches/server/0029-Prevent-player-banning-using-duplicate-UUIDs.patch new file mode 100644 index 0000000..dcbaaf0 --- /dev/null +++ b/patches/server/0029-Prevent-player-banning-using-duplicate-UUIDs.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:21:25 -0500 +Subject: [PATCH] Prevent player banning using duplicate UUIDs + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index ca56a0b596976448da6bb2a0e82b3d5cd4133e12..f8198f99244b4a635fa6fc68757acb38008c4564 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1673,7 +1673,13 @@ public class ServerLevel extends Level implements WorldGenLevel { + if (entity != null) { + ServerLevel.LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID()); + entity.unRide(); +- this.removePlayerImmediately((ServerPlayer) entity, Entity.RemovalReason.DISCARDED); ++ // Scissors start - Prevent player banning using duplicate UUIDs ++ if (entity instanceof ServerPlayer serverPlayer) { ++ this.removePlayerImmediately(serverPlayer, Entity.RemovalReason.DISCARDED); ++ } else { ++ entity.discard(null); ++ } ++ // Scissors end + } + + this.entityLookup.addNewEntity(player); // Paper - rewite chunk system diff --git a/patches/server/0030-Don-t-warn-on-duplicate-entity-UUIDs.patch b/patches/server/0030-Don-t-warn-on-duplicate-entity-UUIDs.patch new file mode 100644 index 0000000..d2a3e26 --- /dev/null +++ b/patches/server/0030-Don-t-warn-on-duplicate-entity-UUIDs.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:22:22 -0500 +Subject: [PATCH] Don't warn on duplicate entity UUIDs + + +diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java +index 15ee41452992714108efe53b708b5a4e1da7c1ff..5054dce35127cb0132431021578c345fcbb1f92a 100644 +--- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java ++++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java +@@ -415,7 +415,7 @@ public final class EntityLookup implements LevelEntityGetter { + return false; + } + if (this.entityByUUID.containsKey(entity.getUUID())) { +- LOGGER.warn("Entity uuid already exists: " + entity.getUUID() + ", mapped to " + this.entityByUUID.get(entity.getUUID()) + ", can't add " + entity); ++ // Scissors - Don't warn on duplicate entity UUIDs + return false; + } + this.entityById.put(entity.getId(), entity); diff --git a/patches/server/0031-Limit-beacon-effectRange.patch b/patches/server/0031-Limit-beacon-effectRange.patch new file mode 100644 index 0000000..141751c --- /dev/null +++ b/patches/server/0031-Limit-beacon-effectRange.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:23:46 -0500 +Subject: [PATCH] Limit beacon effectRange + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +index a6ffbbc1b5021564864e42c0756342352c2b8290..724edea5d4399fef2ddadbe631adef3d22513894 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +@@ -91,7 +91,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + private double effectRange = -1; + + public double getEffectRange() { +- if (this.effectRange < 0) { ++ if (this.effectRange < 0 || this.effectRange > 256) { // Scissors + return this.levels * 10 + 10; + } else { + return effectRange; +@@ -458,6 +458,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + + this.lockKey = LockCode.fromTag(nbt); + this.effectRange = nbt.contains(PAPER_RANGE_TAG, 6) ? nbt.getDouble(PAPER_RANGE_TAG) : -1; // Paper - Custom beacon ranges ++ if (this.effectRange > 256) this.effectRange = 256; // Scissors + } + + @Override diff --git a/patches/server/0032-Improve-validation-of-ResourceLocations.patch b/patches/server/0032-Improve-validation-of-ResourceLocations.patch new file mode 100644 index 0000000..a77757c --- /dev/null +++ b/patches/server/0032-Improve-validation-of-ResourceLocations.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:24:35 -0500 +Subject: [PATCH] Improve validation of ResourceLocations + + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java +index 5014192edb9616ce725fc1592832034789527b6f..64da1b0afd51720803aba0d9e86d0b1743bdb0da 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java +@@ -21,6 +21,7 @@ public final class CraftNamespacedKey { + } + + public static NamespacedKey fromMinecraft(ResourceLocation minecraft) { ++ if (minecraft == null) throw new IllegalArgumentException("Null ResourceLocation provided"); // Scissors + return new NamespacedKey(minecraft.getNamespace(), minecraft.getPath()); + } + diff --git a/patches/server/0033-Don-t-log-on-too-many-chained-updates.patch b/patches/server/0033-Don-t-log-on-too-many-chained-updates.patch new file mode 100644 index 0000000..7f0bf0b --- /dev/null +++ b/patches/server/0033-Don-t-log-on-too-many-chained-updates.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:25:43 -0500 +Subject: [PATCH] Don't log on too many chained updates + + +diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +index 106af2b2c7ff72c7549975aef75cdcff8d9a7d97..ecdcf4cf8650270ce7595905ce9d498eee520dcd 100644 +--- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java ++++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +@@ -58,7 +58,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater { + this.stack.push(entry); + } + } else if (this.count - 1 == this.maxChainedNeighborUpdates) { +- LOGGER.error("Too many chained neighbor updates. Skipping the rest. First skipped position: " + pos.toShortString()); ++ // Scissors - don't log + } + + if (!bl) { diff --git a/patches/server/0034-Implement-command-block-events.patch b/patches/server/0034-Implement-command-block-events.patch new file mode 100644 index 0000000..0c006bd --- /dev/null +++ b/patches/server/0034-Implement-command-block-events.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:34:17 -0500 +Subject: [PATCH] Implement command block events + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundSetCommandMinecartPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundSetCommandMinecartPacket.java +index 5cee02970241caafd151cadf08fc8d7092ec13d9..81e16e36b1950d4ae81cb09c39b36d7d4ba91d31 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundSetCommandMinecartPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundSetCommandMinecartPacket.java +@@ -14,7 +14,7 @@ public class ServerboundSetCommandMinecartPacket implements Packet STREAM_CODEC = Packet.codec( + ServerboundSetCommandMinecartPacket::write, ServerboundSetCommandMinecartPacket::new + ); +- private final int entity; ++ public final int entity; // Scissors - private -> public + private final String command; + private final boolean trackOutput; + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 779d44f878e3ae48f1808d1f48bf2b3120cc97ed..87d0dc96d8592612cefa25c378805aeea131b99e 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -31,6 +31,9 @@ import java.util.stream.Stream; + import javax.annotation.Nullable; + + import me.totalfreedom.scissors.ScissorsConfig; ++import me.totalfreedom.scissors.event.block.CommandBlockPlayerEditEvent; ++import me.totalfreedom.scissors.event.block.CommandMinecartPlayerEditEvent; ++import me.totalfreedom.scissors.event.block.CommandBlockPlayerEditEvent; + import me.totalfreedom.scissors.event.player.SpectatorTeleportEvent; + import net.kyori.adventure.text.format.NamedTextColor; + import net.minecraft.ChatFormatting; +@@ -160,6 +163,7 @@ import net.minecraft.world.entity.player.Inventory; + import net.minecraft.world.entity.player.ProfilePublicKey; + import net.minecraft.world.entity.projectile.AbstractArrow; + import net.minecraft.world.entity.vehicle.Boat; ++import net.minecraft.world.entity.vehicle.MinecartCommandBlock; + import net.minecraft.world.inventory.AbstractContainerMenu; + import net.minecraft.world.inventory.AnvilMenu; + import net.minecraft.world.inventory.BeaconMenu; +@@ -197,6 +201,8 @@ import net.minecraft.world.phys.Vec3; + import net.minecraft.world.phys.shapes.BooleanOp; + import net.minecraft.world.phys.shapes.Shapes; + import net.minecraft.world.phys.shapes.VoxelShape; ++import org.bukkit.craftbukkit.block.CraftCommandBlock; ++import org.bukkit.craftbukkit.entity.CraftMinecartCommand; + import org.slf4j.Logger; + + // CraftBukkit start +@@ -931,6 +937,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.player.level().getChunkAt(blockposition).setBlockEntity(tileentity); + } + ++ // Scissors start ++ CommandBlockPlayerEditEvent event = new CommandBlockPlayerEditEvent(this.getCraftPlayer(), commandblocklistenerabstract.getCommand(), s, new CraftCommandBlock(this.player.level().getWorld(), tileentitycommand)); ++ if (!event.callEvent()) { ++ return; ++ } ++ ++ s = event.getNewCommand(); ++ // Scissors end ++ + commandblocklistenerabstract.setCommand(s); + commandblocklistenerabstract.setTrackOutput(flag); + if (!flag) { +@@ -962,7 +977,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + BaseCommandBlock commandblocklistenerabstract = packet.getCommandBlock(this.player.level()); + + if (commandblocklistenerabstract != null) { +- commandblocklistenerabstract.setCommand(packet.getCommand()); ++ // Scissors start - Implement command block events ++ String command = packet.getCommand(); ++ CommandMinecartPlayerEditEvent event = new CommandMinecartPlayerEditEvent(this.getCraftPlayer(), commandblocklistenerabstract.getCommand(), command, new CraftMinecartCommand(this.cserver, (MinecartCommandBlock) this.player.level().getEntity(packet.entity))); ++ ++ if (!event.callEvent()) { ++ return; ++ } ++ ++ command = event.getNewCommand(); ++ commandblocklistenerabstract.setCommand(command); ++ // Scissors end + commandblocklistenerabstract.setTrackOutput(packet.isTrackOutput()); + if (!packet.isTrackOutput()) { + commandblocklistenerabstract.setLastOutput((Component) null); diff --git a/patches/server/0035-Limit-save-data-for-Bees-and-Vexes.patch b/patches/server/0035-Limit-save-data-for-Bees-and-Vexes.patch new file mode 100644 index 0000000..93b5377 --- /dev/null +++ b/patches/server/0035-Limit-save-data-for-Bees-and-Vexes.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:39:39 -0500 +Subject: [PATCH] Limit save data for Bees and Vexes + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java +index 0dfb8109fd8c022b079da00f6a0e3fc85b57bf7a..fdfe3ca7c2a1d34567651e64933392c4a17bd751 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java +@@ -231,7 +231,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + + @Override + public void readAdditionalSaveData(CompoundTag nbt) { +- this.hivePos = (BlockPos) NbtUtils.readBlockPos(nbt, "hive_pos").orElse(null); // CraftBukkit - decompile error ++ // Scissors start - limit hive_pos ++ if (nbt.contains("hive_pos")) ++ { ++ final BlockPos savedHivePos = NbtUtils.readBlockPos(nbt, "hive_pos").orElse(null); // CraftBukkit - decompile error ++ this.hivePos = this.level().isLoadedAndInBounds(savedHivePos) ? savedHivePos : null; ++ } ++ // Scissors end + this.savedFlowerPos = (BlockPos) NbtUtils.readBlockPos(nbt, "flower_pos").orElse(null); // CraftBukkit - decompile error + super.readAdditionalSaveData(nbt); + this.setHasNectar(nbt.getBoolean("HasNectar")); +diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java +index fd3b37dde54623ba38186efb2a64d364c86b81d2..ae1051a7ebc2b2bf6d5bf5582443fedeb307ee01 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Vex.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java +@@ -111,7 +111,10 @@ public class Vex extends Monster implements TraceableEntity { + public void readAdditionalSaveData(CompoundTag nbt) { + super.readAdditionalSaveData(nbt); + if (nbt.contains("BoundX")) { +- this.boundOrigin = new BlockPos(nbt.getInt("BoundX"), nbt.getInt("BoundY"), nbt.getInt("BoundZ")); ++ // Scissors start - Limit Vex bound origin ++ final BlockPos savedBoundOrigin = new BlockPos(nbt.getInt("BoundX"), nbt.getInt("BoundY"), nbt.getInt("BoundZ")); ++ this.boundOrigin = this.level().isLoadedAndInBounds(savedBoundOrigin) ? savedBoundOrigin : null; ++ // Scissors end - Limit Vex bound origin + } + + if (nbt.contains("LifeTicks")) { diff --git a/patches/server/0036-Mute-invalid-Enderdragon-phases.patch b/patches/server/0036-Mute-invalid-Enderdragon-phases.patch new file mode 100644 index 0000000..6a8a01f --- /dev/null +++ b/patches/server/0036-Mute-invalid-Enderdragon-phases.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:49:11 -0500 +Subject: [PATCH] Mute invalid Enderdragon phases + + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonChargePlayerPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonChargePlayerPhase.java +index 1b1a210a86121049e507a497649727a99452c0a2..5501d94f3b39665a94062ae97b3739ae197dadb1 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonChargePlayerPhase.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonChargePlayerPhase.java +@@ -20,7 +20,7 @@ public class DragonChargePlayerPhase extends AbstractDragonPhaseInstance { + @Override + public void doServerTick() { + if (this.targetLocation == null) { +- LOGGER.warn("Aborting charge player as no target was set."); ++ // Scissors - Mute invalid Enderdragon phases + this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); + } else if (this.timeSinceCharge > 0 && this.timeSinceCharge++ >= 10) { + this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java +index c5269c3117901b8521720d1b32689d7f600f20a3..02dd6f72aa16e6b3edec700b7bc82a84b5ca8dd9 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java +@@ -31,7 +31,7 @@ public class DragonStrafePlayerPhase extends AbstractDragonPhaseInstance { + @Override + public void doServerTick() { + if (this.attackTarget == null) { +- LOGGER.warn("Skipping player strafe phase because no player was found"); ++ // Scissors - Mute invalid Enderdragon phases + this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); + } else { + if (this.currentPath != null && this.currentPath.isDone()) { diff --git a/patches/server/0037-Add-length-limit-to-note-block-sound.patch b/patches/server/0037-Add-length-limit-to-note-block-sound.patch new file mode 100644 index 0000000..4a73428 --- /dev/null +++ b/patches/server/0037-Add-length-limit-to-note-block-sound.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:50:32 -0500 +Subject: [PATCH] Add length limit to note block sound + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java +index e79b1ccbdf12006d72401b5be1ac25187033ec59..a7b1a44de0689f7d07bd3e69048b04c28c272159 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java +@@ -147,7 +147,7 @@ public class SkullBlockEntity extends BlockEntity { + } + + if (nbt.contains("note_block_sound", 8)) { +- this.noteBlockSound = ResourceLocation.tryParse(nbt.getString("note_block_sound")); ++ this.noteBlockSound = ResourceLocation.tryParse(StringUtil.truncateStringIfNecessary(nbt.getString("note_block_sound"), 32767, false)); + } + + if (nbt.contains("custom_name", 8)) { diff --git a/patches/server/0038-Change-version-fetcher-to-AMG.patch b/patches/server/0038-Change-version-fetcher-to-AMG.patch new file mode 100644 index 0000000..989ebd4 --- /dev/null +++ b/patches/server/0038-Change-version-fetcher-to-AMG.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 18:56:18 -0500 +Subject: [PATCH] Change version fetcher to AMG + + +diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +index 532306cacd52579cdf37e4aca25887b1ed3ba6a1..1cdba130f6224ba0eb5e958d3328b1c476520efe 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java ++++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +@@ -18,10 +18,14 @@ import java.net.URI; + import java.util.Optional; + import java.util.OptionalInt; + import java.util.stream.StreamSupport; ++ ++import io.papermc.paper.util.JarManifests; + import net.kyori.adventure.text.Component; + import net.kyori.adventure.text.event.ClickEvent; + import net.kyori.adventure.text.format.NamedTextColor; + import net.kyori.adventure.text.format.TextDecoration; ++import org.bukkit.Bukkit; ++import org.bukkit.Server; + import org.checkerframework.checker.nullness.qual.NonNull; + import org.checkerframework.checker.nullness.qual.Nullable; + import org.checkerframework.framework.qual.DefaultQualifier; +@@ -35,7 +39,7 @@ public class PaperVersionFetcher implements VersionFetcher { + private static final Logger LOGGER = LogUtils.getClassLogger(); + private static final int DISTANCE_ERROR = -1; + private static final int DISTANCE_UNKNOWN = -2; +- private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads/paper"; ++ private static final String DOWNLOAD_PAGE = "https://ci.plex.us.org/job/Scissors/job/" + ServerBuildInfo.buildInfo().gitBranch(); // Scissors + + @Override + public long getCacheTime() { +@@ -49,7 +53,7 @@ public class PaperVersionFetcher implements VersionFetcher { + if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) { + updateMessage = text("You are running a development version without access to version information", color(0xFF5300)); + } else { +- updateMessage = getUpdateStatusMessage("PaperMC/Paper", build); ++ updateMessage = getUpdateStatusMessage("AtlasMediaGroup/Scissors", build); + } + final @Nullable Component history = this.getHistory(); + +@@ -59,15 +63,10 @@ public class PaperVersionFetcher implements VersionFetcher { + private static Component getUpdateStatusMessage(final String repo, final ServerBuildInfo build) { + int distance = DISTANCE_ERROR; + +- final OptionalInt buildNumber = build.buildNumber(); +- if (buildNumber.isPresent()) { +- distance = fetchDistanceFromSiteApi(build, buildNumber.getAsInt()); +- } else { +- final Optional gitBranch = build.gitBranch(); +- final Optional gitCommit = build.gitCommit(); +- if (gitBranch.isPresent() && gitCommit.isPresent()) { +- distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get()); +- } ++ final Optional gitBranch = build.gitBranch(); ++ final Optional gitCommit = build.gitCommit(); ++ if (gitBranch.isPresent() && gitCommit.isPresent()) { ++ distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get()); + } + + return switch (distance) { +diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java +index 6101ff98022e7c1ad253edb112a0bf87b139e62b..4338714a0bc8c3618a88b915b575e8b17a77dbd8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/Main.java ++++ b/src/main/java/org/bukkit/craftbukkit/Main.java +@@ -316,7 +316,7 @@ public class Main { + if (buildDate.before(deadline.getTime())) { + // Paper start - This is some stupid bullshit + System.err.println("*** Warning, you've not updated in a while! ***"); +- System.err.println("*** Please download a new build as per instructions from https://papermc.io/downloads/paper ***"); // Paper ++ System.err.println("*** Please download a new build as per instructions from https://ci.plex.us.org/job/Scissors ***"); // Paper + //System.err.println("*** Server will start in 20 seconds ***"); + //Thread.sleep(TimeUnit.SECONDS.toMillis(20)); + // Paper end diff --git a/patches/server/0039-Add-depth-limit-to-Component-deserialization.patch b/patches/server/0039-Add-depth-limit-to-Component-deserialization.patch new file mode 100644 index 0000000..260f21f --- /dev/null +++ b/patches/server/0039-Add-depth-limit-to-Component-deserialization.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 19:01:14 -0500 +Subject: [PATCH] Add depth limit to Component deserialization + + +diff --git a/src/main/java/net/minecraft/network/chat/Component.java b/src/main/java/net/minecraft/network/chat/Component.java +index 3b075dcb6bda40b278296fc8750f2af90c13acc4..a0c3c4faa8c80c880340e0150e16223ac0b5e5a0 100644 +--- a/src/main/java/net/minecraft/network/chat/Component.java ++++ b/src/main/java/net/minecraft/network/chat/Component.java +@@ -1,15 +1,7 @@ + package net.minecraft.network.chat; + + import com.google.common.collect.Lists; +-import com.google.gson.Gson; +-import com.google.gson.GsonBuilder; +-import com.google.gson.JsonDeserializationContext; +-import com.google.gson.JsonDeserializer; +-import com.google.gson.JsonElement; +-import com.google.gson.JsonParseException; +-import com.google.gson.JsonParser; +-import com.google.gson.JsonSerializationContext; +-import com.google.gson.JsonSerializer; ++import com.google.gson.*; + import com.google.gson.stream.JsonReader; + import com.mojang.brigadier.Message; + import com.mojang.serialization.JsonOps; +@@ -24,6 +16,7 @@ import java.util.Optional; + import java.util.UUID; + import javax.annotation.Nullable; + ++import me.totalfreedom.scissors.ScissorsConfig; + import net.minecraft.ChatFormatting; + import net.minecraft.core.HolderLookup; + import net.minecraft.network.chat.contents.DataSource; +@@ -35,8 +28,10 @@ import net.minecraft.network.chat.contents.SelectorContents; + import net.minecraft.network.chat.contents.TranslatableContents; + import net.minecraft.resources.ResourceLocation; + import net.minecraft.util.FormattedCharSequence; ++import net.minecraft.util.GsonHelper; + import net.minecraft.world.level.ChunkPos; + // CraftBukkit start ++import java.util.regex.Pattern; + import java.util.stream.Stream; + // CraftBukkit end + +@@ -286,10 +281,70 @@ public interface Component extends Message, FormattedText, Iterable { + public static class Serializer { + + private static final Gson GSON = (new GsonBuilder()).disableHtmlEscaping().create(); ++ private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("%[0-9]+\\$s"); // Scissors + + private Serializer() {} + ++ // Scissors start ++ static int depthChecker(int depth) { ++ depth = depth + 1; ++ if (depth > ScissorsConfig.componentDepthLimit) { ++ throw new JsonParseException("Depth limit exceeded"); ++ } ++ return depth; ++ } ++ ++ static int getPenalty(String string) { ++ if (PLACEHOLDER_PATTERN.matcher(string).find()) { ++ long translate_placeholders = PLACEHOLDER_PATTERN.matcher(string).results().count(); ++ return (int) translate_placeholders * 12; ++ } ++ return 0; ++ } ++ + static MutableComponent deserialize(JsonElement json, HolderLookup.Provider registries) { ++ int depth = 1; ++ if (!json.isJsonPrimitive()) { ++ if (!json.isJsonObject()) { ++ if (json.isJsonArray()) { ++ JsonArray jsonArray = json.getAsJsonArray(); ++ if (jsonArray.size() <= 0) { ++ throw new JsonParseException("Unexpected empty array of components"); ++ } ++ ++ for (JsonElement ignored : jsonArray) { ++ depth = depthChecker(depth); ++ } ++ } ++ } ++ else ++ { ++ JsonObject jsonObject = json.getAsJsonObject(); ++ if (jsonObject.has("translate")) { ++ String s = GsonHelper.getAsString(jsonObject, "translate"); ++ int penalty = getPenalty(s); ++ depth = depthChecker(depth + penalty); ++ ++ if (jsonObject.has("with")) { ++ String s1 = GsonHelper.getAsJsonArray(jsonObject, "with").toString(); ++ penalty = getPenalty(s1); ++ depth = depthChecker(depth + penalty); ++ } ++ } ++ ++ if (jsonObject.has("extra")) { ++ JsonArray jsonArray = GsonHelper.getAsJsonArray(jsonObject, "extra"); ++ if (jsonArray.size() <= 0) { ++ throw new JsonParseException("Unexpected empty array of components"); ++ } ++ ++ for (JsonElement ignored : jsonArray) { ++ depth = depthChecker(depth); ++ } ++ } ++ } ++ } ++ // Scissors end + return (MutableComponent) ComponentSerialization.CODEC.parse(registries.createSerializationContext(JsonOps.INSTANCE), json).getOrThrow(JsonParseException::new); + } + diff --git a/patches/server/0040-Add-depth-limit-to-updateCustomBlockEntityTag.patch b/patches/server/0040-Add-depth-limit-to-updateCustomBlockEntityTag.patch new file mode 100644 index 0000000..df661f2 --- /dev/null +++ b/patches/server/0040-Add-depth-limit-to-updateCustomBlockEntityTag.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Telesphoreo +Date: Fri, 14 Jun 2024 19:05:44 -0500 +Subject: [PATCH] Add depth limit to updateCustomBlockEntityTag + + +diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java +index 96fb69ec6db2e7c8c728435f0c537b076259b2fb..b27a5f2251012f256652bcb50caf317c31378b63 100644 +--- a/src/main/java/net/minecraft/world/item/BlockItem.java ++++ b/src/main/java/net/minecraft/world/item/BlockItem.java +@@ -2,12 +2,18 @@ package net.minecraft.world.item; + + import java.util.List; + import java.util.Map; ++import java.util.regex.Matcher; ++import java.util.regex.Pattern; + import javax.annotation.Nullable; ++ ++import me.totalfreedom.scissors.ScissorsConfig; + import net.minecraft.advancements.CriteriaTriggers; + import net.minecraft.core.BlockPos; + import net.minecraft.core.Holder; + import net.minecraft.core.component.DataComponents; + import net.minecraft.nbt.CompoundTag; ++import net.minecraft.nbt.ListTag; ++import net.minecraft.nbt.Tag; + import net.minecraft.network.chat.Component; + import net.minecraft.server.MinecraftServer; + import net.minecraft.server.level.ServerLevel; +@@ -217,6 +223,35 @@ public class BlockItem extends Item { + if (!customdata.isEmpty()) { + BlockEntity tileentity = world.getBlockEntity(pos); + ++ // Scissors start ++ if (customdata.contains("CustomName")) { ++ String customName = customdata.getUnsafe().getString("CustomName"); ++ Pattern EXTRA_PATTERN = Pattern.compile("\"extra\":(\\[(.*?)\\{|\\[\\{)"); ++ Matcher matcher = EXTRA_PATTERN.matcher(customName); ++ if (matcher.find()) { ++ String matcherString = matcher.group(); ++ int penalty = (matcherString.startsWith("\"extra\":[{") ? (int) matcher.results().count() : matcher.group().replace("\"extra\":", "").replace("{", "").length()) * 12; ++ if (penalty > ScissorsConfig.componentDepthLimit) { ++ return false; ++ } ++ } ++ } ++ ++ for (Tag tag : customdata.getUnsafe().tags.values()) { ++ if (tag instanceof CompoundTag compoundTag && compoundTag.contains("messages")) { ++ ListTag messagesList = compoundTag.getList("messages", 8); ++ Pattern TRANSLATE_PLACEHOLDER_PATTERN = Pattern.compile("%[0-9]+\\$s"); ++ Matcher matcher = TRANSLATE_PLACEHOLDER_PATTERN.matcher(messagesList.toString()); ++ if (matcher.find()) { ++ int penalty = (int) matcher.results().count() * 12; ++ if (penalty > ScissorsConfig.componentDepthLimit) { ++ return false; ++ } ++ } ++ } ++ } ++ // Scissors end ++ + if (tileentity != null) { + if (!world.isClientSide && tileentity.onlyOpCanSetNbt() && (player == null || !(player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place"))))) { // Spigot - add permission + return false;