diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 21a8d63..7a596c8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,10 @@ name: Patch and Build -on: [ push, pull_request ] + +on: + push: + branches: [ "**" ] + pull_request: + jobs: build: # Only run on PRs if the source branch is on someone else's repo @@ -7,26 +12,19 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Git Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Validate Gradle wrapper uses: gradle/wrapper-validation-action@v1 - - name: Cache Gradle - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', '**/gradle.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 - name: Set up JDK - uses: actions/setup-java@v2.3.0 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '17' - name: Configure Git User Details run: git config --global user.email "actions@github.com" && git config --global user.name "Github Actions" - name: Apply Patches - run: ./gradlew applyPatches --stacktrace + run: ./gradlew applyPatches - name: Build - run: ./gradlew build --stacktrace + run: ./gradlew build diff --git a/patches/server/0049-Implement-command-block-events.patch b/patches/server/0049-Implement-command-block-events.patch index f6af8ac..01f2850 100644 --- a/patches/server/0049-Implement-command-block-events.patch +++ b/patches/server/0049-Implement-command-block-events.patch @@ -4,8 +4,21 @@ Date: Fri, 2 Jun 2023 20:55:18 +0100 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 c99fc118013cb3d4043638e2001a8297e79ddf9c..cdaa81e1f2167b29ec01cc25e51a8400deb533d2 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundSetCommandMinecartPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundSetCommandMinecartPacket.java +@@ -9,7 +9,7 @@ import net.minecraft.world.level.BaseCommandBlock; + import net.minecraft.world.level.Level; + + public class ServerboundSetCommandMinecartPacket implements Packet { +- 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 a2b96f7b1e98586017dbbf28a73446196738ee99..0227e2c7197c3684677f76ff7f0fe0acc21b6c14 100644 +index 757f20c0d546ab2ca9f32ca2c3733f36290d3a3d..127ed778733eb29f90416ae9c9f2ae0b8c727e9d 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1,6 +1,8 @@ @@ -25,56 +38,82 @@ index a2b96f7b1e98586017dbbf28a73446196738ee99..0227e2c7197c3684677f76ff7f0fe0ac import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.Item; -@@ -188,6 +191,7 @@ import net.minecraft.world.phys.Vec3; +@@ -188,6 +191,10 @@ 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.CraftBlockStates; ++import org.bukkit.craftbukkit.block.CraftCommandBlock; ++import org.bukkit.craftbukkit.entity.CraftMinecartCommand; +import org.bukkit.entity.minecart.CommandMinecart; import org.slf4j.Logger; // CraftBukkit start -@@ -1001,6 +1005,21 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -651,14 +658,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && ( + !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position()))) || + !worldserver.areChunksLoadedForMove(entity.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(entity.position()))) +- )) { ++ )) { + this.connection.send(new ClientboundMoveVehiclePacket(entity)); + return; + } + // Paper end + + if (d10 - d9 > Math.max(100.0D, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && !this.isSingleplayerOwner()) { +- // CraftBukkit end ++ // CraftBukkit end + ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8}); + this.connection.send(new ClientboundMoveVehiclePacket(entity)); + return; +@@ -905,11 +912,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + // Paper end - Don't suggest if tab-complete is disabled + // Paper start - async tab completion + TAB_COMPLETE_EXECUTOR.execute(() -> { +- StringReader stringreader = new StringReader(packet.getCommand()); ++ StringReader stringreader = new StringReader(packet.getCommand()); + +- if (stringreader.canRead() && stringreader.peek() == '/') { +- stringreader.skip(); +- } ++ if (stringreader.canRead() && stringreader.peek() == '/') { ++ stringreader.skip(); ++ } + final String command = packet.getCommand(); + final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getCraftPlayer(), command, true, null); + event.callEvent(); +@@ -1001,6 +1008,17 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic this.player.level().getChunkAt(blockposition).setBlockEntity(tileentity); } -+ // Scissors start - Implement command block events -+ if (commandblocklistenerabstract instanceof org.bukkit.block.CommandBlock commandBlock) -+ { -+ CommandBlockPlayerEditEvent event = new CommandBlockPlayerEditEvent(this.getCraftPlayer(), Objects.requireNonNullElse(commandblocklistenerabstract.getCommand(), ""), s, commandBlock); -+ event.callEvent(); ++ CommandBlockPlayerEditEvent event = new CommandBlockPlayerEditEvent(this.getCraftPlayer(), commandblocklistenerabstract.getCommand(), s, new CraftCommandBlock(this.player.level().getWorld(), tileentitycommand)); + -+ if (event.isCancelled()) { -+ return; -+ } -+ -+ s = event.getNewCommand(); ++ if (!event.callEvent()) { ++ return; + } + ++ s = event.getNewCommand(); ++ ++ + // Scissors end + commandblocklistenerabstract.setCommand(s); commandblocklistenerabstract.setTrackOutput(flag); if (!flag) { -@@ -1032,7 +1051,27 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1032,7 +1050,21 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 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 (commandblocklistenerabstract instanceof CommandMinecart commandMinecart) -+ { -+ CommandMinecartPlayerEditEvent event = new CommandMinecartPlayerEditEvent(this.getCraftPlayer(), Objects.requireNonNullElse(commandblocklistenerabstract.getCommand(), ""), command, commandMinecart); -+ event.callEvent(); -+ -+ if (event.isCancelled()) { -+ return; -+ } -+ -+ command = event.getNewCommand(); ++ if (!event.callEvent()) { ++ return; + } + ++ command = event.getNewCommand(); + commandblocklistenerabstract.setCommand(command); + + // commandblocklistenerabstract.setCommand(packet.getCommand()); @@ -84,3 +123,193 @@ index a2b96f7b1e98586017dbbf28a73446196738ee99..0227e2c7197c3684677f76ff7f0fe0ac commandblocklistenerabstract.setTrackOutput(packet.isTrackOutput()); if (!packet.isTrackOutput()) { commandblocklistenerabstract.setLastOutput((Component) null); +@@ -1484,7 +1516,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + float f2 = this.player.isFallFlying() ? 300.0F : 100.0F; + + if (d10 - d9 > Math.max(f2, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && !this.isSingleplayerOwner()) { +- // CraftBukkit end ++ // CraftBukkit end + ServerGamePacketListenerImpl.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8}); + this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); + return; +@@ -1976,7 +2008,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + MutableComponent ichatmutablecomponent = Component.translatable("build.tooHigh", i - 1).withStyle(ChatFormatting.RED); + + this.player.sendSystemMessage(ichatmutablecomponent, true); +- } else if (enuminteractionresult.shouldSwing() && !this.player.gameMode.interactResult) { // Paper ++ } else if (enuminteractionresult.shouldSwing() && !this.player.gameMode.interactResult) { // Paper + this.player.swing(enumhand, true); + } + } +@@ -2227,32 +2259,32 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + // CraftBukkit end + if (ServerGamePacketListenerImpl.isChatMessageIllegal(packet.message())) { + this.server.scheduleOnMain(() -> { // Paper - push to main for event firing +- this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add cause ++ this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add cause + }); // Paper - push to main for event firing + } else { + Optional optional = this.tryHandleChat(packet.message(), packet.timeStamp(), packet.lastSeenMessages()); + + if (optional.isPresent()) { + // this.server.submit(() -> { // CraftBukkit - async chat +- PlayerChatMessage playerchatmessage; ++ PlayerChatMessage playerchatmessage; + +- try { +- playerchatmessage = this.getSignedMessage(packet, (LastSeenMessages) optional.get()); +- } catch (SignedMessageChain.DecodeException signedmessagechain_a) { +- this.handleMessageDecodeFailure(signedmessagechain_a); +- return; +- } ++ try { ++ playerchatmessage = this.getSignedMessage(packet, (LastSeenMessages) optional.get()); ++ } catch (SignedMessageChain.DecodeException signedmessagechain_a) { ++ this.handleMessageDecodeFailure(signedmessagechain_a); ++ return; ++ } + +- CompletableFuture completablefuture = this.filterTextPacket(playerchatmessage.signedContent()); +- CompletableFuture completablefuture1 = this.server.getChatDecorator().decorate(this.player, null, playerchatmessage.decoratedContent()); // Paper ++ CompletableFuture completablefuture = this.filterTextPacket(playerchatmessage.signedContent()); ++ CompletableFuture completablefuture1 = this.server.getChatDecorator().decorate(this.player, null, playerchatmessage.decoratedContent()); // Paper + +- this.chatMessageChain.append((executor) -> { +- return CompletableFuture.allOf(completablefuture, completablefuture1).thenAcceptAsync((ovoid) -> { +- PlayerChatMessage playerchatmessage1 = playerchatmessage.filter(((FilteredText) completablefuture.join()).mask()).withResult(completablefuture1.join()); // Paper ++ this.chatMessageChain.append((executor) -> { ++ return CompletableFuture.allOf(completablefuture, completablefuture1).thenAcceptAsync((ovoid) -> { ++ PlayerChatMessage playerchatmessage1 = playerchatmessage.filter(((FilteredText) completablefuture.join()).mask()).withResult(completablefuture1.join()); // Paper + +- this.broadcastChatMessage(playerchatmessage1); +- }, this.server.chatExecutor); // CraftBukkit - async chat +- }); ++ this.broadcastChatMessage(playerchatmessage1); ++ }, this.server.chatExecutor); // CraftBukkit - async chat ++ }); + // }); // CraftBukkit - async chat + } + +@@ -2263,7 +2295,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + public void handleChatCommand(ServerboundChatCommandPacket packet) { + if (ServerGamePacketListenerImpl.isChatMessageIllegal(packet.command())) { + this.server.scheduleOnMain(() -> { // Paper - push to main for event firing +- this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper ++ this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper + }); // Paper - push to main for event firing + } else { + Optional optional = this.tryHandleChat(packet.command(), packet.timeStamp(), packet.lastSeenMessages()); +@@ -2288,7 +2320,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + // CraftBukkit start + String command = "/" + packet.command(); + if (org.spigotmc.SpigotConfig.logCommands) { // Paper +- ServerGamePacketListenerImpl.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command); ++ ServerGamePacketListenerImpl.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command); + } // Paper + + PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), command, new LazyPlayerSet(this.server)); +@@ -2353,7 +2385,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + if (!this.updateChatOrder(timestamp)) { + ServerGamePacketListenerImpl.LOGGER.warn("{} sent out-of-order chat: '{}': {} > {}", this.player.getName().getString(), message, this.lastChatTimeStamp.get().getEpochSecond(), timestamp.getEpochSecond()); // Paper + this.server.scheduleOnMain(() -> { // Paper - push to main +- this.disconnect(Component.translatable("multiplayer.disconnect.out_of_order_chat"), org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event ca ++ this.disconnect(Component.translatable("multiplayer.disconnect.out_of_order_chat"), org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event ca + }); // Paper - push to main + return Optional.empty(); + } else { +@@ -2424,7 +2456,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + this.handleCommand(s); + } else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) { + // Do nothing, this is coming from a plugin +- // Paper start ++ // Paper start + } else if (true) { + final ChatProcessor cp = new ChatProcessor(this.server, this.player, original, async); + cp.process(); +@@ -2535,7 +2567,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + // Paper End + co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper + if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot +- this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); ++ this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); + + CraftPlayer player = this.getCraftPlayer(); + +@@ -2614,16 +2646,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + @Override + public void handleChatAck(ServerboundChatAckPacket packet) { + LastSeenMessagesValidator lastseenmessagesvalidator = this.lastSeenMessages; +- if (!this.lastSeenMessages.applyOffset(packet.offset())) { +- synchronized (this.lastSeenMessages) { +- // Scissors start - Add configuration option to disable chat signatures +- if (!ScissorsConfig.chatSignaturesEnabled) +- { +- return; +- } +- // Scissors end +- 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 ++ if (!this.lastSeenMessages.applyOffset(packet.offset())) { ++ synchronized (this.lastSeenMessages) { ++ // Scissors start - Add configuration option to disable chat signatures ++ if (!ScissorsConfig.chatSignaturesEnabled) ++ { ++ return; ++ } ++ // Scissors end ++ 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 + } + + } +@@ -2862,7 +2894,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + } + + if (event.isCancelled()) { +- ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); // Paper - Refresh player inventory ++ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); // Paper - Refresh player inventory + return; + } + // CraftBukkit end +@@ -3436,19 +3468,19 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + itemstack = CraftItemStack.asNMSCopy(event.getCursor()); + + switch (event.getResult()) { +- case ALLOW: +- // Plugin cleared the id / stacksize checks +- flag2 = true; +- break; +- case DEFAULT: +- break; +- case DENY: +- // Reset the slot +- if (packet.getSlotNum() >= 0) { +- this.player.connection.send(new ClientboundContainerSetSlotPacket(this.player.inventoryMenu.containerId, this.player.inventoryMenu.incrementStateId(), packet.getSlotNum(), this.player.inventoryMenu.getSlot(packet.getSlotNum()).getItem())); +- this.player.connection.send(new ClientboundContainerSetSlotPacket(-1, this.player.inventoryMenu.incrementStateId(), -1, ItemStack.EMPTY)); +- } +- return; ++ case ALLOW: ++ // Plugin cleared the id / stacksize checks ++ flag2 = true; ++ break; ++ case DEFAULT: ++ break; ++ case DENY: ++ // Reset the slot ++ if (packet.getSlotNum() >= 0) { ++ this.player.connection.send(new ClientboundContainerSetSlotPacket(this.player.inventoryMenu.containerId, this.player.inventoryMenu.incrementStateId(), packet.getSlotNum(), this.player.inventoryMenu.getSlot(packet.getSlotNum()).getItem())); ++ this.player.connection.send(new ClientboundContainerSetSlotPacket(-1, this.player.inventoryMenu.incrementStateId(), -1, ItemStack.EMPTY)); ++ } ++ return; + } + } + // CraftBukkit end +@@ -3516,7 +3548,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + } else if (!this.isSingleplayerOwner()) { + // Paper start - This needs to be handled on the main thread for plugins + server.submit(() -> { +- this.disconnect(Component.translatable("disconnect.timeout"), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause ++ this.disconnect(Component.translatable("disconnect.timeout"), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause + }); + // Paper end + }