--- a/net/minecraft/world/level/GameRules.java
+++ b/net/minecraft/world/level/GameRules.java
@@ -10,10 +10,13 @@
 import com.mojang.brigadier.context.CommandContext;
 import com.mojang.brigadier.exceptions.CommandSyntaxException;
 import com.mojang.logging.LogUtils;
+import com.mojang.serialization.DataResult;
 import com.mojang.serialization.DynamicLike;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.Supplier;
@@ -29,188 +32,106 @@
 import org.slf4j.Logger;
 
 public class GameRules {
+
     public static final int DEFAULT_RANDOM_TICK_SPEED = 3;
     static final Logger LOGGER = LogUtils.getLogger();
-    private static final Map<GameRules.Key<?>, GameRules.Type<?>> GAME_RULE_TYPES = Maps.newTreeMap(Comparator.comparing(key -> key.id));
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOFIRETICK = register(
-        "doFireTick", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_MOBGRIEFING = register(
-        "mobGriefing", GameRules.Category.MOBS, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_KEEPINVENTORY = register(
-        "keepInventory", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOMOBSPAWNING = register(
-        "doMobSpawning", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOMOBLOOT = register(
-        "doMobLoot", GameRules.Category.DROPS, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_PROJECTILESCANBREAKBLOCKS = register(
-        "projectilesCanBreakBlocks", GameRules.Category.DROPS, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOBLOCKDROPS = register(
-        "doTileDrops", GameRules.Category.DROPS, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOENTITYDROPS = register(
-        "doEntityDrops", GameRules.Category.DROPS, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_COMMANDBLOCKOUTPUT = register(
-        "commandBlockOutput", GameRules.Category.CHAT, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_NATURAL_REGENERATION = register(
-        "naturalRegeneration", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DAYLIGHT = register(
-        "doDaylightCycle", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_LOGADMINCOMMANDS = register(
-        "logAdminCommands", GameRules.Category.CHAT, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_SHOWDEATHMESSAGES = register(
-        "showDeathMessages", GameRules.Category.CHAT, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_RANDOMTICKING = register(
-        "randomTickSpeed", GameRules.Category.UPDATES, GameRules.IntegerValue.create(3)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_SENDCOMMANDFEEDBACK = register(
-        "sendCommandFeedback", GameRules.Category.CHAT, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_REDUCEDDEBUGINFO = register(
-        "reducedDebugInfo", GameRules.Category.MISC, GameRules.BooleanValue.create(false, (server, rule) -> {
-            byte b = (byte)(rule.get() ? 22 : 23);
+    private static final Map<GameRules.Key<?>, GameRules.Type<?>> GAME_RULE_TYPES = Maps.newTreeMap(Comparator.comparing((gamerules_gamerulekey) -> {
+        return gamerules_gamerulekey.id;
+    }));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOFIRETICK = GameRules.register("doFireTick", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_MOBGRIEFING = GameRules.register("mobGriefing", GameRules.Category.MOBS, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_KEEPINVENTORY = GameRules.register("keepInventory", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOMOBSPAWNING = GameRules.register("doMobSpawning", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOMOBLOOT = GameRules.register("doMobLoot", GameRules.Category.DROPS, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_PROJECTILESCANBREAKBLOCKS = GameRules.register("projectilesCanBreakBlocks", GameRules.Category.DROPS, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOBLOCKDROPS = GameRules.register("doTileDrops", GameRules.Category.DROPS, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOENTITYDROPS = GameRules.register("doEntityDrops", GameRules.Category.DROPS, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_COMMANDBLOCKOUTPUT = GameRules.register("commandBlockOutput", GameRules.Category.CHAT, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_NATURAL_REGENERATION = GameRules.register("naturalRegeneration", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DAYLIGHT = GameRules.register("doDaylightCycle", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_LOGADMINCOMMANDS = GameRules.register("logAdminCommands", GameRules.Category.CHAT, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_SHOWDEATHMESSAGES = GameRules.register("showDeathMessages", GameRules.Category.CHAT, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_RANDOMTICKING = GameRules.register("randomTickSpeed", GameRules.Category.UPDATES, GameRules.IntegerValue.create(3));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_SENDCOMMANDFEEDBACK = GameRules.register("sendCommandFeedback", GameRules.Category.CHAT, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_REDUCEDDEBUGINFO = GameRules.register("reducedDebugInfo", GameRules.Category.MISC, GameRules.BooleanValue.create(false, (minecraftserver, gamerules_gameruleboolean) -> {
+        int i = gamerules_gameruleboolean.get() ? 22 : 23;
+        Iterator iterator = minecraftserver.players().iterator(); // CraftBukkit - per-world
 
-            for (ServerPlayer serverPlayer : server.getPlayerList().getPlayers()) {
-                serverPlayer.connection.send(new ClientboundEntityEventPacket(serverPlayer, b));
-            }
-        })
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_SPECTATORSGENERATECHUNKS = register(
-        "spectatorsGenerateChunks", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_SPAWN_RADIUS = register(
-        "spawnRadius", GameRules.Category.PLAYER, GameRules.IntegerValue.create(10)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DISABLE_ELYTRA_MOVEMENT_CHECK = register(
-        "disableElytraMovementCheck", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_MAX_ENTITY_CRAMMING = register(
-        "maxEntityCramming", GameRules.Category.MOBS, GameRules.IntegerValue.create(24)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_WEATHER_CYCLE = register(
-        "doWeatherCycle", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_LIMITED_CRAFTING = register(
-        "doLimitedCrafting", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (server, rule) -> {
-            for (ServerPlayer serverPlayer : server.getPlayerList().getPlayers()) {
-                serverPlayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LIMITED_CRAFTING, rule.get() ? 1.0F : 0.0F));
-            }
-        })
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_MAX_COMMAND_CHAIN_LENGTH = register(
-        "maxCommandChainLength", GameRules.Category.MISC, GameRules.IntegerValue.create(65536)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_MAX_COMMAND_FORK_COUNT = register(
-        "maxCommandForkCount", GameRules.Category.MISC, GameRules.IntegerValue.create(65536)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_COMMAND_MODIFICATION_BLOCK_LIMIT = register(
-        "commandModificationBlockLimit", GameRules.Category.MISC, GameRules.IntegerValue.create(32768)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_ANNOUNCE_ADVANCEMENTS = register(
-        "announceAdvancements", GameRules.Category.CHAT, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DISABLE_RAIDS = register(
-        "disableRaids", GameRules.Category.MOBS, GameRules.BooleanValue.create(false)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOINSOMNIA = register(
-        "doInsomnia", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_IMMEDIATE_RESPAWN = register(
-        "doImmediateRespawn", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (server, rule) -> {
-            for (ServerPlayer serverPlayer : server.getPlayerList().getPlayers()) {
-                serverPlayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.IMMEDIATE_RESPAWN, rule.get() ? 1.0F : 0.0F));
-            }
-        })
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_PLAYERS_NETHER_PORTAL_DEFAULT_DELAY = register(
-        "playersNetherPortalDefaultDelay", GameRules.Category.PLAYER, GameRules.IntegerValue.create(80)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_PLAYERS_NETHER_PORTAL_CREATIVE_DELAY = register(
-        "playersNetherPortalCreativeDelay", GameRules.Category.PLAYER, GameRules.IntegerValue.create(1)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DROWNING_DAMAGE = register(
-        "drowningDamage", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_FALL_DAMAGE = register(
-        "fallDamage", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_FIRE_DAMAGE = register(
-        "fireDamage", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_FREEZE_DAMAGE = register(
-        "freezeDamage", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_PATROL_SPAWNING = register(
-        "doPatrolSpawning", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_TRADER_SPAWNING = register(
-        "doTraderSpawning", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_WARDEN_SPAWNING = register(
-        "doWardenSpawning", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_FORGIVE_DEAD_PLAYERS = register(
-        "forgiveDeadPlayers", GameRules.Category.MOBS, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_UNIVERSAL_ANGER = register(
-        "universalAnger", GameRules.Category.MOBS, GameRules.BooleanValue.create(false)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_PLAYERS_SLEEPING_PERCENTAGE = register(
-        "playersSleepingPercentage", GameRules.Category.PLAYER, GameRules.IntegerValue.create(100)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_BLOCK_EXPLOSION_DROP_DECAY = register(
-        "blockExplosionDropDecay", GameRules.Category.DROPS, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_MOB_EXPLOSION_DROP_DECAY = register(
-        "mobExplosionDropDecay", GameRules.Category.DROPS, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_TNT_EXPLOSION_DROP_DECAY = register(
-        "tntExplosionDropDecay", GameRules.Category.DROPS, GameRules.BooleanValue.create(false)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_SNOW_ACCUMULATION_HEIGHT = register(
-        "snowAccumulationHeight", GameRules.Category.UPDATES, GameRules.IntegerValue.create(1)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_WATER_SOURCE_CONVERSION = register(
-        "waterSourceConversion", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_LAVA_SOURCE_CONVERSION = register(
-        "lavaSourceConversion", GameRules.Category.UPDATES, GameRules.BooleanValue.create(false)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_GLOBAL_SOUND_EVENTS = register(
-        "globalSoundEvents", GameRules.Category.MISC, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_VINES_SPREAD = register(
-        "doVinesSpread", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.BooleanValue> RULE_ENDER_PEARLS_VANISH_ON_DEATH = register(
-        "enderPearlsVanishOnDeath", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
-    );
-    public static final GameRules.Key<GameRules.IntegerValue> RULE_SPAWN_CHUNK_RADIUS = register(
-        "spawnChunkRadius", GameRules.Category.MISC, GameRules.IntegerValue.create(2, 0, 32, (server, value) -> {
-            ServerLevel serverLevel = server.overworld();
-            serverLevel.setDefaultSpawnPos(serverLevel.getSharedSpawnPos(), serverLevel.getSharedSpawnAngle());
-        })
-    );
+        while (iterator.hasNext()) {
+            ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+
+            entityplayer.connection.send(new ClientboundEntityEventPacket(entityplayer, (byte) i));
+        }
+
+    }));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_SPECTATORSGENERATECHUNKS = GameRules.register("spectatorsGenerateChunks", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_SPAWN_RADIUS = GameRules.register("spawnRadius", GameRules.Category.PLAYER, GameRules.IntegerValue.create(10));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DISABLE_ELYTRA_MOVEMENT_CHECK = GameRules.register("disableElytraMovementCheck", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_MAX_ENTITY_CRAMMING = GameRules.register("maxEntityCramming", GameRules.Category.MOBS, GameRules.IntegerValue.create(24));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_WEATHER_CYCLE = GameRules.register("doWeatherCycle", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_LIMITED_CRAFTING = GameRules.register("doLimitedCrafting", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (minecraftserver, gamerules_gameruleboolean) -> {
+        Iterator iterator = minecraftserver.players().iterator(); // CraftBukkit - per-world
+
+        while (iterator.hasNext()) {
+            ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+
+            entityplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LIMITED_CRAFTING, gamerules_gameruleboolean.get() ? 1.0F : 0.0F));
+        }
+
+    }));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_MAX_COMMAND_CHAIN_LENGTH = GameRules.register("maxCommandChainLength", GameRules.Category.MISC, GameRules.IntegerValue.create(65536));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_MAX_COMMAND_FORK_COUNT = GameRules.register("maxCommandForkCount", GameRules.Category.MISC, GameRules.IntegerValue.create(65536));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_COMMAND_MODIFICATION_BLOCK_LIMIT = GameRules.register("commandModificationBlockLimit", GameRules.Category.MISC, GameRules.IntegerValue.create(32768));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_ANNOUNCE_ADVANCEMENTS = GameRules.register("announceAdvancements", GameRules.Category.CHAT, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DISABLE_RAIDS = GameRules.register("disableRaids", GameRules.Category.MOBS, GameRules.BooleanValue.create(false));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DOINSOMNIA = GameRules.register("doInsomnia", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_IMMEDIATE_RESPAWN = GameRules.register("doImmediateRespawn", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (minecraftserver, gamerules_gameruleboolean) -> {
+        Iterator iterator = minecraftserver.players().iterator(); // CraftBukkit - per-world
+
+        while (iterator.hasNext()) {
+            ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+
+            entityplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.IMMEDIATE_RESPAWN, gamerules_gameruleboolean.get() ? 1.0F : 0.0F));
+        }
+
+    }));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_PLAYERS_NETHER_PORTAL_DEFAULT_DELAY = GameRules.register("playersNetherPortalDefaultDelay", GameRules.Category.PLAYER, GameRules.IntegerValue.create(80));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_PLAYERS_NETHER_PORTAL_CREATIVE_DELAY = GameRules.register("playersNetherPortalCreativeDelay", GameRules.Category.PLAYER, GameRules.IntegerValue.create(1));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DROWNING_DAMAGE = GameRules.register("drowningDamage", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_FALL_DAMAGE = GameRules.register("fallDamage", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_FIRE_DAMAGE = GameRules.register("fireDamage", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_FREEZE_DAMAGE = GameRules.register("freezeDamage", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_PATROL_SPAWNING = GameRules.register("doPatrolSpawning", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_TRADER_SPAWNING = GameRules.register("doTraderSpawning", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_WARDEN_SPAWNING = GameRules.register("doWardenSpawning", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_FORGIVE_DEAD_PLAYERS = GameRules.register("forgiveDeadPlayers", GameRules.Category.MOBS, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_UNIVERSAL_ANGER = GameRules.register("universalAnger", GameRules.Category.MOBS, GameRules.BooleanValue.create(false));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_PLAYERS_SLEEPING_PERCENTAGE = GameRules.register("playersSleepingPercentage", GameRules.Category.PLAYER, GameRules.IntegerValue.create(100));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_BLOCK_EXPLOSION_DROP_DECAY = GameRules.register("blockExplosionDropDecay", GameRules.Category.DROPS, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_MOB_EXPLOSION_DROP_DECAY = GameRules.register("mobExplosionDropDecay", GameRules.Category.DROPS, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_TNT_EXPLOSION_DROP_DECAY = GameRules.register("tntExplosionDropDecay", GameRules.Category.DROPS, GameRules.BooleanValue.create(false));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_SNOW_ACCUMULATION_HEIGHT = GameRules.register("snowAccumulationHeight", GameRules.Category.UPDATES, GameRules.IntegerValue.create(1));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_WATER_SOURCE_CONVERSION = GameRules.register("waterSourceConversion", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_LAVA_SOURCE_CONVERSION = GameRules.register("lavaSourceConversion", GameRules.Category.UPDATES, GameRules.BooleanValue.create(false));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_GLOBAL_SOUND_EVENTS = GameRules.register("globalSoundEvents", GameRules.Category.MISC, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_VINES_SPREAD = GameRules.register("doVinesSpread", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.BooleanValue> RULE_ENDER_PEARLS_VANISH_ON_DEATH = GameRules.register("enderPearlsVanishOnDeath", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true));
+    public static final GameRules.Key<GameRules.IntegerValue> RULE_SPAWN_CHUNK_RADIUS = GameRules.register("spawnChunkRadius", GameRules.Category.MISC, GameRules.IntegerValue.create(2, 0, 32, (minecraftserver, gamerules_gameruleint) -> {
+        ServerLevel worldserver = minecraftserver; // CraftBukkit - per-world
+
+        worldserver.setDefaultSpawnPos(worldserver.getSharedSpawnPos(), worldserver.getSharedSpawnAngle());
+    }));
     private final Map<GameRules.Key<?>, GameRules.Value<?>> rules;
+    private final GameRules.Value<?>[] gameruleArray; // Paper - Perf: Use array for gamerule storage
 
     private static <T extends GameRules.Value<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
-        GameRules.Key<T> key = new GameRules.Key<>(name, category);
-        GameRules.Type<?> type2 = GAME_RULE_TYPES.put(key, type);
-        if (type2 != null) {
+        GameRules.Key<T> gamerules_gamerulekey = new GameRules.Key<>(name, category);
+        GameRules.Type<?> gamerules_gameruledefinition1 = (GameRules.Type) GameRules.GAME_RULE_TYPES.put(gamerules_gamerulekey, type);
+
+        if (gamerules_gameruledefinition1 != null) {
             throw new IllegalStateException("Duplicate game rule registration for " + name);
         } else {
-            return key;
+            return gamerules_gamerulekey;
         }
     }
 
@@ -220,68 +141,228 @@
     }
 
     public GameRules() {
-        this.rules = GAME_RULE_TYPES.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, e -> e.getValue().createRule()));
+        // Paper start - Perf: Use array for gamerule storage
+        this((Map) GameRules.GAME_RULE_TYPES.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry) -> {
+            return ((GameRules.Type) entry.getValue()).createRule();
+        })));
+        // Paper end - Perf: Use array for gamerule storage
     }
 
     private GameRules(Map<GameRules.Key<?>, GameRules.Value<?>> rules) {
         this.rules = rules;
+
+        // Paper start - Perf: Use array for gamerule storage
+        int arraySize = rules.keySet().stream().mapToInt(key -> key.gameRuleIndex).max().orElse(-1) + 1;
+        GameRules.Value<?>[] values = new GameRules.Value[arraySize];
+
+        for (Entry<GameRules.Key<?>, GameRules.Value<?>> entry : rules.entrySet()) {
+            values[entry.getKey().gameRuleIndex] = entry.getValue();
+        }
+
+        this.gameruleArray = values;
+        // Paper end - Perf: Use array for gamerule storage
     }
 
     public <T extends GameRules.Value<T>> T getRule(GameRules.Key<T> key) {
-        return (T)this.rules.get(key);
+        return key == null ? null : (T) this.gameruleArray[key.gameRuleIndex]; // Paper - Perf: Use array for gamerule storage
     }
 
     public CompoundTag createTag() {
-        CompoundTag compoundTag = new CompoundTag();
-        this.rules.forEach((key, rule) -> compoundTag.putString(key.id, rule.serialize()));
-        return compoundTag;
+        CompoundTag nbttagcompound = new CompoundTag();
+
+        this.rules.forEach((gamerules_gamerulekey, gamerules_gamerulevalue) -> {
+            nbttagcompound.putString(gamerules_gamerulekey.id, gamerules_gamerulevalue.serialize());
+        });
+        return nbttagcompound;
     }
 
     private void loadFromTag(DynamicLike<?> dynamic) {
-        this.rules.forEach((key, rule) -> dynamic.get(key.id).asString().ifSuccess(rule::deserialize));
+        this.rules.forEach((gamerules_gamerulekey, gamerules_gamerulevalue) -> {
+            DataResult<String> dataresult = dynamic.get(gamerules_gamerulekey.id).asString(); // CraftBukkit - decompile error
+
+            Objects.requireNonNull(gamerules_gamerulevalue);
+            dataresult.ifSuccess(gamerules_gamerulevalue::deserialize);
+        });
     }
 
     public GameRules copy() {
-        return new GameRules(this.rules.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, entry -> entry.getValue().copy())));
+        return new GameRules((Map) this.rules.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry) -> {
+            return ((GameRules.Value) entry.getValue()).copy();
+        })));
     }
 
     public static void visitGameRuleTypes(GameRules.GameRuleTypeVisitor visitor) {
-        GAME_RULE_TYPES.forEach((key, type) -> callVisitorCap(visitor, (GameRules.Key<?>)key, (GameRules.Type<?>)type));
+        GameRules.GAME_RULE_TYPES.forEach((gamerules_gamerulekey, gamerules_gameruledefinition) -> {
+            GameRules.callVisitorCap(visitor, gamerules_gamerulekey, gamerules_gameruledefinition);
+        });
     }
 
     private static <T extends GameRules.Value<T>> void callVisitorCap(GameRules.GameRuleTypeVisitor consumer, GameRules.Key<?> key, GameRules.Type<?> type) {
-        consumer.visit(key, type);
-        type.callVisitor(consumer, key);
+        consumer.visit((GameRules.Key<T>) key, (GameRules.Type<T>) type); // CraftBukkit - decompile error
+        ((GameRules.Type<T>) type).callVisitor(consumer, (GameRules.Key<T>) key); // CraftBukkit - decompile error
     }
 
-    public void assignFrom(GameRules rules, @Nullable MinecraftServer server) {
-        rules.rules.keySet().forEach(key -> this.assignCap((GameRules.Key<?>)key, rules, server));
+    public void assignFrom(GameRules gamerules, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
+        gamerules.rules.keySet().forEach((gamerules_gamerulekey) -> {
+            this.assignCap(gamerules_gamerulekey, gamerules, minecraftserver);
+        });
     }
 
-    private <T extends GameRules.Value<T>> void assignCap(GameRules.Key<T> key, GameRules rules, @Nullable MinecraftServer server) {
-        T value = rules.getRule(key);
-        this.<T>getRule(key).setFrom(value, server);
+    private <T extends GameRules.Value<T>> void assignCap(GameRules.Key<T> gamerules_gamerulekey, GameRules gamerules, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
+        T t0 = gamerules.getRule(gamerules_gamerulekey);
+
+        this.getRule(gamerules_gamerulekey).setFrom(t0, minecraftserver);
     }
 
     public boolean getBoolean(GameRules.Key<GameRules.BooleanValue> rule) {
-        return this.getRule(rule).get();
+        return ((GameRules.BooleanValue) this.getRule(rule)).get();
     }
 
     public int getInt(GameRules.Key<GameRules.IntegerValue> rule) {
-        return this.getRule(rule).get();
+        return ((GameRules.IntegerValue) this.getRule(rule)).get();
+    }
+
+    public static final class Key<T extends GameRules.Value<T>> {
+        // Paper start - Perf: Use array for gamerule storage
+        private static int lastGameRuleIndex = 0;
+        public final int gameRuleIndex = lastGameRuleIndex++;
+        // Paper end - Perf: Use array for gamerule storage
+
+        final String id;
+        private final GameRules.Category category;
+
+        public Key(String name, GameRules.Category category) {
+            this.id = name;
+            this.category = category;
+        }
+
+        public String toString() {
+            return this.id;
+        }
+
+        public boolean equals(Object object) {
+            return this == object ? true : object instanceof GameRules.Key && ((GameRules.Key) object).id.equals(this.id);
+        }
+
+        public int hashCode() {
+            return this.id.hashCode();
+        }
+
+        public String getId() {
+            return this.id;
+        }
+
+        public String getDescriptionId() {
+            return "gamerule." + this.id;
+        }
+
+        public GameRules.Category getCategory() {
+            return this.category;
+        }
+    }
+
+    public static enum Category {
+
+        PLAYER("gamerule.category.player"), MOBS("gamerule.category.mobs"), SPAWNING("gamerule.category.spawning"), DROPS("gamerule.category.drops"), UPDATES("gamerule.category.updates"), CHAT("gamerule.category.chat"), MISC("gamerule.category.misc");
+
+        private final String descriptionId;
+
+        private Category(final String s) {
+            this.descriptionId = s;
+        }
+
+        public String getDescriptionId() {
+            return this.descriptionId;
+        }
+    }
+
+    public static class Type<T extends GameRules.Value<T>> {
+
+        final Supplier<ArgumentType<?>> argument;
+        private final Function<GameRules.Type<T>, T> constructor;
+        final BiConsumer<ServerLevel, T> callback; // CraftBukkit - per-world
+        private final GameRules.VisitorCaller<T> visitorCaller;
+
+        Type(Supplier<ArgumentType<?>> argumentType, Function<GameRules.Type<T>, T> ruleFactory, BiConsumer<ServerLevel, T> changeCallback, GameRules.VisitorCaller<T> ruleAcceptor) { // CraftBukkit - per-world
+            this.argument = argumentType;
+            this.constructor = ruleFactory;
+            this.callback = changeCallback;
+            this.visitorCaller = ruleAcceptor;
+        }
+
+        public RequiredArgumentBuilder<CommandSourceStack, ?> createArgument(String name) {
+            return Commands.argument(name, (ArgumentType) this.argument.get());
+        }
+
+        public T createRule() {
+            return this.constructor.apply(this); // CraftBukkit - decompile error
+        }
+
+        public void callVisitor(GameRules.GameRuleTypeVisitor consumer, GameRules.Key<T> key) {
+            this.visitorCaller.call(consumer, key, this);
+        }
+    }
+
+    public abstract static class Value<T extends GameRules.Value<T>> {
+
+        protected final GameRules.Type<T> type;
+
+        public Value(GameRules.Type<T> type) {
+            this.type = type;
+        }
+
+        protected abstract void updateFromArgument(CommandContext<CommandSourceStack> context, String name, GameRules.Key<T> gameRuleKey); // Paper - Add WorldGameRuleChangeEvent
+
+        public void setFromArgument(CommandContext<CommandSourceStack> context, String name, GameRules.Key<T> gameRuleKey) { // Paper - Add WorldGameRuleChangeEvent
+            this.updateFromArgument(context, name, gameRuleKey); // Paper - Add WorldGameRuleChangeEvent
+            this.onChanged(((CommandSourceStack) context.getSource()).getLevel()); // CraftBukkit - per-world
+        }
+
+        public void onChanged(@Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
+            if (minecraftserver != null) {
+                this.type.callback.accept(minecraftserver, this.getSelf());
+            }
+
+        }
+
+        public abstract void deserialize(String value); // PAIL - private->public
+
+        public abstract String serialize();
+
+        public String toString() {
+            return this.serialize();
+        }
+
+        public abstract int getCommandResult();
+
+        protected abstract T getSelf();
+
+        protected abstract T copy();
+
+        public abstract void setFrom(T t0, @Nullable ServerLevel minecraftserver); // CraftBukkit - per-world
+    }
+
+    public interface GameRuleTypeVisitor {
+
+        default <T extends GameRules.Value<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {}
+
+        default void visitBoolean(GameRules.Key<GameRules.BooleanValue> key, GameRules.Type<GameRules.BooleanValue> type) {}
+
+        default void visitInteger(GameRules.Key<GameRules.IntegerValue> key, GameRules.Type<GameRules.IntegerValue> type) {}
     }
 
     public static class BooleanValue extends GameRules.Value<GameRules.BooleanValue> {
+
         private boolean value;
 
-        static GameRules.Type<GameRules.BooleanValue> create(boolean initialValue, BiConsumer<MinecraftServer, GameRules.BooleanValue> changeCallback) {
-            return new GameRules.Type<>(
-                BoolArgumentType::bool, type -> new GameRules.BooleanValue(type, initialValue), changeCallback, GameRules.GameRuleTypeVisitor::visitBoolean
-            );
+        static GameRules.Type<GameRules.BooleanValue> create(boolean initialValue, BiConsumer<ServerLevel, GameRules.BooleanValue> changeCallback) { // CraftBukkit - per-world
+            return new GameRules.Type<>(BoolArgumentType::bool, (gamerules_gameruledefinition) -> {
+                return new GameRules.BooleanValue(gamerules_gameruledefinition, initialValue);
+            }, changeCallback, GameRules.GameRuleTypeVisitor::visitBoolean);
         }
 
         static GameRules.Type<GameRules.BooleanValue> create(boolean initialValue) {
-            return create(initialValue, (server, rule) -> {
+            return BooleanValue.create(initialValue, (minecraftserver, gamerules_gameruleboolean) -> {
             });
         }
 
@@ -291,17 +372,20 @@
         }
 
         @Override
-        protected void updateFromArgument(CommandContext<CommandSourceStack> context, String name) {
-            this.value = BoolArgumentType.getBool(context, name);
+        protected void updateFromArgument(CommandContext<CommandSourceStack> context, String name, GameRules.Key<BooleanValue> gameRuleKey) { // Paper start - Add WorldGameRuleChangeEvent
+            io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule<Boolean>) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(BoolArgumentType.getBool(context, name)));
+            if (!event.callEvent()) return;
+            this.value = Boolean.parseBoolean(event.getValue());
+            // Paper end - Add WorldGameRuleChangeEvent
         }
 
         public boolean get() {
             return this.value;
         }
 
-        public void set(boolean value, @Nullable MinecraftServer server) {
-            this.value = value;
-            this.onChanged(server);
+        public void set(boolean flag, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
+            this.value = flag;
+            this.onChanged(minecraftserver);
         }
 
         @Override
@@ -310,7 +394,7 @@
         }
 
         @Override
-        protected void deserialize(String value) {
+        public void deserialize(String value) { // PAIL - protected->public
             this.value = Boolean.parseBoolean(value);
         }
 
@@ -329,69 +413,32 @@
             return new GameRules.BooleanValue(this.type, this.value);
         }
 
-        @Override
-        public void setFrom(GameRules.BooleanValue rule, @Nullable MinecraftServer server) {
-            this.value = rule.value;
-            this.onChanged(server);
-        }
-    }
-
-    public static enum Category {
-        PLAYER("gamerule.category.player"),
-        MOBS("gamerule.category.mobs"),
-        SPAWNING("gamerule.category.spawning"),
-        DROPS("gamerule.category.drops"),
-        UPDATES("gamerule.category.updates"),
-        CHAT("gamerule.category.chat"),
-        MISC("gamerule.category.misc");
-
-        private final String descriptionId;
-
-        private Category(final String category) {
-            this.descriptionId = category;
-        }
-
-        public String getDescriptionId() {
-            return this.descriptionId;
-        }
-    }
-
-    public interface GameRuleTypeVisitor {
-        default <T extends GameRules.Value<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {
-        }
-
-        default void visitBoolean(GameRules.Key<GameRules.BooleanValue> key, GameRules.Type<GameRules.BooleanValue> type) {
-        }
-
-        default void visitInteger(GameRules.Key<GameRules.IntegerValue> key, GameRules.Type<GameRules.IntegerValue> type) {
+        public void setFrom(GameRules.BooleanValue gamerules_gameruleboolean, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
+            this.value = gamerules_gameruleboolean.value;
+            this.onChanged(minecraftserver);
         }
     }
 
     public static class IntegerValue extends GameRules.Value<GameRules.IntegerValue> {
+
         private int value;
 
-        private static GameRules.Type<GameRules.IntegerValue> create(int initialValue, BiConsumer<MinecraftServer, GameRules.IntegerValue> changeCallback) {
-            return new GameRules.Type<>(
-                IntegerArgumentType::integer,
-                type -> new GameRules.IntegerValue(type, initialValue),
-                changeCallback,
-                GameRules.GameRuleTypeVisitor::visitInteger
-            );
+        private static GameRules.Type<GameRules.IntegerValue> create(int initialValue, BiConsumer<ServerLevel, GameRules.IntegerValue> changeCallback) { // CraftBukkit - per-world
+            return new GameRules.Type<>(IntegerArgumentType::integer, (gamerules_gameruledefinition) -> {
+                return new GameRules.IntegerValue(gamerules_gameruledefinition, initialValue);
+            }, changeCallback, GameRules.GameRuleTypeVisitor::visitInteger);
         }
 
-        static GameRules.Type<GameRules.IntegerValue> create(
-            int initialValue, int min, int max, BiConsumer<MinecraftServer, GameRules.IntegerValue> changeCallback
-        ) {
-            return new GameRules.Type<>(
-                () -> IntegerArgumentType.integer(min, max),
-                type -> new GameRules.IntegerValue(type, initialValue),
-                changeCallback,
-                GameRules.GameRuleTypeVisitor::visitInteger
-            );
+        static GameRules.Type<GameRules.IntegerValue> create(int initialValue, int min, int max, BiConsumer<ServerLevel, GameRules.IntegerValue> changeCallback) { // CraftBukkit - per-world
+            return new GameRules.Type<>(() -> {
+                return IntegerArgumentType.integer(min, max);
+            }, (gamerules_gameruledefinition) -> {
+                return new GameRules.IntegerValue(gamerules_gameruledefinition, initialValue);
+            }, changeCallback, GameRules.GameRuleTypeVisitor::visitInteger);
         }
 
         static GameRules.Type<GameRules.IntegerValue> create(int initialValue) {
-            return create(initialValue, (server, rule) -> {
+            return IntegerValue.create(initialValue, (minecraftserver, gamerules_gameruleint) -> {
             });
         }
 
@@ -401,17 +448,20 @@
         }
 
         @Override
-        protected void updateFromArgument(CommandContext<CommandSourceStack> context, String name) {
-            this.value = IntegerArgumentType.getInteger(context, name);
+        protected void updateFromArgument(CommandContext<CommandSourceStack> context, String name, GameRules.Key<IntegerValue> gameRuleKey) { // Paper start - Add WorldGameRuleChangeEvent
+            io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule<Integer>) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(IntegerArgumentType.getInteger(context, name)));
+            if (!event.callEvent()) return;
+            this.value = Integer.parseInt(event.getValue());
+            // Paper end - Add WorldGameRuleChangeEvent
         }
 
         public int get() {
             return this.value;
         }
 
-        public void set(int value, @Nullable MinecraftServer server) {
-            this.value = value;
-            this.onChanged(server);
+        public void set(int i, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
+            this.value = i;
+            this.onChanged(minecraftserver);
         }
 
         @Override
@@ -420,16 +470,17 @@
         }
 
         @Override
-        protected void deserialize(String value) {
-            this.value = safeParse(value);
+        public void deserialize(String value) { // PAIL - protected->public
+            this.value = IntegerValue.safeParse(value);
         }
 
         public boolean tryDeserialize(String input) {
             try {
-                StringReader stringReader = new StringReader(input);
-                this.value = (Integer)this.type.argument.get().parse(stringReader);
-                return !stringReader.canRead();
-            } catch (CommandSyntaxException var3) {
+                StringReader stringreader = new StringReader(input);
+
+                this.value = (Integer) ((ArgumentType) this.type.argument.get()).parse(stringreader);
+                return !stringreader.canRead();
+            } catch (CommandSyntaxException commandsyntaxexception) {
                 return false;
             }
         }
@@ -438,7 +489,7 @@
             if (!input.isEmpty()) {
                 try {
                     return Integer.parseInt(input);
-                } catch (NumberFormatException var2) {
+                } catch (NumberFormatException numberformatexception) {
                     GameRules.LOGGER.warn("Failed to parse integer {}", input);
                 }
             }
@@ -461,120 +512,14 @@
             return new GameRules.IntegerValue(this.type, this.value);
         }
 
-        @Override
-        public void setFrom(GameRules.IntegerValue rule, @Nullable MinecraftServer server) {
-            this.value = rule.value;
-            this.onChanged(server);
-        }
-    }
-
-    public static final class Key<T extends GameRules.Value<T>> {
-        final String id;
-        private final GameRules.Category category;
-
-        public Key(String name, GameRules.Category category) {
-            this.id = name;
-            this.category = category;
-        }
-
-        @Override
-        public String toString() {
-            return this.id;
-        }
-
-        @Override
-        public boolean equals(Object object) {
-            return this == object || object instanceof GameRules.Key && ((GameRules.Key)object).id.equals(this.id);
-        }
-
-        @Override
-        public int hashCode() {
-            return this.id.hashCode();
-        }
-
-        public String getId() {
-            return this.id;
-        }
-
-        public String getDescriptionId() {
-            return "gamerule." + this.id;
-        }
-
-        public GameRules.Category getCategory() {
-            return this.category;
-        }
-    }
-
-    public static class Type<T extends GameRules.Value<T>> {
-        final Supplier<ArgumentType<?>> argument;
-        private final Function<GameRules.Type<T>, T> constructor;
-        final BiConsumer<MinecraftServer, T> callback;
-        private final GameRules.VisitorCaller<T> visitorCaller;
-
-        Type(
-            Supplier<ArgumentType<?>> argumentType,
-            Function<GameRules.Type<T>, T> ruleFactory,
-            BiConsumer<MinecraftServer, T> changeCallback,
-            GameRules.VisitorCaller<T> ruleAcceptor
-        ) {
-            this.argument = argumentType;
-            this.constructor = ruleFactory;
-            this.callback = changeCallback;
-            this.visitorCaller = ruleAcceptor;
-        }
-
-        public RequiredArgumentBuilder<CommandSourceStack, ?> createArgument(String name) {
-            return Commands.argument(name, this.argument.get());
-        }
-
-        public T createRule() {
-            return this.constructor.apply(this);
-        }
-
-        public void callVisitor(GameRules.GameRuleTypeVisitor consumer, GameRules.Key<T> key) {
-            this.visitorCaller.call(consumer, key, this);
+        public void setFrom(GameRules.IntegerValue gamerules_gameruleint, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
+            this.value = gamerules_gameruleint.value;
+            this.onChanged(minecraftserver);
         }
     }
 
-    public abstract static class Value<T extends GameRules.Value<T>> {
-        protected final GameRules.Type<T> type;
-
-        public Value(GameRules.Type<T> type) {
-            this.type = type;
-        }
-
-        protected abstract void updateFromArgument(CommandContext<CommandSourceStack> context, String name);
-
-        public void setFromArgument(CommandContext<CommandSourceStack> context, String name) {
-            this.updateFromArgument(context, name);
-            this.onChanged(context.getSource().getServer());
-        }
-
-        public void onChanged(@Nullable MinecraftServer server) {
-            if (server != null) {
-                this.type.callback.accept(server, this.getSelf());
-            }
-        }
-
-        protected abstract void deserialize(String value);
-
-        public abstract String serialize();
-
-        @Override
-        public String toString() {
-            return this.serialize();
-        }
-
-        public abstract int getCommandResult();
-
-        protected abstract T getSelf();
-
-        protected abstract T copy();
-
-        public abstract void setFrom(T rule, @Nullable MinecraftServer server);
-    }
+    private interface VisitorCaller<T extends GameRules.Value<T>> {
 
-    interface VisitorCaller<T extends GameRules.Value<T>> {
         void call(GameRules.GameRuleTypeVisitor consumer, GameRules.Key<T> key, GameRules.Type<T> type);
     }
 }
