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 {
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..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
@@ -584,12 +584,21 @@
}
}
+@@ -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 +_,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);
-+ gameRules.set(rule, (T)parsedValue, this.player.level()); // Paper - per-world game rules
++ parsedValue = org.bukkit.craftbukkit.event.CraftEventFactory.handleGameRuleSet(rule, parsedValue, this.player.level(), this.player.getBukkitEntity()).value(); // Paper - per-world game rules and event
this.broadcastGameRuleChangeToOperators(rule, (T)parsedValue);
});
}
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 8bb0c229b41b..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;
@@ -1245,7 +1244,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