diff --git a/patches/api/0449-OperatorInteractEvents-WIP.patch b/patches/api/0449-OperatorInteractEvents-WIP.patch new file mode 100644 index 0000000000..8edd0980a4 --- /dev/null +++ b/patches/api/0449-OperatorInteractEvents-WIP.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 13 Jun 2023 23:42:01 -0700 +Subject: [PATCH] OperatorInteractEvents - WIP + + +diff --git a/src/main/java/io/papermc/paper/event/player/OperatorBlockInteractEvent.java b/src/main/java/io/papermc/paper/event/player/OperatorBlockInteractEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5b68151606ad71f09f527fcc87880a0819d6657f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/OperatorBlockInteractEvent.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.event.player; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.block.Block; ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public final class OperatorBlockInteractEvent extends OperatorInteractEvent { ++ ++ private final Block block; ++ ++ @ApiStatus.Internal ++ public OperatorBlockInteractEvent(final @NotNull Player player, final @NotNull Action action, final @NotNull Block block, final @Nullable Component denialMessage) { ++ super(player, action, denialMessage); ++ this.block = block; ++ } ++ ++ public @NotNull Block getBlock() { ++ return this.block; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/OperatorEntityInteractEvent.java b/src/main/java/io/papermc/paper/event/player/OperatorEntityInteractEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b39a5eb82cb128934040972aa3c8f7cecdb7da7c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/OperatorEntityInteractEvent.java +@@ -0,0 +1,21 @@ ++package io.papermc.paper.event.player; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public final class OperatorEntityInteractEvent extends OperatorInteractEvent { ++ ++ private final Entity target; ++ ++ public OperatorEntityInteractEvent(final @NotNull Player player, final @NotNull Action action, final @NotNull Entity target, final @Nullable Component denialMessage) { ++ super(player, action, denialMessage); ++ this.target = target; ++ } ++ ++ public @NotNull Entity getTarget() { ++ return this.target; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/OperatorInteractEvent.java b/src/main/java/io/papermc/paper/event/player/OperatorInteractEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d325e836b9e43c80ecb5c6aea7fadd3ab3a855e1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/OperatorInteractEvent.java +@@ -0,0 +1,72 @@ ++package io.papermc.paper.event.player; ++ ++import com.google.common.base.Preconditions; ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public abstract sealed class OperatorInteractEvent extends PlayerEvent implements Cancellable permits OperatorBlockInteractEvent, OperatorEntityInteractEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ private final Action action; ++ private Component denialMessage; ++ private Result result = Result.DEFAULT; ++ ++ @ApiStatus.Internal ++ public OperatorInteractEvent(final @NotNull Player player, final @NotNull Action action, final @Nullable Component denialMessage) { ++ super(player); ++ this.action = action; ++ this.denialMessage = denialMessage; ++ } ++ ++ public @NotNull Action getAction() { ++ return this.action; ++ } ++ ++ public @NotNull Result getResult() { ++ return this.result; ++ } ++ ++ public void setResult(final @NotNull Result result) { ++ Preconditions.checkArgument(result != null, "result must not be null"); ++ this.result = result; ++ } ++ ++ public @Nullable Component denialMessage() { ++ return this.denialMessage; ++ } ++ ++ public void denialMessage(final @Nullable Component denialMessage) { ++ this.denialMessage = denialMessage; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.result == Result.DENY; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.result = cancel ? Result.DENY : Result.DEFAULT; ++ } ++ ++ @Override ++ public @NotNull HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static @NotNull HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum Action { ++ DESTROY, ++ PLACE, ++ CHANGE ++ } ++} diff --git a/patches/server/1055-OperatorInteractEvents-WIP.patch b/patches/server/1055-OperatorInteractEvents-WIP.patch new file mode 100644 index 0000000000..d662df54a0 --- /dev/null +++ b/patches/server/1055-OperatorInteractEvents-WIP.patch @@ -0,0 +1,174 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 13 Jun 2023 23:42:05 -0700 +Subject: [PATCH] OperatorInteractEvents - WIP + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 106a312aba249d1e83e4b535fc6e741e04ccfd14..7b691cf2715ef5a094a8a61148b41dfc70e842bb 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -409,7 +409,11 @@ public class ServerPlayerGameMode { + BlockEntity tileentity = this.level.getBlockEntity(pos); + Block block = iblockdata.getBlock(); + +- if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission ++ // Paper start - operator interact event ++ final it.unimi.dsi.fastutil.Pair pair; ++ if (block instanceof GameMasterBlock && !(pair = CraftEventFactory.callOpBlockInteractEvent(this.player, this.level, pos, io.papermc.paper.event.player.OperatorInteractEvent.Action.DESTROY, () -> this.player.canUseGameMasterBlocks() || (block instanceof net.minecraft.world.level.block.CommandBlock && this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")), null)).left()) { // Paper - command block permission ++ if (pair.right() != null) this.player.sendSystemMessage(pair.right()); ++ // Paper end - operator interact event + this.level.sendBlockUpdated(pos, iblockdata, iblockdata, 3); + return false; + } else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) { +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 65bb221993147a558995b36fb835f7b82e0eb4bd..542807f5e352b3ce6b51c355fa2bd7c59486f80a 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -848,9 +848,22 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (!this.server.isCommandBlockEnabled()) { + this.player.sendSystemMessage(Component.translatable("advMode.notEnabled")); +- } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission +- this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); + } else { ++ // Paper start - operator interact event ++ final it.unimi.dsi.fastutil.Pair pair = ++ CraftEventFactory.callOpBlockInteractEvent( ++ this.player, ++ this.player.serverLevel(), ++ packet.getPos(), ++ io.papermc.paper.event.player.OperatorInteractEvent.Action.CHANGE, ++ () -> this.player.canUseGameMasterBlocks() || (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")), ++ Component.translatable("advMode.notAllowed") ++ ); ++ if (!pair.left()) { ++ if (pair.right() != null) this.player.sendSystemMessage(pair.right()); ++ return; ++ } ++ // Paper end - operator interact event + BaseCommandBlock commandblocklistenerabstract = null; + CommandBlockEntity tileentitycommand = null; + BlockPos blockposition = packet.getPos(); +@@ -915,12 +928,26 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (!this.server.isCommandBlockEnabled()) { + this.player.sendSystemMessage(Component.translatable("advMode.notEnabled")); +- } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission +- this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); ++ // } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission // Paper - move check below ++ // this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); + } else { + BaseCommandBlock commandblocklistenerabstract = packet.getCommandBlock(this.player.level()); + + if (commandblocklistenerabstract != null) { ++ // Paper start - operator interact events ++ final it.unimi.dsi.fastutil.Pair pair = ++ CraftEventFactory.callOpEntityInteractEvent( ++ this.player, ++ ((net.minecraft.world.entity.vehicle.MinecartCommandBlock.MinecartCommandBase) commandblocklistenerabstract).getMinecart(), ++ io.papermc.paper.event.player.OperatorInteractEvent.Action.CHANGE, ++ () -> this.player.canUseGameMasterBlocks() || (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")), ++ Component.translatable("advMode.notAllowed") ++ ); ++ if (!pair.left()) { ++ if (pair.right() != null) this.player.sendSystemMessage(pair.right()); ++ return; ++ } ++ // Paper end - operator interact events + commandblocklistenerabstract.setCommand(packet.getCommand()); + commandblocklistenerabstract.setTrackOutput(packet.isTrackOutput()); + if (!packet.isTrackOutput()) { +@@ -996,7 +1023,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + @Override + public void handleSetStructureBlock(ServerboundSetStructureBlockPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); +- if (this.player.canUseGameMasterBlocks()) { ++ // Paper start - operator interact event ++ final it.unimi.dsi.fastutil.Pair pair = ++ CraftEventFactory.callOpBlockInteractEvent( ++ this.player, ++ this.player.serverLevel(), ++ packet.getPos(), ++ io.papermc.paper.event.player.OperatorInteractEvent.Action.CHANGE, ++ this.player::canUseGameMasterBlocks, ++ null ++ ); ++ if (!pair.left()) { ++ if (pair.right() != null) this.player.sendSystemMessage(pair.right()); ++ } else { ++ // Paper end - operator interact event + BlockPos blockposition = packet.getPos(); + BlockState iblockdata = this.player.level().getBlockState(blockposition); + BlockEntity tileentity = this.player.level().getBlockEntity(blockposition); +@@ -1054,7 +1094,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + @Override + public void handleSetJigsawBlock(ServerboundSetJigsawBlockPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); +- if (this.player.canUseGameMasterBlocks()) { ++ // Paper start - operator interact event ++ final it.unimi.dsi.fastutil.Pair pair = ++ CraftEventFactory.callOpBlockInteractEvent( ++ this.player, ++ this.player.serverLevel(), ++ packet.getPos(), ++ io.papermc.paper.event.player.OperatorInteractEvent.Action.CHANGE, ++ this.player::canUseGameMasterBlocks, ++ null ++ ); ++ if (!pair.left()) { ++ if (pair.right() != null) this.player.sendSystemMessage(pair.right()); ++ } else { ++ // Paper end - operator interact event + BlockPos blockposition = packet.getPos(); + BlockState iblockdata = this.player.level().getBlockState(blockposition); + BlockEntity tileentity = this.player.level().getBlockEntity(blockposition); +@@ -1077,7 +1130,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + @Override + public void handleJigsawGenerate(ServerboundJigsawGeneratePacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); +- if (this.player.canUseGameMasterBlocks()) { ++ // Paper start - operator interact event ++ final it.unimi.dsi.fastutil.Pair pair = ++ CraftEventFactory.callOpBlockInteractEvent( ++ this.player, ++ this.player.serverLevel(), ++ packet.getPos(), ++ io.papermc.paper.event.player.OperatorInteractEvent.Action.CHANGE, ++ this.player::canUseGameMasterBlocks, ++ null ++ ); ++ if (!pair.left()) { ++ if (pair.right() != null) this.player.sendSystemMessage(pair.right()); ++ } else { ++ // Paper end - operator interact event + BlockPos blockposition = packet.getPos(); + BlockEntity tileentity = this.player.level().getBlockEntity(blockposition); + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 5dc160b743534665c6b3efb10b10f7c36e2da5ab..6e4328dca4703832739441f4ee349c21904be30a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -2166,4 +2166,22 @@ public class CraftEventFactory { + return event; + } + // Paper end - add EntityFertilizeEggEvent ++ ++ // Paper start ++ public static it.unimi.dsi.fastutil.Pair callOpBlockInteractEvent(final ServerPlayer serverPlayer, final Level world, final BlockPos blockPos, final io.papermc.paper.event.player.OperatorInteractEvent.Action action, final java.util.function.BooleanSupplier defaultCheck, @Nullable final net.minecraft.network.chat.Component denialMessage) { ++ final CraftBlock block = CraftBlock.at(world, blockPos); ++ final io.papermc.paper.event.player.OperatorInteractEvent event = new io.papermc.paper.event.player.OperatorBlockInteractEvent(serverPlayer.getBukkitEntity(), action, block, denialMessage == null ? null : io.papermc.paper.adventure.PaperAdventure.asAdventure(denialMessage)); ++ return callOperatorInteractEvent(event, defaultCheck); ++ } ++ ++ public static it.unimi.dsi.fastutil.Pair callOpEntityInteractEvent(final ServerPlayer serverPlayer, final Entity entity, final io.papermc.paper.event.player.OperatorInteractEvent.Action action, final java.util.function.BooleanSupplier defaultCheck, @Nullable final net.minecraft.network.chat.Component denialMessage) { ++ final io.papermc.paper.event.player.OperatorInteractEvent event = new io.papermc.paper.event.player.OperatorEntityInteractEvent(serverPlayer.getBukkitEntity(), action, entity.getBukkitEntity(), denialMessage == null ? null : io.papermc.paper.adventure.PaperAdventure.asAdventure(denialMessage)); ++ return callOperatorInteractEvent(event, defaultCheck); ++ } ++ ++ private static it.unimi.dsi.fastutil.Pair callOperatorInteractEvent(final io.papermc.paper.event.player.OperatorInteractEvent event, final java.util.function.BooleanSupplier defaultCheck) { ++ final boolean result = event.callEvent() && (event.getResult() == org.bukkit.event.Event.Result.ALLOW || defaultCheck.getAsBoolean()); ++ return it.unimi.dsi.fastutil.Pair.of(result, io.papermc.paper.adventure.PaperAdventure.asVanilla(event.denialMessage())); ++ } ++ // Paper end + }