From c90258ba88d1c464d30841cf3072a60847668f93 Mon Sep 17 00:00:00 2001 From: Doc Date: Wed, 25 Mar 2026 10:42:28 -0300 Subject: [PATCH 1/6] Call WorldGameRuleChangeEvent for World Options Menu --- .../server/network/ServerGamePacketListenerImpl.java.patch | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 8b15ba7efdaf..220a149ff109 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -584,11 +584,12 @@ } } -@@ -808,7 +_,7 @@ +@@ -808,7 +_,8 @@ private void setGameRuleValue(final GameRules gameRules, final GameRule rule, final String value) { rule.deserialize(value).result().ifPresent(parsedValue -> { - gameRules.set(rule, (T)parsedValue, this.server); ++ parsedValue = org.bukkit.craftbukkit.event.CraftEventFactory.handleGameRuleSet(rule, parsedValue, this.player.level(), this.player.getBukkitEntity()).value(); // Paper - per-world game rules and event + gameRules.set(rule, (T)parsedValue, this.player.level()); // Paper - per-world game rules this.broadcastGameRuleChangeToOperators(rule, (T)parsedValue); }); From 988a9b7efe7989459c443d3eb8340b8389511e50 Mon Sep 17 00:00:00 2001 From: Doc Date: Wed, 25 Mar 2026 11:51:34 -0300 Subject: [PATCH 2/6] Updated WorldGameRuleChangeEvent for reference new ways to update game rules --- .../io/papermc/paper/event/world/WorldGameRuleChangeEvent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/paper-api/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java b/paper-api/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java index c44006faf327..73569979b732 100644 --- a/paper-api/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java +++ b/paper-api/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java @@ -11,7 +11,8 @@ import org.jspecify.annotations.Nullable; /** - * Called when a world's gamerule is changed, either by command or by api. + * Called when a world's gamerule is changed, either by command, world options menu, or by api. + * @see Modifying game rules - Minecraft wiki */ @NullMarked public class WorldGameRuleChangeEvent extends WorldEvent implements Cancellable { From eb9826622bcc7bbdf748d90405638ef4a5ef6955 Mon Sep 17 00:00:00 2001 From: Doc Date: Wed, 25 Mar 2026 17:41:40 -0300 Subject: [PATCH 3/6] Redirect World#setPVP to World GameRule for call event --- .../src/main/java/org/bukkit/craftbukkit/CraftWorld.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 8bb0c229b41b..9a672ebf80c3 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -1245,7 +1245,7 @@ public boolean getPVP() { @Override public void setPVP(boolean pvp) { - this.world.getGameRules().set(GameRules.PVP, pvp, this.world); + this.setGameRule(org.bukkit.GameRules.PVP, pvp); } @Override From 41de674bde056fa23377ac674b2d84053e1f3d19 Mon Sep 17 00:00:00 2001 From: Doc Date: Wed, 25 Mar 2026 17:44:45 -0300 Subject: [PATCH 4/6] Include permission check for game rule --- .../network/ServerGamePacketListenerImpl.java.patch | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 220a149ff109..4df353afbfc7 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -584,6 +584,15 @@ } } +@@ -790,7 +_,7 @@ + @Override + public void handleSetGameRule(final ServerboundSetGameRulePacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); +- if (!this.player.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER)) { ++ if (!this.player.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER) && !this.player.getBukkitEntity().hasPermission("minecraft.command.gamerule")) { // Paper - add permission check + LOGGER.warn("Player {} tried to set game rule values without required permissions", this.player.getGameProfile().name()); + } else { + GameRules gameRules = this.player.level().getGameRules(); @@ -808,7 +_,8 @@ private void setGameRuleValue(final GameRules gameRules, final GameRule rule, final String value) { From eeef05957bfa06f7c8d65dfc047f8994d9c978ee Mon Sep 17 00:00:00 2001 From: Doc Date: Wed, 25 Mar 2026 18:01:32 -0300 Subject: [PATCH 5/6] Remove redundant set game rule for ServerGamePacketListenerImpl --- .../server/network/ServerGamePacketListenerImpl.java.patch | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 4df353afbfc7..0e5d4d933257 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -593,13 +593,12 @@ LOGGER.warn("Player {} tried to set game rule values without required permissions", this.player.getGameProfile().name()); } else { GameRules gameRules = this.player.level().getGameRules(); -@@ -808,7 +_,8 @@ +@@ -808,7 +_,7 @@ private void setGameRuleValue(final GameRules gameRules, final GameRule rule, final String value) { rule.deserialize(value).result().ifPresent(parsedValue -> { - gameRules.set(rule, (T)parsedValue, this.server); + parsedValue = org.bukkit.craftbukkit.event.CraftEventFactory.handleGameRuleSet(rule, parsedValue, this.player.level(), this.player.getBukkitEntity()).value(); // Paper - per-world game rules and event -+ gameRules.set(rule, (T)parsedValue, this.player.level()); // Paper - per-world game rules this.broadcastGameRuleChangeToOperators(rule, (T)parsedValue); }); } From 695bf18ba7e9f010a93b68ca9e708c3ec2675b8a Mon Sep 17 00:00:00 2001 From: Doc Date: Wed, 25 Mar 2026 18:06:32 -0300 Subject: [PATCH 6/6] Remove unused import --- .../src/main/java/org/bukkit/craftbukkit/CraftServer.java | 1 - .../src/main/java/org/bukkit/craftbukkit/CraftWorld.java | 1 - 2 files changed, 2 deletions(-) diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 2081802580f1..f9627f06336b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -95,7 +95,6 @@ import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.item.crafting.RepairItemRecipe; import net.minecraft.world.level.CustomSpawner; -import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.GameType; import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.biome.BiomeManager; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 9a672ebf80c3..6e1bac760ee0 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -73,7 +73,6 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.gamerules.GameRule; -import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.level.storage.LevelResource;