diff --git a/game/client/src/main/java/net/betterthanadventure/utils/BiomeFinder.java b/game/client/src/main/java/net/betterthanadventure/utils/BiomeFinder.java
index e43f9ee96..1f97baf51 100644
--- a/game/client/src/main/java/net/betterthanadventure/utils/BiomeFinder.java
+++ b/game/client/src/main/java/net/betterthanadventure/utils/BiomeFinder.java
@@ -500,7 +500,7 @@ public class BiomeFinder implements MinecraftAccessor {
 		} else {
 			SaveFormatBase saveFormat = new SaveFormat19134(worldFolder.getParentFile());
 			LevelStorage levelStorage = saveFormat.getLevelStorage(worldFolder.getName(), false);
-			world = new World(levelStorage, levelStorage.getLevelData().getWorldName(), levelStorage.getLevelData().getRandomSeed(), Dimension.OVERWORLD);
+			world = new World(levelStorage, Dimension.OVERWORLD);
 			biomeProvider = worldType.createBiomeProvider(world);
 		}
 		allBiomes.clear();
@@ -667,8 +667,8 @@ public class BiomeFinder implements MinecraftAccessor {
 	}
 
 	private static final class World extends net.minecraft.core.world.World {
-		public World(final @NotNull LevelStorage levelStorage, final @Nullable String name, final long seed, final @NotNull Dimension dimension) {
-			super(levelStorage, name, seed, dimension, null);
+		public World(final @NotNull LevelStorage levelStorage, final @NotNull Dimension dimension) {
+			super(levelStorage, null, dimension);
 		}
 
 		@Override
diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java
index 3813b09d7..f5ac77198 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -95,9 +95,6 @@ import net.minecraft.client.util.helper.Textures;
 import net.minecraft.client.util.helper.UrlHelper;
 import net.minecraft.client.world.WorldClient;
 import net.minecraft.client.world.WorldClientMP;
-import net.minecraft.client.world.chunk.provider.ChunkProviderDynamic;
-import net.minecraft.client.world.chunk.provider.ChunkProviderStatic;
-import net.minecraft.client.world.chunk.provider.ChunkProviderThreadedClient;
 import net.minecraft.client.world.save.LevelStorageClientSP;
 import net.minecraft.core.Global;
 import net.minecraft.core.MinecraftAccessor;
@@ -172,7 +169,6 @@ import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.util.pool.ObjectPool;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.PortalHandler;
-import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.provider.BiomeProviderOverworld;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
@@ -189,7 +185,6 @@ import net.minecraft.core.world.save.SaveFormatBase;
 import net.minecraft.core.world.save.SaveFormats;
 import net.minecraft.core.world.save.mcregion.SaveFormat19134;
 import net.minecraft.core.world.settings.WorldConfiguration;
-import net.minecraft.core.world.type.WorldType;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.joml.Matrix4f;
@@ -2039,21 +2034,18 @@ public class Minecraft
     public void createAndStartWorld(final @NotNull WorldConfiguration worldConfiguration) {
         final @NotNull LevelStorage levelStorage = this.saveFormat.getLevelStorage(worldConfiguration.getFolderName(this.saveFormat), false);
         for (final @NotNull Dimension dimension : Dimension.getDimensionList().values()) {
-            final @Nullable WorldType worldType = worldConfiguration.getWorldTypeGroup().get(dimension);
-            final @NotNull DimensionData data = new DimensionData(worldType);
+            final @NotNull DimensionData data = new DimensionData(dimension, worldConfiguration);
             levelStorage.saveDimensionData(dimension.id, data);
         }
 
         final @NotNull WorldClient world = new WorldClient(
             this,
             levelStorage,
-            worldConfiguration.getFinalWorldName(),
-            worldConfiguration.getFinalNumericSeed(),
-            Dimension.OVERWORLD,
-            worldConfiguration.getStartingBiome()
+            worldConfiguration,
+            Dimension.OVERWORLD
         );
         world.getLevelData().setCheatsEnabled(worldConfiguration.getCheatsEnabled());
-        world.getLevelData().getGameRules().setValues(worldConfiguration.getGameRuleCollection());
+        world.getLevelData().getGameRules().setValues(worldConfiguration.getGameRules());
         world.getSpawnerConfig().set(worldConfiguration.getSpawnerConfig());
 
         this.statsCounter.add(StatList.createWorldStat, 1);
@@ -2095,7 +2087,7 @@ public class Minecraft
                 dimension = Dimension.OVERWORLD;
             }
 
-            WorldClient world = new WorldClient(this, saveHandler, null, 0L, dimension, null);
+            WorldClient world = new WorldClient(this, saveHandler, null, dimension);
             this.statsCounter.add(StatList.loadWorldStat, 1);
             this.statsCounter.add(StatList.startGameStat, 1);
             changeWorld(world, i18n.translateKey("gui.loading.label.loading"));
diff --git a/game/client/src/main/java/net/minecraft/client/gui/paged/PageComponent.java b/game/client/src/main/java/net/minecraft/client/gui/paged/PageComponent.java
index 8301b293e..b44e73e66 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/paged/PageComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/paged/PageComponent.java
@@ -1,23 +1,26 @@
 package net.minecraft.client.gui.paged;
 
 import net.minecraft.client.Minecraft;
+import org.jetbrains.annotations.NotNull;
 
 public interface PageComponent {
-    default void init(Minecraft mc) { }
+    default void init(final @NotNull Minecraft mc) { }
 
     int getHeight();
 
-    void render(int x, int y, int width, int relativeMouseX, int relativeMouseY);
+    void render(@NotNull ScreenPaged screen, int x, int y, int width, int relativeMouseX, int relativeMouseY);
 
     default void tick() { }
 
-    void onMouseClick(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY);
+    boolean onMouseClick(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY);
 
-    void onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY);
+    boolean onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY);
 
-    void onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY);
+    boolean onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY);
 
     void onKeyPress(int keyCode, char character);
 
+    default void onClose() { }
+
     boolean matchesSearchTerm(String term);
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/paged/ScreenPaged.java b/game/client/src/main/java/net/minecraft/client/gui/paged/ScreenPaged.java
index f68d4b21a..84a2c8a2f 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/paged/ScreenPaged.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/paged/ScreenPaged.java
@@ -16,8 +16,7 @@ import org.jetbrains.annotations.Nullable;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 
-public class ScreenPaged
-    extends Screen {
+public class ScreenPaged extends Screen {
     protected static final int TOP_SPACING = 24;
     protected static final int BUTTON_SPACING = 4;
     protected static final int SEPARATOR_WIDTH = 8;
@@ -105,10 +104,18 @@ public class ScreenPaged
         }
     }
 
+    public int top() {
+        return this.top;
+    }
+
+    public int bottom() {
+        return this.bottom;
+    }
+
     private void drawPageItems(final int x, final int y, final int width, final int mouseX, final int mouseY) {
         int y2 = y;
         for (final @NotNull PageComponent component : this.selectedPage.getComponents()) {
-            component.render(x, y2, width, mouseX - x, mouseY - y2);
+            component.render(this, x, y2, width, mouseX - x, mouseY - y2);
             y2 += component.getHeight();
         }
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupBuilder.java b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupBuilder.java
index 946de0f74..9b03df285 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupBuilder.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupBuilder.java
@@ -28,7 +28,7 @@ public class PopupBuilder {
         this.width = width;
     }
 
-    public PopupScreen build() {
+    public @NotNull PopupScreen build() {
         final PopupScreen popup = new PopupScreen(
             this.parent,
             this.width,
diff --git a/game/client/src/main/java/net/minecraft/client/gui/server/ServerEntryComponent.java b/game/client/src/main/java/net/minecraft/client/gui/server/ServerEntryComponent.java
index d2ef59c6b..47dc33f90 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/server/ServerEntryComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/server/ServerEntryComponent.java
@@ -2,6 +2,7 @@ package net.minecraft.client.gui.server;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.paged.PageComponent;
+import net.minecraft.client.gui.paged.ScreenPaged;
 import net.minecraft.client.render.font.Alignment;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
@@ -27,7 +28,7 @@ public class ServerEntryComponent implements PageComponent {
     }
 
     @Override
-    public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
+    public void render(final @NotNull ScreenPaged screen, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
         TessellatorGeneral t = GLRenderer.getTessellator();
         if (this.entry.icon != null) {
             this.entry.icon.bind();
@@ -70,18 +71,19 @@ public class ServerEntryComponent implements PageComponent {
     }
 
     @Override
-    public void onMouseClick(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
+    public boolean onMouseClick(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
         this.attachedScreen.setSelectedEntry(this.entry);
+        return true;
     }
 
     @Override
-    public void onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
-
+    public boolean onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
+        return false;
     }
 
     @Override
-    public void onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
-
+    public boolean onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
+        return false;
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/server/SeverDirectConnectComponent.java b/game/client/src/main/java/net/minecraft/client/gui/server/SeverDirectConnectComponent.java
index e3134975e..d578b2d40 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/server/SeverDirectConnectComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/server/SeverDirectConnectComponent.java
@@ -3,6 +3,7 @@ package net.minecraft.client.gui.server;
 import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.client.gui.TextFieldElement;
 import net.minecraft.client.gui.paged.PageComponent;
+import net.minecraft.client.gui.paged.ScreenPaged;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.ServerAddress;
 import org.jetbrains.annotations.NotNull;
@@ -23,7 +24,7 @@ public class SeverDirectConnectComponent implements PageComponent {
     }
 
     @Override
-    public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
+    public void render(final @NotNull ScreenPaged screen, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
         int _x = x + width / 2 - this.ipField.width / 2;
         int _y = this.attachedScreen.height / 2 - 40;
 
@@ -45,21 +46,24 @@ public class SeverDirectConnectComponent implements PageComponent {
     }
 
     @Override
-    public void onMouseClick(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
+    public boolean onMouseClick(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
         this.ipField.mouseClicked(x + relativeMouseX, y + relativeMouseY, 0);
         if (this.connectButton.isHovered(x + relativeMouseX, y + relativeMouseY)) {
             connect();
+            return true;
         }
+
+        return false;
     }
 
     @Override
-    public void onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
-
+    public boolean onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
+        return false;
     }
 
     @Override
-    public void onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
-
+    public boolean onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
+        return false;
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ButtonComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ButtonComponent.java
index fd96114d7..9280c2c5a 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ButtonComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ButtonComponent.java
@@ -3,6 +3,7 @@ package net.minecraft.client.gui.worldsettings;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.client.gui.paged.PageComponent;
+import net.minecraft.client.gui.paged.ScreenPaged;
 import net.minecraft.client.render.renderer.BlendFactor;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.renderer.Shaders;
@@ -42,7 +43,7 @@ public abstract class ButtonComponent
     }
 
     @Override
-    public void render(final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+    public void render(final @NotNull ScreenPaged screen, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
         final @NotNull String translated = I18n.getInstance().translateKey(this.translationKey);
         int textColor = 0xFFFFFFFF;
         if (relativeMouseX >= 0 && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= this.getHeight() - COMPONENT_SPACING) {
@@ -59,24 +60,30 @@ public abstract class ButtonComponent
     }
 
     @Override
-    public void onMouseClick(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+    public boolean onMouseClick(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
         if (relativeMouseX >= width - BUTTON_WIDTH && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= COMPONENT_SPACING + 20) {
             mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
             this.buttonClicked(mouseButton, x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+            return true;
         } else if (this.resetButton.enabled && relativeMouseX >= width - BUTTON_WIDTH - 20 && relativeMouseX <= width - BUTTON_WIDTH && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= COMPONENT_SPACING + 20) {
             mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
             this.resetValue();
+            return true;
         }
+
+        return false;
     }
 
     @Override
-    public void onMouseMove(final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+    public boolean onMouseMove(final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
         this.buttonDragged(x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+        return true;
     }
 
     @Override
-    public void onMouseRelease(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+    public boolean onMouseRelease(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
         this.buttonReleased(mouseButton, x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+        return true;
     }
 
     protected abstract void buttonClicked(int mouseButton, int x, int y, int width, int height, int relativeMouseX, int relativeMouseY);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/CategoryMobSpawningComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/CategoryMobSpawningComponent.java
index b610bd657..a7c11b3c8 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/CategoryMobSpawningComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/CategoryMobSpawningComponent.java
@@ -33,7 +33,7 @@ public class CategoryMobSpawningComponent extends ButtonComponent {
     }
 
     @Override
-    public void init(Minecraft mc) {
+    public void init(@NotNull Minecraft mc) {
         onChange();
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/EntryMobSpawningComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/EntryMobSpawningComponent.java
index 4116250e8..895310b6a 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/EntryMobSpawningComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/EntryMobSpawningComponent.java
@@ -36,7 +36,7 @@ public class EntryMobSpawningComponent extends ButtonComponent{
     }
 
     @Override
-    public void init(Minecraft mc) {
+    public void init(@NotNull Minecraft mc) {
         onChange();
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/NodeComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/NodeComponent.java
new file mode 100644
index 000000000..84620aee4
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/NodeComponent.java
@@ -0,0 +1,17 @@
+package net.minecraft.client.gui.worldsettings;
+
+import net.minecraft.client.gui.paged.PageComponent;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.settings.SettingNode;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import org.jetbrains.annotations.NotNull;
+
+public interface NodeComponent extends PageComponent {
+    void onUpdate(final @NotNull Dimension dimension, final @NotNull WorldConfiguration worldConfiguration);
+
+    @NotNull SettingNode getNode();
+
+    int getNestLevel();
+
+    void reset();
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ScreenWorldSettings.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ScreenWorldSettings.java
index 3baacf81f..d138d87a7 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ScreenWorldSettings.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ScreenWorldSettings.java
@@ -1,27 +1,54 @@
 package net.minecraft.client.gui.worldsettings;
 
+import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
 import net.minecraft.client.gui.Screen;
 import net.minecraft.client.gui.paged.Page;
 import net.minecraft.client.gui.paged.PageComponent;
 import net.minecraft.client.gui.paged.PageRegistry;
 import net.minecraft.client.gui.paged.ScreenPaged;
+import net.minecraft.client.gui.worldsettings.gamerule.BooleanGameRuleComponent;
+import net.minecraft.client.gui.worldsettings.settingnode.CategoryComponent;
+import net.minecraft.client.gui.worldsettings.settingnode.NestedNodeComponent;
 import net.minecraft.core.data.gamerule.GameRule;
 import net.minecraft.core.data.gamerule.GameRuleBoolean;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.entity.EntityDispatcher;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.item.Items;
+import net.minecraft.core.lang.text.TranslatableText;
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.settings.WorldConfiguration;
+import net.minecraft.core.world.settings.WorldSettingNodes;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
-public class ScreenWorldSettings
-    extends ScreenPaged {
-    public static final @NotNull PageRegistry CREATE_WORLD_PAGES = new PageRegistry();
-    public static final @NotNull Page PAGE_GAME_RULES = CREATE_WORLD_PAGES.register(new Page("gui.world_settings.page.game_rules.title", Items.PAPER.getDefaultStack()));
+public class ScreenWorldSettings extends ScreenPaged implements WorldConfiguration.ChangeListener {
+    public static final @NotNull PageRegistry WORLD_SETTINGS_PAGES = new PageRegistry();
+    private static final @NotNull Map<@NotNull Dimension, @NotNull NodeComponent> WORLD_SETTINGS_ROOT_COMPONENTS = new Object2ObjectArrayMap<>();
+    static {
+        for (final @NotNull Dimension dimension : Dimension.getDimensionList().values()) {
+            WORLD_SETTINGS_ROOT_COMPONENTS.put(dimension, new NestedNodeComponent(WorldSettingNodes.getRootNode(), 0));
+        }
+    }
+
+    public static final @NotNull Page PAGE_WORLD_SETTINGS = WORLD_SETTINGS_PAGES.register(
+        new Page("gui.world_settings.page.world_settings.title", Items.PAINTBRUSH.getDefaultStack())
+            .withComponent(new WorldTypeButtonComponent("gui.world_settings.label.world_type", null))
+            .withComponent(
+                new CategoryComponent(new TranslatableText("gui.world_settings.page.world_settings.category.overworld"))
+                    .withComponent(WORLD_SETTINGS_ROOT_COMPONENTS.get(Dimension.OVERWORLD))
+            )
+            .withComponent(
+                new CategoryComponent(new TranslatableText("gui.world_settings.page.world_settings.category.nether"))
+                    .withComponent(WORLD_SETTINGS_ROOT_COMPONENTS.get(Dimension.NETHER))
+            )
+    );
 
+    public static final @NotNull Page PAGE_GAME_RULES = WORLD_SETTINGS_PAGES.register(new Page("gui.world_settings.page.game_rules.title", Items.PAPER.getDefaultStack()));
     static {
         for (final @NotNull GameRule<?> gameRule : Registries.GAME_RULES) {
             if (gameRule instanceof GameRuleBoolean) {
@@ -30,17 +57,11 @@ public class ScreenWorldSettings
         }
     }
 
-    public static final @NotNull Page PAGE_WORLD_SETTINGS = CREATE_WORLD_PAGES.register(
-        new Page("gui.world_settings.page.world_settings.title", Items.PAINTBRUSH.getDefaultStack())
-            .withComponent(new WorldTypeButtonComponent("gui.world_settings.label.world_type", null))
-            .withComponent(new StartingBiomeButtonComponent("gui.world_settings.label.starting_biome", null))
-    );
-    public static final @NotNull Page PAGE_MOB_SPAWNING = CREATE_WORLD_PAGES.register(
+    public static final @NotNull Page PAGE_MOB_SPAWNING = WORLD_SETTINGS_PAGES.register(
         new Page("gui.world_settings.page.mob_spawning.title", Items.EGG_CHICKEN.getDefaultStack())
             .withComponent(new CategoryMobSpawningComponent(CategoryMobSpawningComponent.Type.HOSTILE))
             .withComponent(new CategoryMobSpawningComponent(CategoryMobSpawningComponent.Type.PASSIVE))
     );
-
     static {
         for (var entry : EntityDispatcher.getInstance().entries) {
             if (Mob.class.isAssignableFrom(entry.entityClass) && entry.nameKey != null) { // Probably have something better than checking if name key is null
@@ -52,23 +73,25 @@ public class ScreenWorldSettings
     private final @NotNull WorldConfiguration worldConfiguration;
 
     public ScreenWorldSettings(final @Nullable Screen parent, final @NotNull WorldConfiguration worldConfiguration) {
-        super(parent, CREATE_WORLD_PAGES, PAGE_GAME_RULES, "gui.world_settings.label.title", new String[]{"gui.world_settings.button.done"});
+        super(parent, WORLD_SETTINGS_PAGES, PAGE_WORLD_SETTINGS, "gui.world_settings.label.title", new String[]{"gui.world_settings.button.done"});
 
         this.worldConfiguration = worldConfiguration;
-
-        final List<PageComponent> gameRulesPageComponents = PAGE_GAME_RULES.getComponents();
-        for (final @NotNull PageComponent component : gameRulesPageComponents) {
-            if (component instanceof BooleanGameRuleComponent ruleComponent) {
-                ruleComponent.setGameRuleCollection(worldConfiguration.getGameRuleCollection());
-            }
+        this.worldConfiguration.setChangeListener(this);
+        for (final @NotNull Dimension dimension : WORLD_SETTINGS_ROOT_COMPONENTS.keySet()) {
+            Objects.requireNonNull(WORLD_SETTINGS_ROOT_COMPONENTS.get(dimension)).onUpdate(dimension, worldConfiguration);
         }
 
         final List<PageComponent> worldSettingsPageComponents = PAGE_WORLD_SETTINGS.getComponents();
         for (final @NotNull PageComponent component : worldSettingsPageComponents) {
             if (component instanceof WorldTypeButtonComponent typeButtonComponent) {
                 typeButtonComponent.setWorldConfiguration(worldConfiguration);
-            } else if (component instanceof StartingBiomeButtonComponent startingBiomeButtonComponent) {
-                startingBiomeButtonComponent.setWorldConfiguration(worldConfiguration);
+            }
+        }
+
+        final List<PageComponent> gameRulesPageComponents = PAGE_GAME_RULES.getComponents();
+        for (final @NotNull PageComponent component : gameRulesPageComponents) {
+            if (component instanceof BooleanGameRuleComponent ruleComponent) {
+                ruleComponent.setGameRuleCollection(worldConfiguration.getGameRules());
             }
         }
 
@@ -81,4 +104,11 @@ public class ScreenWorldSettings
             }
         }
     }
+
+    @Override
+    public void onChanged() {
+        for (final @NotNull Dimension dimension : WORLD_SETTINGS_ROOT_COMPONENTS.keySet()) {
+            Objects.requireNonNull(WORLD_SETTINGS_ROOT_COMPONENTS.get(dimension)).onUpdate(dimension, worldConfiguration);
+        }
+    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/StartingBiomeButtonComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/StartingBiomeButtonComponent.java
deleted file mode 100644
index fe9c119b5..000000000
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/StartingBiomeButtonComponent.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package net.minecraft.client.gui.worldsettings;
-
-import net.minecraft.client.gui.ButtonElement;
-import net.minecraft.client.gui.popup.PopupBuilder;
-import net.minecraft.client.gui.popup.PopupScreen;
-import net.minecraft.client.render.window.CursorShape;
-import net.minecraft.core.lang.I18n;
-import net.minecraft.core.world.Dimension;
-import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.settings.WorldConfiguration;
-import net.minecraft.core.world.type.WorldTypeGroups;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Objects;
-
-public class StartingBiomeButtonComponent
-    extends ButtonComponent {
-    private @Nullable WorldConfiguration worldConfiguration = null;
-    private final @NotNull ButtonElement button;
-    private @Nullable WorldTypeGroups.Group lastGroup = null;
-
-    public StartingBiomeButtonComponent(final @NotNull String translationKey, final @Nullable String tooltipTranslationKey) {
-        super(translationKey, tooltipTranslationKey);
-
-        this.button = new ButtonElement(0, 0, 0, 150, 20, "");
-    }
-
-    public void setWorldConfiguration(final @NotNull WorldConfiguration worldConfiguration) {
-        this.worldConfiguration = worldConfiguration;
-        Biome biome = this.worldConfiguration.getStartingBiome();
-        this.button.displayString = I18n.getInstance().translateKey(biome == null ? "gui.world_settings.page.starting_biome.biome.none" : biome.translationKey);
-    }
-
-    @Override
-    public void resetValue() {
-        Objects.requireNonNull(this.worldConfiguration).setStartingBiome(null);
-        Biome biome = this.worldConfiguration.getStartingBiome();
-        this.button.displayString = I18n.getInstance().translateKey(biome == null ? "gui.world_settings.page.starting_biome.biome.none" : biome.translationKey);
-    }
-
-    @Override
-    public boolean isDefault() {
-        return Objects.requireNonNull(this.worldConfiguration).getStartingBiome() == null;
-    }
-
-    @Override
-    protected void buttonClicked(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
-        final I18n i18n = I18n.getInstance();
-
-        Biome[] biomes = this.worldConfiguration.getWorldTypeGroup().get(Dimension.OVERWORLD).allBiomes();
-
-        final @NotNull String @NotNull [] keys = new String[biomes.length + 1];
-        for (int i = 0; i < keys.length; i++) {
-            int selected = i - 1;
-
-            Biome biome;
-            if (selected >= 0) {
-                biome = biomes[selected];
-            } else {
-                biome = null;
-            }
-
-            keys[i] = i18n.translateKey(biome == null ? "gui.world_settings.page.starting_biome.biome.none" : biome.translationKey);
-        }
-
-        int b = 0;
-        if (this.worldConfiguration.getStartingBiome() == null) {
-            b = 0;
-        } else {
-            for (int i = 0; i < biomes.length; i++) {
-                if (biomes[i] == this.worldConfiguration.getStartingBiome()) {
-                    b = i + 1;
-                    break;
-                }
-            }
-        }
-
-        final PopupScreen popup = new PopupBuilder(Objects.requireNonNull(mc.currentScreen), 150)
-            .closeOnEsc(0)
-            .closeOnClickOut(0)
-            .withLabel("gui.world_settings.label.starting_biome")
-            .withList("biomeList", 140, keys, null, b, true)
-            .withOnCloseListener((statusCode, results) -> {
-                if (statusCode == 1) {
-                    int selected = (Integer) results.get("biomeList") - 1;
-                    Biome biome;
-                    if (selected >= 0) {
-                        biome = biomes[selected];
-                    } else {
-                        biome = null;
-                    }
-                    this.worldConfiguration.setStartingBiome(biome);
-                    this.button.displayString = I18n.getInstance().translateKey(biome == null ? "gui.world_settings.page.starting_biome.biome.none" : biome.translationKey);
-                }
-            })
-            .build();
-        mc.displayScreen(popup);
-    }
-
-    @Override
-    protected void renderButton(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY) {
-        if (worldConfiguration.getWorldTypeGroup() != lastGroup) {
-            lastGroup = worldConfiguration.getWorldTypeGroup();
-            resetValue();
-        }
-
-        super.renderButton(x, y, relativeButtonX, relativeButtonY, buttonWidth, buttonHeight, relativeMouseX, relativeMouseY);
-
-        this.button.xPosition = x + relativeButtonX;
-        this.button.yPosition = y + relativeButtonY;
-        this.button.width = buttonWidth;
-        this.button.height = buttonHeight;
-
-        this.button.drawButton(mc, x + relativeMouseX, y + relativeMouseY);
-
-        if (mc.currentScreen != null && relativeMouseX >= relativeButtonX && relativeMouseX < relativeButtonX + buttonWidth && relativeMouseY >= relativeButtonY && relativeButtonY < relativeButtonY + buttonHeight) {
-            mc.currentScreen.setDesiredCursor(CursorShape.HAND);
-        }
-    }
-}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/BooleanGameRuleComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/gamerule/BooleanGameRuleComponent.java
similarity index 96%
rename from game/client/src/main/java/net/minecraft/client/gui/worldsettings/BooleanGameRuleComponent.java
rename to game/client/src/main/java/net/minecraft/client/gui/worldsettings/gamerule/BooleanGameRuleComponent.java
index fcb5c878b..bd9a18a4d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/BooleanGameRuleComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/gamerule/BooleanGameRuleComponent.java
@@ -1,7 +1,8 @@
-package net.minecraft.client.gui.worldsettings;
+package net.minecraft.client.gui.worldsettings.gamerule;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.SwitchElement;
+import net.minecraft.client.gui.worldsettings.ButtonComponent;
 import net.minecraft.client.render.window.CursorShape;
 import net.minecraft.core.data.gamerule.GameRuleBoolean;
 import net.minecraft.core.data.gamerule.GameRuleCollection;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/IntegerGameRuleComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/gamerule/IntegerGameRuleComponent.java
similarity index 94%
rename from game/client/src/main/java/net/minecraft/client/gui/worldsettings/IntegerGameRuleComponent.java
rename to game/client/src/main/java/net/minecraft/client/gui/worldsettings/gamerule/IntegerGameRuleComponent.java
index 153aae41b..6cbb3a6bc 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/IntegerGameRuleComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/gamerule/IntegerGameRuleComponent.java
@@ -1,7 +1,8 @@
-package net.minecraft.client.gui.worldsettings;
+package net.minecraft.client.gui.worldsettings.gamerule;
 
 import net.minecraft.client.gui.SwitchElement;
 import net.minecraft.client.gui.TextFieldElement;
+import net.minecraft.client.gui.worldsettings.ButtonComponent;
 import net.minecraft.core.data.gamerule.GameRuleBoolean;
 import net.minecraft.core.data.gamerule.GameRuleCollection;
 import net.minecraft.core.data.gamerule.GameRuleInteger;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/BooleanValueNodeComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/BooleanValueNodeComponent.java
new file mode 100644
index 000000000..e7583d960
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/BooleanValueNodeComponent.java
@@ -0,0 +1,57 @@
+package net.minecraft.client.gui.worldsettings.settingnode;
+
+import net.minecraft.client.gui.SwitchElement;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.settings.ValueSettingNode;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class BooleanValueNodeComponent extends ValueNodeComponent<@NotNull Boolean> {
+    private final @NotNull SwitchElement button;
+
+    public BooleanValueNodeComponent(final @NotNull ValueSettingNode<@NotNull Boolean> valueNode, final int nestLevel) {
+        super(valueNode, nestLevel);
+
+        this.button = new SwitchElement(0, 0, 0, 150, 20, false, "", "");
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        this.onChange();
+    }
+
+    @Override
+    public void onUpdate(final @NotNull Dimension dimension, final @NotNull WorldConfiguration worldConfiguration) {
+        super.onUpdate(dimension, worldConfiguration);
+        this.onChange();
+    }
+
+    @Override
+    protected boolean buttonClicked(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+        final @Nullable Dimension dimension = this.getDimension();
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        assert dimension != null && worldConfiguration != null;
+
+        worldConfiguration.getDimensionSettings(dimension).setNodeValue(this.getNode(), !worldConfiguration.getDimensionSettings(dimension).getNodeValue(this.getNode(), worldConfiguration));
+        this.onChange();
+
+        return true;
+    }
+
+    @Override
+    protected void renderButtonInner(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY) {
+        this.button.xPosition = x + relativeButtonX;
+        this.button.yPosition = y + relativeButtonY;
+        this.button.width = buttonWidth;
+        this.button.height = buttonHeight;
+
+        this.button.drawButton(MC, x + relativeMouseX, y + relativeMouseY);
+    }
+
+    private void onChange() {
+        this.button.setOn(this.getValue());
+        this.button.displayString = this.getNode().getValueText(this.getValue()).toString();
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/CategoryComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/CategoryComponent.java
new file mode 100644
index 000000000..a943ca170
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/CategoryComponent.java
@@ -0,0 +1,139 @@
+package net.minecraft.client.gui.worldsettings.settingnode;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ItemElement;
+import net.minecraft.client.gui.options.components.OptionsComponent;
+import net.minecraft.client.gui.paged.PageComponent;
+import net.minecraft.client.gui.paged.ScreenPaged;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.sound.SoundCategory;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CategoryComponent implements PageComponent {
+    private static final Minecraft MC = Minecraft.getMinecraft();
+    private static final ItemElement RENDER_ITEM = new ItemElement(MC);
+    private static final int PADDING = 2;
+    private static final int TOP_SPACING = PADDING + 10 + 10 + PADDING;
+    private static final int COMPONENT_LEFT_MARGIN = 16;
+
+    private final @NotNull Text label;
+    private final @Nullable ItemStack icon;
+    private final @NotNull List<@NotNull PageComponent> components = new ArrayList<>();
+
+    private @Nullable PageComponent clickedComponent = null;
+    private int clickedComponentY = 0;
+
+    private boolean collapsed = false;
+
+    public CategoryComponent(final @NotNull Text label, final @Nullable ItemStack icon) {
+        this.label = label;
+        this.icon = icon;
+    }
+
+    public CategoryComponent(final @NotNull Text label) {
+        this(label, null);
+    }
+
+    public @NotNull CategoryComponent withComponent(final @NotNull PageComponent component) {
+        this.components.add(component);
+
+        return this;
+    }
+
+    @Override
+    public void tick() {
+        for (final @NotNull PageComponent component : this.components) {
+            component.tick();
+        }
+    }
+
+    @Override
+    public int getHeight() {
+        int height = TOP_SPACING;
+        if (!this.collapsed) {
+            for (final @NotNull PageComponent component : this.components) {
+                height += component.getHeight();
+            }
+        }
+        return height;
+    }
+
+    @Override
+    public void render(final @NotNull ScreenPaged screen, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        final int textColor = 0x7F7F7F;
+        MC.font.render((this.collapsed ? "▷" : "▽"), x, y + PADDING + 10).setShadow().setColor(textColor).call();
+
+        int xOffset = 10;
+        if (this.icon != null) {
+            RENDER_ITEM.render(this.icon, x + 11, y + PADDING + 5);
+            xOffset += 20;
+        }
+        MC.font.render(this.label.toString(), x + xOffset, y + PADDING + 10).setShadow().setColor(textColor).call();
+        if (!this.collapsed) {
+            int componentY = TOP_SPACING;
+            for (final @NotNull PageComponent component : this.components) {
+                if (y + componentY + component.getHeight() >= screen.top() && y + componentY <= screen.bottom()) {
+                    component.render(screen, x + COMPONENT_LEFT_MARGIN, y + componentY, width - COMPONENT_LEFT_MARGIN, relativeMouseX - COMPONENT_LEFT_MARGIN, relativeMouseY - componentY);
+                }
+                componentY += component.getHeight();
+            }
+        }
+    }
+
+    @Override
+    public boolean onMouseClick(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        if (relativeMouseX >= 0 && relativeMouseX < width && relativeMouseY >= 0 && relativeMouseY < TOP_SPACING) {
+            this.collapsed = !this.collapsed;
+            MC.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+        }
+
+        int componentY = TOP_SPACING;
+        for (final @NotNull PageComponent component : this.components) {
+            if (relativeMouseX >= COMPONENT_LEFT_MARGIN && relativeMouseX < width && relativeMouseY >= componentY && relativeMouseY < componentY + component.getHeight()) {
+                component.onMouseClick(mouseButton, x + COMPONENT_LEFT_MARGIN, componentY, width - COMPONENT_LEFT_MARGIN, relativeMouseX - COMPONENT_LEFT_MARGIN, relativeMouseY - componentY);
+                this.clickedComponent = component;
+                this.clickedComponentY = componentY;
+                return true;
+            }
+            componentY += component.getHeight();
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean onMouseMove(final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        if (this.clickedComponent != null) {
+            return this.clickedComponent.onMouseMove(x + COMPONENT_LEFT_MARGIN, this.clickedComponentY, width - COMPONENT_LEFT_MARGIN, relativeMouseX - COMPONENT_LEFT_MARGIN, relativeMouseY - this.clickedComponentY);
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean onMouseRelease(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        if (this.clickedComponent != null) {
+            return this.clickedComponent.onMouseRelease(mouseButton, x + COMPONENT_LEFT_MARGIN, this.clickedComponentY, width - COMPONENT_LEFT_MARGIN, relativeMouseX - COMPONENT_LEFT_MARGIN, relativeMouseY - this.clickedComponentY);
+        }
+
+        return false;
+    }
+
+    @Override
+    public void onKeyPress(final int keyCode, final char character) {
+        for (final @NotNull PageComponent component : this.components) {
+            component.onKeyPress(keyCode, character);
+        }
+    }
+
+    @Override
+    public boolean matchesSearchTerm(final String term) {
+        return false;
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/ListValueNodeComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/ListValueNodeComponent.java
new file mode 100644
index 000000000..ff79936b2
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/ListValueNodeComponent.java
@@ -0,0 +1,85 @@
+package net.minecraft.client.gui.worldsettings.settingnode;
+
+import net.minecraft.client.gui.ButtonElement;
+import net.minecraft.client.gui.popup.PopupBuilder;
+import net.minecraft.client.gui.popup.PopupScreen;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.settings.ListValueSettingNode;
+import net.minecraft.core.world.settings.ValueSettingNode;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Objects;
+
+public class ListValueNodeComponent<T> extends ValueNodeComponent<T> {
+    private final @NotNull ButtonElement button;
+
+    public ListValueNodeComponent(final @NotNull ListValueSettingNode<T> valueNode, final int nestLevel) {
+        super(valueNode, nestLevel);
+
+        this.button = new ButtonElement(0, 0, 0, 150, 20, "");
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        this.button.displayString = this.getNode().getValueText(this.getValue()).toString();
+    }
+
+    @Override
+    public void onUpdate(final @NotNull Dimension dimension, final @NotNull WorldConfiguration worldConfiguration) {
+        super.onUpdate(dimension, worldConfiguration);
+        this.button.displayString = this.getNode().getValueText(this.getValue()).toString();
+    }
+
+    @Override
+    protected boolean buttonClicked(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+        final @NotNull ListValueSettingNode<T> node = (ListValueSettingNode<T>) this.getNode();
+        final @Nullable Dimension dimension = this.getDimension();
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        assert dimension != null && worldConfiguration != null;
+
+        final @NotNull T currentValue = this.getValue();
+
+        int selected = 0;
+        final @NotNull List<@NotNull T> values = node.getValues(dimension, worldConfiguration);
+        final @NotNull String @NotNull [] keys = new String[values.size()];
+        for (int i = 0; i < keys.length; i++) {
+            final @NotNull T value = values.get(i);
+            final @NotNull Text valueText = node.getValueText(value);
+            keys[i] = valueText.toString();
+
+            if (value == currentValue || value.equals(currentValue) || currentValue.equals(value)) {
+                selected = i;
+            }
+        }
+
+        final @NotNull PopupScreen popup = new PopupBuilder(Objects.requireNonNull(MC.currentScreen), 150)
+            .closeOnEsc(0)
+            .closeOnClickOut(0)
+            .withList("settingList", 140, keys, null, selected, true)
+            .withOnCloseListener((statusCode, results) -> {
+                if (statusCode == 1) {
+                    final int index = (Integer) Objects.requireNonNull(results.get("settingList"));
+                    this.getWorldConfiguration().getDimensionSettings(Objects.requireNonNull(this.getDimension())).setNodeValue(node, values.get(index));
+                }
+            })
+            .build();
+        MC.displayScreen(popup);
+
+        return true;
+    }
+
+    @Override
+    protected void renderButtonInner(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY) {
+        this.button.xPosition = x + relativeButtonX;
+        this.button.yPosition = y + relativeButtonY;
+        this.button.width = buttonWidth;
+        this.button.height = buttonHeight;
+
+        this.button.drawButton(MC, x + relativeMouseX, y + relativeMouseY);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/NestedNodeComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/NestedNodeComponent.java
new file mode 100644
index 000000000..b433c459c
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/NestedNodeComponent.java
@@ -0,0 +1,205 @@
+package net.minecraft.client.gui.worldsettings.settingnode;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.paged.ScreenPaged;
+import net.minecraft.client.gui.worldsettings.NodeComponent;
+import net.minecraft.client.gui.worldsettings.settingnode.conversion.NodeAdapterRegistry;
+import net.minecraft.client.render.renderer.BlendFactor;
+import net.minecraft.client.render.renderer.GLRenderer;
+import net.minecraft.client.render.renderer.Shaders;
+import net.minecraft.client.render.renderer.State;
+import net.minecraft.client.render.tessellator.TessellatorGeneral;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.settings.SettingNode;
+import net.minecraft.core.world.settings.SettingNodeChildrenProvider;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NestedNodeComponent implements NodeComponent {
+    protected static final @NotNull Minecraft MC = Minecraft.getMinecraft();
+    protected static final int COMPONENT_SPACING = 2;
+    private static final int NEST_LEFT_MARGIN = 16;
+
+    private final int nestLevel;
+    private final @NotNull SettingNode node;
+    private final @NotNull List<@NotNull NodeComponent> components = new ArrayList<>();
+
+    private @Nullable Dimension dimension = null;
+    private @Nullable WorldConfiguration worldConfiguration = null;
+    private @Nullable NodeComponent clickedComponent = null;
+    private int clickedComponentY = 0;
+
+    public NestedNodeComponent(final @NotNull SettingNode node, final int nestLevel) {
+        this.node = node;
+        this.nestLevel = nestLevel;
+    }
+
+    protected @Nullable Dimension getDimension() {
+        return this.dimension;
+    }
+
+    protected @Nullable WorldConfiguration getWorldConfiguration() {
+        return this.worldConfiguration;
+    }
+
+    @Override
+    public void reset() {
+        for (final @NotNull NodeComponent component : this.components) {
+            component.reset();
+        }
+    }
+
+    @Override
+    public int getNestLevel() {
+        return this.nestLevel;
+    }
+
+    @Override
+    public void onUpdate(final @NotNull Dimension dimension, final @NotNull WorldConfiguration worldConfiguration) {
+        this.dimension = dimension;
+        this.worldConfiguration = worldConfiguration;
+
+        this.components.clear();
+        final @Nullable SettingNodeChildrenProvider childrenProvider = this.node.getChildrenProvider();
+        if (childrenProvider != null && this.getNode().areChildrenVisible(this.dimension, this.worldConfiguration)) {
+            for (final @NotNull SettingNode child : childrenProvider) {
+                if (child.isVisible(dimension, worldConfiguration)) {
+                    final @NotNull NodeComponent childComponent = NodeAdapterRegistry.adapt(child, this.nestLevel + this.getNestLevelContribution());
+                    childComponent.onUpdate(dimension, worldConfiguration);
+                    this.components.add(childComponent);
+                }
+            }
+        }
+    }
+
+    @Override
+    public @NotNull SettingNode getNode() {
+        return this.node;
+    }
+
+    public int getNestLevelContribution() {
+        return 0;
+    }
+
+    public int getBaseHeight() {
+        return COMPONENT_SPACING;
+    }
+
+    @Override
+    public void tick() {
+        for (final @NotNull NodeComponent child : this.components) {
+            child.tick();
+        }
+    }
+
+    @Override
+    public int getHeight() {
+        int height = this.getBaseHeight();
+        for (final @NotNull NodeComponent component : this.components) {
+            height += component.getHeight();
+        }
+
+        return height;
+    }
+
+    @Override
+    public void render(final @NotNull ScreenPaged screen, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        final int childrenHeight = this.getHeight() - this.getBaseHeight();
+        if (childrenHeight > 0) {
+            int alpha = 0x80 * (this.nestLevel + this.getNestLevelContribution());
+            if (alpha > 0xFF) {
+                alpha = 0xFF;
+            }
+
+            if (alpha > 0) {
+                alpha = alpha << 24;
+                this.drawRect(x - (NEST_LEFT_MARGIN * (this.nestLevel + this.getNestLevelContribution())), y + this.getBaseHeight(), x + width + 16, y + this.getBaseHeight() + childrenHeight, alpha);
+            }
+        }
+
+        int componentY = this.getBaseHeight();
+        for (final @NotNull NodeComponent component : this.components) {
+            if (y + componentY + component.getHeight() >= screen.top() && y + componentY <= screen.bottom()) {
+                component.render(screen, x + NEST_LEFT_MARGIN * component.getNestLevel(), y + componentY, width - NEST_LEFT_MARGIN * component.getNestLevel(), relativeMouseX - NEST_LEFT_MARGIN * component.getNestLevel(), relativeMouseY - componentY);
+            }
+            componentY += component.getHeight();
+        }
+    }
+
+    @Override
+    public boolean onMouseClick(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        int componentY = this.getBaseHeight();
+        for (final @NotNull NodeComponent component : this.components) {
+            if (relativeMouseX >= NEST_LEFT_MARGIN * component.getNestLevel() && relativeMouseX < width && relativeMouseY >= componentY && relativeMouseY < componentY + component.getHeight()) {
+                component.onMouseClick(mouseButton, x + NEST_LEFT_MARGIN * component.getNestLevel(), componentY, width - NEST_LEFT_MARGIN * component.getNestLevel(), relativeMouseX - NEST_LEFT_MARGIN * component.getNestLevel(), relativeMouseY - componentY);
+                this.clickedComponent = component;
+                this.clickedComponentY = componentY;
+                return true;
+            }
+            componentY += component.getHeight();
+        }
+
+        this.clickedComponent = null;
+        return false;
+    }
+
+    @Override
+    public boolean onMouseMove(final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        if (this.clickedComponent != null) {
+            this.clickedComponent.onMouseMove(x + NEST_LEFT_MARGIN * this.clickedComponent.getNestLevel(), this.clickedComponentY, width - NEST_LEFT_MARGIN * this.clickedComponent.getNestLevel(), relativeMouseX - NEST_LEFT_MARGIN * this.clickedComponent.getNestLevel(), relativeMouseY - this.clickedComponentY);
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean onMouseRelease(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        if (this.clickedComponent != null) {
+            this.clickedComponent.onMouseRelease(mouseButton, x + NEST_LEFT_MARGIN * this.clickedComponent.getNestLevel(), this.clickedComponentY, width - NEST_LEFT_MARGIN * this.clickedComponent.getNestLevel(), relativeMouseX - NEST_LEFT_MARGIN * this.clickedComponent.getNestLevel(), relativeMouseY - this.clickedComponentY);
+            this.clickedComponent = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void onKeyPress(final int keyCode, final char character) {
+        for (final @NotNull NodeComponent component : this.components) {
+            component.onKeyPress(keyCode, character);
+        }
+    }
+
+    @Override
+    public void onClose() {
+        for (final @NotNull NodeComponent component : this.components) {
+            component.onClose();
+        }
+    }
+
+    @Override
+    public boolean matchesSearchTerm(final String term) {
+        return false;
+    }
+
+    protected void drawRect(final int minX, final int minY, final int maxX, final int maxY, final int argb) {
+        GLRenderer.pushFrame();
+        GLRenderer.setShader(Shaders.COLOR);
+        GLRenderer.enableState(State.BLEND);
+        GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA);
+        final TessellatorGeneral tessellator = GLRenderer.getTessellator();
+        tessellator.startDrawingQuads();
+        tessellator.setColor2i(argb & 0x00FFFFFF, argb >> 24 & 0xff);
+        tessellator.addVertex(minX, maxY, 0.0D);
+        tessellator.addVertex(maxX, maxY, 0.0D);
+        tessellator.addVertex(maxX, minY, 0.0D);
+        tessellator.addVertex(minX, minY, 0.0D);
+        tessellator.draw();
+        GLRenderer.popFrame();
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/RangeIntegerNodeComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/RangeIntegerNodeComponent.java
new file mode 100644
index 000000000..14fe22bc3
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/RangeIntegerNodeComponent.java
@@ -0,0 +1,220 @@
+package net.minecraft.client.gui.worldsettings.settingnode;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ButtonElement;
+import net.minecraft.client.render.renderer.GLRenderer;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.client.render.window.CursorShape;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import net.minecraft.core.world.settings.impl.RangeIntegerSettingNode;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class RangeIntegerNodeComponent extends ValueNodeComponent<@NotNull Integer> {
+    private final @NotNull IntegerSliderElement slider;
+    private final boolean applyOnRelease = true;
+
+    public RangeIntegerNodeComponent(final @NotNull RangeIntegerSettingNode valueNode, final int nestLevel) {
+        super(valueNode, nestLevel);
+
+        this.slider = new IntegerSliderElement(0, 0, 0, 150, 20);
+    }
+
+    @Override
+    public @NotNull RangeIntegerSettingNode getNode() {
+        return (RangeIntegerSettingNode) super.getNode();
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        this.onChange();
+    }
+
+    @Override
+    public void onUpdate(final @NotNull Dimension dimension, final @NotNull WorldConfiguration worldConfiguration) {
+        super.onUpdate(dimension, worldConfiguration);
+        this.onChange();
+    }
+
+    @Override
+    protected boolean buttonClicked(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+        final @Nullable Dimension dimension = this.getDimension();
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        assert dimension != null && worldConfiguration != null;
+
+        this.slider.mouseClicked(MC, this.slider.xPosition + relativeMouseX, this.slider.yPosition + relativeMouseY);
+        if (!this.applyOnRelease) {
+            worldConfiguration.getDimensionSettings(dimension).setNodeValue(this.getNode(), this.slider.sliderValue);
+            this.onChange();
+        } else {
+            this.updateText();
+        }
+
+        return true;
+    }
+
+    @Override
+    protected void buttonDragged(final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+        final @Nullable Dimension dimension = this.getDimension();
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        assert dimension != null && worldConfiguration != null;
+
+        if (!this.applyOnRelease) {
+            worldConfiguration.getDimensionSettings(dimension).setNodeValue(this.getNode(), this.slider.sliderValue);
+            this.onChange();
+        } else {
+            this.updateText();
+        }
+    }
+
+    @Override
+    protected void buttonReleased(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+        final @Nullable Dimension dimension = this.getDimension();
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        assert dimension != null && worldConfiguration != null;
+
+        this.slider.mouseReleased(this.slider.xPosition + relativeMouseX, this.slider.yPosition + relativeMouseY);
+        worldConfiguration.getDimensionSettings(dimension).setNodeValue(this.getNode(), this.slider.sliderValue);
+        this.onChange();
+    }
+
+    @Override
+    protected void renderButtonInner(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY) {
+        this.slider.xPosition = x + relativeButtonX;
+        this.slider.yPosition = y + relativeButtonY;
+        this.slider.width = buttonWidth;
+        this.slider.height = buttonHeight;
+
+        this.slider.drawButton(MC, x + relativeMouseX, y + relativeMouseY);
+    }
+
+    private void updateText() {
+        this.slider.displayString = this.getNode().getValueText(this.slider.sliderValue).toString();
+    }
+
+    private void onChange() {
+        final @Nullable Dimension dimension = this.getDimension();
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        assert dimension != null && worldConfiguration != null;
+
+        this.slider.sliderValue = this.getValue();
+        this.slider.min = this.getNode().getMinimumValue(dimension, worldConfiguration);
+        this.slider.max = this.getNode().getMaximumValue(dimension, worldConfiguration);
+        this.updateText();
+    }
+
+    private static class IntegerSliderElement extends ButtonElement {
+        public int sliderValue;
+        public boolean dragging;
+        public boolean renderText = true;
+        private int min;
+        private int max;
+
+        public IconCoordinate backgroundTexture;
+
+        public IntegerSliderElement(final int id, final int xPosition, final int yPosition) {
+            this(id, xPosition, yPosition, 150, 20);
+        }
+
+        public IntegerSliderElement(final int id, final int xPosition, final int yPosition, final int width, final int height) {
+            super(id, xPosition, yPosition, width, height, "");
+
+            this.dragging = false;
+        }
+
+        @Override
+        protected void setDefaultTextures() {
+            this.backgroundTexture = TextureRegistry.getTexture("minecraft:gui/widgets/slider/slider_background");
+            this.defaultTexture = TextureRegistry.getTexture("minecraft:gui/widgets/slider/slider");
+            this.hoveredTexture = TextureRegistry.getTexture("minecraft:gui/widgets/slider/slider_highlighted");
+            this.disabledTexture = TextureRegistry.getTexture("minecraft:gui/widgets/slider/slider_disabled");
+        }
+
+        private int getSliderWidth() {
+            return 8;
+        }
+
+        @Override
+        public void mouseDragged(final @NotNull Minecraft mc, final int mouseX, final int mouseY) {
+            if (!this.visible) {
+                return;
+            }
+            final int sliderWidth = this.getSliderWidth();
+            final int segments = (this.max - this.min);
+            if (this.dragging && segments != 0) {
+                float percentage = (float) (mouseX - (this.xPosition + 4) - (this.width / (2 * segments))) / (float) (this.width - sliderWidth);
+                if (percentage > 1.0f)
+                    percentage = 1.0f;
+                if (percentage < 0.0f)
+                    percentage = 0.0f;
+                this.sliderValue = this.min + (int) Math.ceil(segments * percentage);
+            }
+            GLRenderer.setColor4f(1f, 1f, 1f, 1f);
+        }
+
+        @Override
+        public void drawButton(final @NotNull Minecraft mc, final int mouseX, final int mouseY) {
+            if (!this.visible) return;
+
+            final boolean mouseOver = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height;
+            final int state = this.getButtonState(mouseOver);
+
+            GLRenderer.setColor4f(1f, 1f, 1f, 1f);
+
+            final @NotNull IconCoordinate tex = switch (state) {
+                case STATE_DISABLED -> this.disabledTexture;
+                case STATE_HOVERED -> this.hoveredTexture;
+                default -> this.defaultTexture;
+            };
+
+            // Draw background
+            this.drawGuiIcon(this.xPosition, this.yPosition, this.width, this.height, this.backgroundTexture);
+
+            // Draw foreground
+            final int segments = (this.max - this.min);
+            if (segments != 0) {
+                final int sliderWidth = this.getSliderWidth();
+                this.drawGuiIcon(this.xPosition + (int) (((this.sliderValue - this.min) / (float) segments) * (float) (this.width - sliderWidth)), this.yPosition, sliderWidth, this.height, tex);
+            }
+
+            this.mouseDragged(mc, mouseX, mouseY);
+
+            final int textColor = switch (state) {
+                case 0 -> 0xA0A0A0;
+                case 1 -> 0xE0E0E0;
+                default -> 0xFFFFA0;
+            };
+
+            if (this.renderText) {
+                this.drawStringCenteredShadow(mc.font, this.displayString, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, textColor);
+            }
+        }
+
+        @Override
+        public boolean mouseClicked(final @NotNull Minecraft mc, final int mouseX, final int mouseY) {
+            if (super.mouseClicked(mc, mouseX, mouseY)) {
+                final int segments = (this.max - this.min);
+                if (segments != 0) {
+                    float percentage = (float) (mouseX - (this.xPosition + 4) - (this.width / (2 * segments))) / (float) (this.width - 8);
+                    if (percentage > 1.0f)
+                        percentage = 1.0f;
+                    if (percentage < 0.0f)
+                        percentage = 0.0f;
+                    this.sliderValue = this.min + (int) Math.ceil(segments * percentage);
+                    this.dragging = true;
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public void mouseReleased(final int mouseX, final int mouseY) {
+            this.dragging = false;
+        }
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/ValueNodeComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/ValueNodeComponent.java
new file mode 100644
index 000000000..b879b01ca
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/ValueNodeComponent.java
@@ -0,0 +1,179 @@
+package net.minecraft.client.gui.worldsettings.settingnode;
+
+import net.minecraft.client.gui.ButtonElement;
+import net.minecraft.client.gui.paged.ScreenPaged;
+import net.minecraft.client.render.window.CursorShape;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.sound.SoundCategory;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.settings.ValueSettingNode;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Objects;
+
+public abstract class ValueNodeComponent<T> extends NestedNodeComponent {
+    private static final int BUTTON_WIDTH = 100;
+    private static final int BUTTON_HEIGHT = 20;
+
+    private final @NotNull Text nameText;
+
+    protected final @NotNull ButtonElement resetButton;
+
+    public ValueNodeComponent(final @NotNull ValueSettingNode<T> valueNode, final int nestLevel) {
+        super(valueNode, nestLevel);
+        this.nameText = valueNode.getName();
+        this.resetButton = new ButtonElement(0, 0, 0, 20, 20, "")
+            .setTextures("minecraft:gui/misc/icon_reset", "minecraft:gui/misc/icon_reset_highlighted", "minecraft:gui/misc/icon_reset");
+    }
+
+    @Override
+    public void reset() {
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        final @Nullable Dimension dimension = this.getDimension();
+        assert worldConfiguration != null;
+        assert dimension != null;
+
+        worldConfiguration.getDimensionSettings(dimension).setNodeValue(this.getNode(), this.getNode().getDefaultValue(dimension, worldConfiguration));
+        super.reset();
+    }
+
+    @Override
+    public void onUpdate(final @NotNull Dimension dimension, final @NotNull WorldConfiguration worldConfiguration) {
+        super.onUpdate(dimension, worldConfiguration);
+
+        if (!this.getNode().validateValue(this.getValue(), dimension, worldConfiguration)) {
+            worldConfiguration.getDimensionSettings(dimension).withNotificationsSuppressed(dimensionSettings -> {
+                dimensionSettings.setNodeValue(this.getNode(), this.getNode().getDefaultValue(dimension, worldConfiguration));
+            });
+        }
+    }
+
+    public boolean isDefault() {
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        final @Nullable Dimension dimension = this.getDimension();
+        assert worldConfiguration != null;
+        assert dimension != null;
+
+        final @NotNull T defaultValue = this.getNode().getDefaultValue(dimension, worldConfiguration);
+        final @NotNull T currentValue = this.getValue();
+        return defaultValue == currentValue || defaultValue.equals(currentValue) || currentValue.equals(defaultValue);
+    }
+
+    @Override
+    public int getNestLevelContribution() {
+        return 1;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public @NotNull ValueSettingNode<T> getNode() {
+        return (ValueSettingNode<T>) super.getNode();
+    }
+
+    public @NotNull T getValue() {
+        final @Nullable WorldConfiguration worldConfiguration = this.getWorldConfiguration();
+        final @Nullable Dimension dimension = this.getDimension();
+        assert worldConfiguration != null;
+        assert dimension != null;
+
+        final @Nullable T value = worldConfiguration.getDimensionSettings(dimension).getNodeValue(this.getNode(), worldConfiguration);
+        return Objects.requireNonNullElseGet(value, () -> this.getNode().getDefaultValue(dimension, worldConfiguration));
+    }
+
+    @Override
+    public int getBaseHeight() {
+        return super.getBaseHeight() + BUTTON_HEIGHT + COMPONENT_SPACING;
+    }
+
+    @Override
+    public void render(final @NotNull ScreenPaged screen, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        final @NotNull String translated = this.nameText.toString();
+        int textColor = 0xFFFFFFFF;
+        if (relativeMouseX >= 0 && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= this.getHeight() - COMPONENT_SPACING) {
+            textColor = 0xFFFFFFA0;
+        }
+
+        MC.font.render(translated, x, y + (this.getBaseHeight() / 2) - 4).setShadow().setColor(textColor).call();
+        this.resetButton.enabled = !this.isDefault();
+        this.renderResetButton(x, y, width - BUTTON_WIDTH, COMPONENT_SPACING, relativeMouseX, relativeMouseY);
+        this.renderButton(x, y, width - BUTTON_WIDTH, COMPONENT_SPACING, BUTTON_WIDTH, BUTTON_HEIGHT, relativeMouseX, relativeMouseY);
+        final int stringWidth = MC.font.stringWidth(translated);
+        int lineMaxX = x + width - BUTTON_WIDTH - 8;
+        if (this.resetButton.enabled) {
+            lineMaxX -= 20;
+        }
+        this.drawRect(x + stringWidth + 8, y + this.getBaseHeight() / 2, lineMaxX, y + this.getBaseHeight() / 2 + 1, 0x5F7F7F7F);
+
+        super.render(screen, x, y, width, relativeMouseX, relativeMouseY);
+    }
+
+    @Override
+    public boolean onMouseClick(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        if (super.onMouseClick(mouseButton, x, y, width, relativeMouseX, relativeMouseY)) {
+            return true;
+        } else if (relativeMouseX >= width - BUTTON_WIDTH && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= COMPONENT_SPACING + BUTTON_HEIGHT) {
+            MC.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+            this.buttonClicked(mouseButton, x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+            return true;
+        } else if (this.resetButton.enabled && relativeMouseX >= width - BUTTON_WIDTH - 20 && relativeMouseX <= width - BUTTON_WIDTH && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= COMPONENT_SPACING + BUTTON_HEIGHT) {
+            MC.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+            this.reset();
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean onMouseMove(final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        if (!super.onMouseMove(x, y, width, relativeMouseX, relativeMouseY)) {
+            this.buttonDragged(x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean onMouseRelease(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        if (!super.onMouseRelease(mouseButton, x, y, width, relativeMouseX, relativeMouseY)) {
+            this.buttonReleased(mouseButton, x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+        }
+
+        return true;
+    }
+
+    protected abstract boolean buttonClicked(int mouseButton, int x, int y, int width, int height, int relativeMouseX, int relativeMouseY);
+
+    protected void buttonDragged(final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+    }
+
+    protected void buttonReleased(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+    }
+
+    @Override
+    public boolean matchesSearchTerm(final @NotNull String term) {
+        return this.nameText.toString().toLowerCase().contains(term.toLowerCase());
+    }
+
+    private void renderResetButton(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int relativeMouseX, final int relativeMouseY) {
+        if (this.resetButton.enabled) {
+            this.resetButton.xPosition = x + relativeButtonX - BUTTON_HEIGHT;
+            this.resetButton.yPosition = y + relativeButtonY;
+
+            this.resetButton.drawButton(MC, x + relativeMouseX, y + relativeMouseY);
+        }
+    }
+
+    private void renderButton(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY) {
+        this.renderButtonInner(x, y, relativeButtonX, relativeButtonY, buttonWidth, buttonHeight, relativeMouseX, relativeMouseY);
+
+        if (relativeMouseX >= relativeButtonX && relativeMouseX < relativeButtonX + buttonWidth && relativeMouseY >= relativeButtonY && relativeButtonY < relativeButtonY + buttonHeight) {
+            assert MC.currentScreen != null;
+            MC.currentScreen.setDesiredCursor(CursorShape.HAND);
+        }
+    }
+
+    protected abstract void renderButtonInner(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY);
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/conversion/NodeAdapterRegistry.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/conversion/NodeAdapterRegistry.java
new file mode 100644
index 000000000..9e14815f2
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/conversion/NodeAdapterRegistry.java
@@ -0,0 +1,52 @@
+package net.minecraft.client.gui.worldsettings.settingnode.conversion;
+
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import net.minecraft.client.gui.worldsettings.settingnode.BooleanValueNodeComponent;
+import net.minecraft.client.gui.worldsettings.settingnode.ListValueNodeComponent;
+import net.minecraft.client.gui.worldsettings.settingnode.NestedNodeComponent;
+import net.minecraft.client.gui.worldsettings.NodeComponent;
+import net.minecraft.client.gui.worldsettings.settingnode.RangeIntegerNodeComponent;
+import net.minecraft.core.world.settings.ContainerSettingNode;
+import net.minecraft.core.world.settings.ListValueSettingNode;
+import net.minecraft.core.world.settings.SettingNode;
+import net.minecraft.core.world.settings.impl.BooleanSettingNode;
+import net.minecraft.core.world.settings.impl.RangeIntegerSettingNode;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+import java.util.Objects;
+
+public final class NodeAdapterRegistry {
+    private NodeAdapterRegistry() throws IllegalAccessException {
+        throw new IllegalAccessException("No NodeAdapterRegistry for you!");
+    }
+
+    private static final @NotNull Map<@NotNull Class<?>, @NotNull NodeIntoComponentAdapter<?, ?>> ADAPTERS = new Object2ObjectOpenHashMap<>();
+    public static <T extends SettingNode, C extends NodeComponent> void register(final @NotNull Class<T> settingNodeClass, final @NotNull NodeIntoComponentAdapter<T, C> adapter) {
+        ADAPTERS.put(settingNodeClass, adapter);
+    }
+
+    static {
+        register(ContainerSettingNode.class, NestedNodeComponent::new);
+        register(ListValueSettingNode.class, ListValueNodeComponent::new);
+        register(BooleanSettingNode.class, BooleanValueNodeComponent::new);
+        register(RangeIntegerSettingNode.class, RangeIntegerNodeComponent::new);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends SettingNode, C extends NodeComponent> @NotNull C adapt(final @NotNull T settingNode, final int nestLevel) {
+        final @NotNull Class<T> settingNodeClass = (Class<T>) settingNode.getClass();
+        final @Nullable NodeIntoComponentAdapter<T, C> adapter = (NodeIntoComponentAdapter<T, C>) ADAPTERS.get(settingNodeClass);
+        if (adapter == null) {
+            for (final @NotNull Class<?> clazz : ADAPTERS.keySet()) {
+                if (clazz.isAssignableFrom(settingNodeClass)) {
+                    return (C) ((NodeIntoComponentAdapter<SettingNode, NodeComponent>) Objects.requireNonNull(ADAPTERS.get(clazz))).adapt(settingNode, nestLevel);
+                }
+            }
+            throw new IllegalArgumentException("Node has no adapter!");
+        }
+
+        return adapter.adapt(settingNode, nestLevel);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/conversion/NodeIntoComponentAdapter.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/conversion/NodeIntoComponentAdapter.java
new file mode 100644
index 000000000..382757004
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/settingnode/conversion/NodeIntoComponentAdapter.java
@@ -0,0 +1,9 @@
+package net.minecraft.client.gui.worldsettings.settingnode.conversion;
+
+import net.minecraft.client.gui.worldsettings.NodeComponent;
+import net.minecraft.core.world.settings.SettingNode;
+import org.jetbrains.annotations.NotNull;
+
+public interface NodeIntoComponentAdapter<T extends SettingNode, C extends NodeComponent> {
+    @NotNull C adapt(final @NotNull T settingNode, final int nestLevel);
+}
diff --git a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
index 4e53b667b..42ac2295b 100644
--- a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
+++ b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
@@ -61,14 +61,15 @@ import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.util.helper.AES;
 import net.minecraft.core.util.helper.RSA;
 import net.minecraft.core.util.helper.UUIDHelper;
-import net.minecraft.core.world.Explosion;
-import net.minecraft.core.world.ExplosionCannonball;
-import net.minecraft.core.world.ICarriable;
-import net.minecraft.core.world.IVehicle;
+import net.minecraft.core.world.*;
 import net.minecraft.core.world.data.SynchedEntityData;
 import net.minecraft.core.world.pos.ChunkPos;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.save.LevelData;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import net.minecraft.core.world.type.WorldType;
+import net.minecraft.core.world.type.WorldTypeGroups;
+import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.Weathers;
 import org.jetbrains.annotations.NotNull;
@@ -145,7 +146,16 @@ public class PacketHandlerClient extends PacketHandler {
     public void handleLogin(@NotNull PacketLogin packetLogin) {
         this.mc.playerController = new PlayerControllerMP(this.mc, this);
         this.mc.statsCounter.add(StatList.joinMultiplayerStat, 1);
-        this.worldClientMP = new WorldClientMP(this, mc, packetLogin.worldSeed, packetLogin.dimensionId, packetLogin.worldTypeId);
+        final @NotNull WorldConfiguration worldConfiguration = new WorldConfiguration();
+        final @NotNull Dimension dimension = Objects.requireNonNull(Dimension.getDimensionList().get(packetLogin.dimensionId));
+        for (final @NotNull WorldTypeGroups.Group group : WorldTypeGroups.GROUPS) {
+            if (group.get(dimension).equals(Registries.WORLD_TYPES.getItemByNumericId(packetLogin.worldTypeId))) {
+                worldConfiguration.setWorldTypeGroup(group);
+                break;
+            }
+        }
+        worldConfiguration.setNumericSeed(packetLogin.worldSeed);
+        this.worldClientMP = new WorldClientMP(this, mc, worldConfiguration, Dimension.getDimensionList().get(packetLogin.dimensionId));
         this.worldClientMP.isClientSide = true;
         this.mc.changeWorld(this.worldClientMP);
         this.mc.thePlayer.dimension = packetLogin.dimensionId;
@@ -745,7 +755,16 @@ public class PacketHandlerClient extends PacketHandler {
     public void handleRespawn(@NotNull PacketRespawn packetRespawn) {
         if (packetRespawn.respawnDimensionId != this.mc.thePlayer.dimension) {
             this.started = false;
-            this.worldClientMP = new WorldClientMP(this, mc, this.worldClientMP.getLevelData().getRandomSeed(), packetRespawn.respawnDimensionId, packetRespawn.respawnWorldTypeId);
+            final @NotNull WorldConfiguration worldConfiguration = new WorldConfiguration();
+            final @NotNull Dimension dimension = Objects.requireNonNull(Dimension.getDimensionList().get(packetRespawn.respawnDimensionId));
+            for (final @NotNull WorldTypeGroups.Group group : WorldTypeGroups.GROUPS) {
+                if (group.get(dimension).equals(Registries.WORLD_TYPES.getItemByNumericId(packetRespawn.respawnWorldTypeId))) {
+                    worldConfiguration.setWorldTypeGroup(group);
+                    break;
+                }
+            }
+            worldConfiguration.setNumericSeed(this.worldClientMP.getLevelData().getRandomSeed());
+            this.worldClientMP = new WorldClientMP(this, mc, worldConfiguration, Dimension.getDimensionList().get(packetRespawn.respawnDimensionId));
             this.worldClientMP.isClientSide = true;
             this.mc.changeWorld(this.worldClientMP);
             this.mc.thePlayer.dimension = packetRespawn.respawnDimensionId;
diff --git a/game/client/src/main/java/net/minecraft/client/render/PostProcessingManager.java b/game/client/src/main/java/net/minecraft/client/render/PostProcessingManager.java
index ecae3acf0..4832cf391 100644
--- a/game/client/src/main/java/net/minecraft/client/render/PostProcessingManager.java
+++ b/game/client/src/main/java/net/minecraft/client/render/PostProcessingManager.java
@@ -72,8 +72,8 @@ public class PostProcessingManager {
         if (GameSettings.COLOR_CORRECTION.value == 0) return;
 
         final float y = (float) this.mc.thePlayer.y;
-        final int maxY = this.mc.currentWorld.getWorldType().getMaxY();
-        final int minY = this.mc.currentWorld.getWorldType().getMinY();
+        final int maxY = this.mc.currentWorld.getWorldType().getMaxY(this.mc.currentWorld);
+        final int minY = this.mc.currentWorld.getWorldType().getMinY(this.mc.currentWorld);
         final int rangeY = maxY - minY;
         final int halfY = minY + rangeY / 2;
         final int quarterY = minY + rangeY / 4;
diff --git a/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java b/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
index d7046525b..30cdf2415 100644
--- a/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
@@ -309,7 +309,7 @@ public class RenderGlobal
         double cameraZO = camera.getZ(0);
 
         final double scale = 1f;
-        double auroraY = (this.world.getWorldType().getMaxY() + 64f) * 2f;
+        double auroraY = (this.world.getWorldType().getMaxY(this.world) + 64f) * 2f;
 
         // Draw pieces
         double time = this.world.getWorldTime();
@@ -391,7 +391,7 @@ public class RenderGlobal
             mult += temperature;
         }
 
-        double altitude = this.world.getWorldType().getYPercentage((int) cameraY);
+        double altitude = this.world.getWorldType().getYPercentage(this.world, (int) cameraY);
         if ((temperature <= 0.6f || this.world.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER || this.world.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER_ENDLESS) && altitude >= 0.8f) {
             // altitude from 0.8f to 1.0f
             altitude -= 0.8f;
@@ -891,7 +891,7 @@ public class RenderGlobal
         int k = MathHelper.floor(posZ / 2048D);
         posX -= j * 2048;
         posZ -= k * 2048;
-        float cloudHeight = (worldTypeFX.getCloudHeight() - cameraY) + 0.33F + getCloudHeightModifier();
+        float cloudHeight = (worldTypeFX.getCloudHeight(world) - cameraY) + 0.33F + getCloudHeightModifier();
         float f10 = (float) (posX * (double) f6);
         float f11 = (float) (posZ * (double) f6);
         tessellator.startDrawingQuads();
@@ -945,7 +945,7 @@ public class RenderGlobal
         float cloudThickness = 4F;
         double dx = (this.mc.activeCamera.getX(partialTick) + (double) ((this.lastCloudOffsetX + (this.cloudOffsetX - this.lastCloudOffsetX) * partialTick) * 0.03F)) / (double) cloudWidth;
         double dz = (this.mc.activeCamera.getZ(partialTick) + (double) ((this.lastCloudOffsetZ + (this.cloudOffsetZ - this.lastCloudOffsetZ) * partialTick) * 0.03F)) / (double) cloudWidth + 0.33D;
-        float dy = (worldTypeFX.getCloudHeight() - cameraY) + 0.33F + getCloudHeightModifier();
+        float dy = (worldTypeFX.getCloudHeight(world) - cameraY) + 0.33F + getCloudHeightModifier();
         int i = MathHelper.floor(dx / 2048D);
         int j = MathHelper.floor(dz / 2048D);
         dx -= i * 2048;
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFX.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFX.java
index 29df947b4..955bbd278 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFX.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFX.java
@@ -54,9 +54,9 @@ public class WorldTypeFX {
         return this.hasSky;
     }
 
-    public float getCloudHeight() {
+    public float getCloudHeight(final @NotNull World world) {
         if (this.cloudHeight == null) {
-            return (this.worldType.getMaxY() + 1) - 20;
+            return (this.worldType.getMaxY(world) + 1) - 20;
         }
         return this.cloudHeight;
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXNether.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXNether.java
index 33d113393..904c206ca 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXNether.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXNether.java
@@ -34,7 +34,7 @@ public class WorldTypeFXNether extends WorldTypeFX {
         float g = 0 / 255.0f;
         float b = 0 / 255.0f;
 
-        double temp = ((BiomeProviderNether) world.getBiomeProvider()).getTemperature(x, z);
+        double temp = world.getBiomeProvider().getTemperature(MathHelper.floor(x), MathHelper.floor(z));
 
         if (temp < 0.25) {
             r = 0.0f;
diff --git a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
index 20f665cac..bfe1b2801 100644
--- a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
+++ b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
@@ -24,6 +24,7 @@ import net.minecraft.core.world.save.LevelStorageDummy;
 import net.minecraft.core.world.saveddata.SavedDataStorage;
 import net.minecraft.core.world.season.SeasonManager;
 import net.minecraft.core.world.season.Seasons;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.weather.IPrecipitation;
@@ -41,12 +42,10 @@ public class WorldClient extends World {
     public WorldClient(
         final @NotNull Minecraft mc,
         final @NotNull LevelStorage levelStorage,
-        final @Nullable String name,
-        final long seed,
-        final @NotNull Dimension dimension,
-        final @Nullable Biome startingBiome
+        final @Nullable WorldConfiguration worldConfiguration,
+        final @NotNull Dimension dimension
     ) {
-        super(levelStorage, name, seed, dimension, startingBiome);
+        super(levelStorage, worldConfiguration, dimension);
 
         this.mc = mc;
     }
diff --git a/game/client/src/main/java/net/minecraft/client/world/WorldClientMP.java b/game/client/src/main/java/net/minecraft/client/world/WorldClientMP.java
index b3a826e02..6849c8bcc 100644
--- a/game/client/src/main/java/net/minecraft/client/world/WorldClientMP.java
+++ b/game/client/src/main/java/net/minecraft/client/world/WorldClientMP.java
@@ -19,6 +19,7 @@ import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.save.LevelStorage;
 import net.minecraft.core.world.save.LevelStorageDummy;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -37,18 +38,14 @@ public class WorldClientMP extends WorldClient {
     public WorldClientMP(
         final @NotNull PacketHandlerClient packetHandler,
         final @NotNull Minecraft mc,
-        final long seed,
-        final int dimensionId,
-        final int worldTypeId
+        final @NotNull WorldConfiguration worldConfiguration,
+        final @NotNull Dimension dimension
     ) {
         super(
             mc,
             new LevelStorageDummy(),
-            "MpServer",
-            seed,
-            Dimension.getDimensionList().get(dimensionId),
-//            Registries.WORLD_TYPES.getItemByNumericId(worldTypeId)
-            null
+            worldConfiguration,
+            dimension
         );
 
         this.positionTypesList = new LinkedList<>();
diff --git a/game/client/src/main/java/net/minecraft/client/world/WorldEmpty.java b/game/client/src/main/java/net/minecraft/client/world/WorldEmpty.java
index 501578fda..0f4162b56 100644
--- a/game/client/src/main/java/net/minecraft/client/world/WorldEmpty.java
+++ b/game/client/src/main/java/net/minecraft/client/world/WorldEmpty.java
@@ -6,13 +6,14 @@ import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.chunk.provider.ChunkProvider;
 import net.minecraft.core.world.save.LevelStorage;
 import net.minecraft.core.world.save.LevelStorageDummy;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import org.jetbrains.annotations.NotNull;
 
 public class WorldEmpty extends WorldClient {
     public static final @NotNull WorldEmpty INSTANCE = new WorldEmpty(Minecraft.getMinecraft());
 
     private WorldEmpty(final @NotNull Minecraft mc) {
-        super(mc, new LevelStorageDummy(), "Empty World", 0, Dimension.OVERWORLD, null);
+        super(mc, new LevelStorageDummy(), new WorldConfiguration(), Dimension.OVERWORLD);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRuleCollection.java b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRuleCollection.java
index 2f545381b..daa8264c9 100644
--- a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRuleCollection.java
+++ b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRuleCollection.java
@@ -2,7 +2,9 @@ package net.minecraft.core.data.gamerule;
 
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.data.registry.Registries;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -11,6 +13,8 @@ public final class GameRuleCollection
 {
     private final Map<GameRule<?>, Object> gameRules = new HashMap<>();
 
+    private @Nullable WorldConfiguration.ChangeListener changeListener;
+
     public GameRuleCollection()
     {
         for (GameRule<?> gameRule : Registries.GAME_RULES)
@@ -19,6 +23,16 @@ public final class GameRuleCollection
         }
     }
 
+    public void setChangeListener(final @Nullable WorldConfiguration.ChangeListener changeListener) {
+        this.changeListener = changeListener;
+    }
+
+    private void notifyChange() {
+        if (this.changeListener != null) {
+            this.changeListener.onChanged();
+        }
+    }
+
     public <T> @NotNull T getValue(final @NotNull GameRule<T> gameRule)
     {
         Object o = gameRules.get(gameRule);
@@ -32,6 +46,7 @@ public final class GameRuleCollection
     public <T> void setValue(GameRule<T> gameRule, T value)
     {
         gameRules.put(gameRule, value);
+        this.notifyChange();
     }
 
     public void setValues(GameRuleCollection collection)
@@ -46,6 +61,7 @@ public final class GameRuleCollection
             }
             gameRules.put(gameRule, o);
         }
+        this.notifyChange();
     }
 
     public GameRuleCollection copy()
diff --git a/game/core/src/main/java/net/minecraft/core/world/Dimension.java b/game/core/src/main/java/net/minecraft/core/world/Dimension.java
index f4693a627..45c1f3258 100644
--- a/game/core/src/main/java/net/minecraft/core/world/Dimension.java
+++ b/game/core/src/main/java/net/minecraft/core/world/Dimension.java
@@ -8,11 +8,14 @@ import net.minecraft.core.block.BlockLogicPortal;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.world.save.DimensionData;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypes;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.Objects;
+
 public class Dimension
 {
 	public int id;
@@ -30,17 +33,15 @@ public class Dimension
 		this.portalBlock = portalBlock;
 		this.defaultWorldType = defaultWorldType;
 	}
-	
-	public DimensionData getDimensionData(World world)
-	{
-		if (world.dimension == this)
-		{
+
+	public @NotNull DimensionData getDimensionData(final @NotNull World world) {
+		if (world.dimension == this) {
 			return world.getDimensionData();
 		}
-		DimensionData dimensionData = world.getLevelStorage().getDimensionData(this);
-		if (dimensionData == null) dimensionData = new DimensionData(this.defaultWorldType);
-		
-		return dimensionData;
+
+		final @Nullable DimensionData dimensionData = world.getLevelStorage().getDimensionData(this);
+
+		return Objects.requireNonNull(dimensionData);
 	}
 	
 	public boolean canPortal(Dimension dim)
diff --git a/game/core/src/main/java/net/minecraft/core/world/LevelDimensionDataWrapper.java b/game/core/src/main/java/net/minecraft/core/world/LevelDimensionDataWrapper.java
new file mode 100644
index 000000000..b4bdb7b37
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/LevelDimensionDataWrapper.java
@@ -0,0 +1,65 @@
+package net.minecraft.core.world;
+
+import net.minecraft.core.data.gamerule.GameRuleCollection;
+import net.minecraft.core.world.config.spawning.SpawnerConfig;
+import net.minecraft.core.world.save.DimensionData;
+import net.minecraft.core.world.save.LevelData;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import net.minecraft.core.world.settings.SettingNodesValues;
+import net.minecraft.core.world.type.WorldType;
+import org.jetbrains.annotations.NotNull;
+
+public class LevelDimensionDataWrapper implements WorldConfigurationReader {
+    private final @NotNull Dimension dimension;
+    private final @NotNull LevelData levelData;
+    private final @NotNull DimensionData dimensionData;
+
+    public LevelDimensionDataWrapper(final @NotNull Dimension dimension, final @NotNull LevelData levelData, final @NotNull DimensionData dimensionData) {
+        this.dimension = dimension;
+        this.levelData = levelData;
+        this.dimensionData = dimensionData;
+    }
+
+    @Override
+    public long getFinalNumericSeed() {
+        return this.levelData.getRandomSeed();
+    }
+
+    @Override
+    public @NotNull String getFinalWorldName() {
+        return this.levelData.getWorldName();
+    }
+
+    @Override
+    public @NotNull GameRuleCollection getGameRules() {
+        return this.levelData.getGameRules();
+    }
+
+    @Override
+    public @NotNull SpawnerConfig getSpawnerConfig() {
+        return this.levelData.getSpawnerConfig();
+    }
+
+    @Override
+    public boolean getCheatsEnabled() {
+        return this.levelData.getCheatsEnabled();
+    }
+
+    @Override
+    public @NotNull WorldType getWorldType(final @NotNull Dimension dimension) {
+        if (this.dimension.equals(dimension)) {
+            return this.dimensionData.getWorldType();
+        }
+
+        throw new RuntimeException("Tried to read un-wrapped dimension data!");
+    }
+
+    @Override
+    public @NotNull SettingNodesValues getDimensionSettings(final @NotNull Dimension dimension) {
+        if (this.dimension.equals(dimension)) {
+            return this.dimensionData.getDimensionSettings();
+        }
+
+        throw new RuntimeException("Tried to read un-wrapped dimension data!");
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java
index f511aaa17..63af916b6 100644
--- a/game/core/src/main/java/net/minecraft/core/world/World.java
+++ b/game/core/src/main/java/net/minecraft/core/world/World.java
@@ -36,13 +36,13 @@ import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.biome.provider.BiomeProvider;
+import net.minecraft.core.world.biome.provider.BiomeProviderSingleBiome;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.chunk.ChunkCache;
-import net.minecraft.core.world.chunk.ChunkCoordinate;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
 import net.minecraft.core.world.chunk.ChunkSection;
-import net.minecraft.core.world.chunk.ChunkLoader;
 import net.minecraft.core.world.chunk.provider.ChunkProvider;
+import net.minecraft.core.world.config.season.SeasonConfig;
 import net.minecraft.core.world.config.spawning.SpawnerConfig;
 import net.minecraft.core.world.lighting.LightingEngine;
 import net.minecraft.core.world.lighting.LightingEngineLegacy;
@@ -51,7 +51,13 @@ import net.minecraft.core.world.pathfinder.PathFinder;
 import net.minecraft.core.world.pos.*;
 import net.minecraft.core.world.save.*;
 import net.minecraft.core.world.saveddata.SavedData;
+import net.minecraft.core.world.season.Season;
 import net.minecraft.core.world.season.SeasonManager;
+import net.minecraft.core.world.settings.SettingNodesValues;
+import net.minecraft.core.world.settings.ValueSettingNode;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import net.minecraft.core.world.settings.WorldSettingNodes;
+import net.minecraft.core.world.settings.impl.SeasonSettingNode;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.weather.IPrecipitation;
 import net.minecraft.core.world.weather.Weather;
@@ -76,7 +82,6 @@ import java.util.TreeSet;
 import java.util.UUID;
 
 import static net.minecraft.core.Global.DAY_LENGTH_TICKS;
-import static net.minecraft.core.Global.accessor;
 import static net.minecraft.core.Global.isServer;
 
 public abstract class World implements MutableWorldSource {
@@ -140,6 +145,7 @@ public abstract class World implements MutableWorldSource {
     private final @NotNull LevelStorage levelStorage;
     private final @NotNull LevelData levelData;
     private final @NotNull DimensionData dimensionData;
+    private final @NotNull WorldConfigurationReader worldConfigurationReader;
     private final @NotNull BiomeProvider biomeProvider;
     private final @NotNull SeasonManager seasonManager;
     private final @NotNull WeatherManager weatherManager;
@@ -148,27 +154,28 @@ public abstract class World implements MutableWorldSource {
     private final @NotNull LightingEngine lightingEngine = new LightingEngineLegacy(this);
 
     private World(
-        final long seed,
-        final @Nullable String name,
         final @NotNull Dimension dimension,
         final @NotNull LevelStorage levelStorage,
+        final @Nullable WorldConfiguration worldConfiguration,
         final @Nullable LevelData levelData,
-        final @Nullable DimensionData dimensionData,
-        final @Nullable Biome startingBiome
+        final @Nullable DimensionData dimensionData
     ) {
-        if (name == null && levelData == null) {
-            throw new IllegalArgumentException("name and levelData cannot both be null!");
+        if (worldConfiguration == null && (levelData == null || dimensionData == null)) {
+            throw new IllegalArgumentException("worldConfiguration and levelData cannot both be null!");
         }
 
         this.levelStorage = levelStorage;
 
         // Set up level data
         this.isNewWorld = levelData == null;
-        this.levelData = Objects.requireNonNullElseGet(levelData, () -> new LevelData(seed, Objects.requireNonNull(name)));
+        this.levelData = Objects.requireNonNullElseGet(levelData, () -> new LevelData(Objects.requireNonNull(worldConfiguration)));
 
         // Set up dimension data
         this.dimension = dimension;
-        this.dimensionData = Objects.requireNonNullElseGet(dimensionData, () -> new DimensionData(this.dimension.defaultWorldType));
+        this.dimensionData = Objects.requireNonNullElseGet(dimensionData, () -> new DimensionData(this.dimension, Objects.requireNonNull(worldConfiguration)));
+
+        // Set up world configuration reader
+        this.worldConfigurationReader = new LevelDimensionDataWrapper(this.dimension, this.levelData, this.dimensionData);
 
         // Set up weather manager
         this.weatherManager = new WeatherManager(this,
@@ -181,11 +188,23 @@ public abstract class World implements MutableWorldSource {
         // Set up chunk provider
         this.chunkProvider = this.createChunkProvider(levelStorage);
 
+        final @NotNull SettingNodesValues dimensionSettings = this.dimensionData.getDimensionSettings();
+
         // Set up season manager
-        this.seasonManager = SeasonManager.fromConfig(this, this.getWorldType().getSeasonConfig());
+        if (dimensionSettings.getNodeValue(WorldSettingNodes.SINGLE_SEASON_ENABLED, this.worldConfigurationReader)) {
+            final @NotNull Season singleSeason = dimensionSettings.getNodeValue(WorldSettingNodes.SINGLE_SEASON_VALUE, this.worldConfigurationReader);
+            this.seasonManager = SeasonManager.fromConfig(this, SeasonConfig.builder().withSingleSeason(singleSeason).build());
+        } else {
+            this.seasonManager = SeasonManager.fromConfig(this, this.getWorldType().getSeasonConfig());
+        }
 
         // Set up biome provider
-        this.biomeProvider = this.getWorldType().createBiomeProvider(this);
+        if (dimensionSettings.getNodeValue(WorldSettingNodes.SINGLE_BIOME_ENABLED, this.worldConfigurationReader)) {
+            final @NotNull Biome biome = dimensionSettings.getNodeValue(WorldSettingNodes.SINGLE_BIOME_VALUE, this.worldConfigurationReader);
+            this.biomeProvider = new BiomeProviderSingleBiome(this, biome, biome.defaultTemperature, biome.defaultHumidity, biome.defaultVariety);
+        } else {
+            this.biomeProvider = this.getWorldType().createBiomeProvider(this);
+        }
 
         // Set up command manager
         this.commandManager.init();
@@ -193,7 +212,12 @@ public abstract class World implements MutableWorldSource {
         // Do world initialization
         if (this.isNewWorld && !this.isClientSide) {
             this.getWorldType().onWorldCreation(this);
-            this.getInitialSpawnLocation(startingBiome);
+
+            if (dimensionSettings.getNodeValue(WorldSettingNodes.STARTING_BIOME_ENABLED, this.worldConfigurationReader)) {
+                this.getInitialSpawnLocation(dimensionSettings.getNodeValue(WorldSettingNodes.STARTING_BIOME_VALUE, this.worldConfigurationReader));
+            } else {
+                this.getInitialSpawnLocation(null);
+            }
         }
         this.updateSkyBrightness();
     }
@@ -201,19 +225,15 @@ public abstract class World implements MutableWorldSource {
     // Usually called when a world is loaded or generated (Singleplayer & Server)
     public World(
         final @NotNull LevelStorage levelStorage,
-        final @Nullable String name,
-        final long seed,
-        final @NotNull Dimension dimension,
-        final @Nullable Biome startingBiome
+        final @Nullable WorldConfiguration worldConfiguration,
+        final @NotNull Dimension dimension
     ) {
         this(
-            seed,
-            name,
             dimension,
             levelStorage,
+            worldConfiguration,
             levelStorage.getLevelData(),
-            levelStorage.getDimensionData(dimension),
-            startingBiome
+            levelStorage.getDimensionData(dimension)
         );
     }
 
@@ -223,16 +243,22 @@ public abstract class World implements MutableWorldSource {
         final @NotNull Dimension dimension
     ) {
         this(
-            parent.getLevelData().getRandomSeed(),
-            parent.getLevelData().getWorldName(),
             dimension,
             parent.levelStorage,
+            null,
             new LevelData(parent.levelData),
-            parent.levelStorage.getDimensionData(dimension),
-            null
+            parent.levelStorage.getDimensionData(dimension)
         );
     }
 
+    public <T> @NotNull T getWorldSetting(final @NotNull ValueSettingNode<T> node) {
+        return this.dimensionData.getDimensionSettings().getNodeValue(node, this.worldConfigurationReader);
+    }
+
+    public <T> @NotNull T getWorldSettingOr(final @NotNull ValueSettingNode<T> node, final @NotNull T or) {
+        return this.dimensionData.getDimensionSettings().getNodeValueOr(node, or);
+    }
+
     public abstract void setLightningFlicker(final int flicker);
 
     public <T> T getGameRuleValue(final GameRule<T> gameRule) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/Biome.java b/game/core/src/main/java/net/minecraft/core/world/biome/Biome.java
index a8455e7a2..8f3503e9d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/Biome.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/Biome.java
@@ -45,6 +45,9 @@ public class Biome
     protected @NotNull List<@NotNull SpawnListEntry> spawnableAmbientCreatureList = new ArrayList<>();
     private boolean hasSurfaceSnow = false;
     private boolean hasSurfaceIce = false;
+    public float defaultTemperature = 0.5f;
+    public float defaultHumidity = 0.5f;
+    public float defaultVariety = 0.5f;
     
     public Biome(String key)
     {
@@ -68,6 +71,13 @@ public class Biome
         this.spawnableAmbientCreatureList.add(new SpawnListEntry(MobButterfly.class, 65));
     }
 
+    public @NotNull Biome setDefaults(final float temperature, final float humidity, final float variety) {
+        this.defaultTemperature = temperature;
+        this.defaultHumidity = humidity;
+        this.defaultVariety = variety;
+        return this;
+    }
+
     public WorldFeature getRandomWorldGenForTrees(Random random)
     {
         if(random.nextInt(10) == 0)
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/Biomes.java b/game/core/src/main/java/net/minecraft/core/world/biome/Biomes.java
index 8fd5abe0a..e42bbc5d1 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/Biomes.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/Biomes.java
@@ -11,28 +11,28 @@ import net.minecraft.core.world.weather.Weathers;
 public class Biomes
 {
 
-    public static final Biome OVERWORLD_RAINFOREST = register("minecraft:overworld.rainforest", new BiomeRainforest("overworld.rainforest").setColor(0x1cf100).setBlockedWeathers(Weathers.OVERWORLD_SNOW));
-    public static final Biome OVERWORLD_SWAMPLAND = register("minecraft:overworld.swampland", new BiomeSwamp("overworld.swampland").setColor(0x00ff78));
-    public static final Biome OVERWORLD_SEASONAL_FOREST = register("minecraft:overworld.seasonal_forest", new BiomeSeasonalForest("overworld.seasonal_forest").setColor(0x64ce15));
-    public static final Biome OVERWORLD_FOREST = register("minecraft:overworld.forest", new BiomeForest("overworld.forest").setColor(0x26a615));
-    public static final Biome OVERWORLD_GRASSLANDS = register("minecraft:overworld.grasslands", new Biome("overworld.grasslands").setColor(0xf0f048).setBlockedWeathers(Weathers.OVERWORLD_SNOW));
-    public static final Biome OVERWORLD_OUTBACK = register("minecraft:overworld.outback", new BiomeOutback("overworld.outback").setColor(0xd95e20).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setTopBlock(Blocks.DIRT_SCORCHED.id()).setFillerBlock(Blocks.DIRT_SCORCHED.id()));
-    public static final Biome OVERWORLD_SHRUBLAND = register("minecraft:overworld.shrubland", new BiomeShrubland("overworld.shrubland").setColor(0xbaba38));
-    public static final Biome OVERWORLD_TAIGA = register("minecraft:overworld.taiga", new BiomeTaiga("overworld.taiga").setColor(0x8abcff).setSurfaceSnow().setSurfaceIce());
-    public static final Biome OVERWORLD_BOREAL_FOREST = register("minecraft:overworld.boreal_forest", new BiomeBorealForest("overworld.boreal_forest").setColor(0x148564));
-    public static final Biome OVERWORLD_DESERT = register("minecraft:overworld.desert", new BiomeDesert("overworld.desert").setColor(0xEDE26F).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM).setTopBlock(Blocks.SAND.id()).setFillerBlock(Blocks.SAND.id()));
-    public static final Biome OVERWORLD_PLAINS = register("minecraft:overworld.plains", new BiomePlains("overworld.plains").setColor(0xA3C649));
-    public static final Biome OVERWORLD_GLACIER = register("minecraft:overworld.glacier", new Biome("overworld.glacier").setColor(0xcbf6ff).setSurfaceSnow().setTopBlock(Blocks.BLOCK_SNOW.id()).setFillerBlock(Blocks.BLOCK_SNOW.id()));
-    public static final Biome OVERWORLD_TUNDRA = register("minecraft:overworld.tundra", new Biome("overworld.tundra").setColor(0x57e0ff).setSurfaceSnow().setSurfaceIce());
-    public static final Biome OVERWORLD_MEADOW = register("minecraft:overworld.meadow", new BiomeBorealForest("overworld.meadow").setColor(0x8c8c22));
-    public static final Biome DRIFT_DRIFT = register("minecraft:drift.drift", new BiomeDrift("drift.drift").setColor(0x8080FF).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG));
-    public static final Biome OVERWORLD_BIRCH_FOREST = register("minecraft:overworld.birch_forest", new BiomeBirchForest("overworld.birch_forest").setColor(0x4bcb5e));
+    public static final Biome OVERWORLD_RAINFOREST = register("minecraft:overworld.rainforest", new BiomeRainforest("overworld.rainforest").setColor(0x1cf100).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setDefaults(0.975f, 0.925f, 0.5f));
+    public static final Biome OVERWORLD_SWAMPLAND = register("minecraft:overworld.swampland", new BiomeSwamp("overworld.swampland").setColor(0x00ff78).setDefaults(0.85f, 0.925f, 0.5f));
+    public static final Biome OVERWORLD_SEASONAL_FOREST = register("minecraft:overworld.seasonal_forest", new BiomeSeasonalForest("overworld.seasonal_forest").setColor(0x64ce15).setDefaults(0.675f, 0.75f, 0.5f));
+    public static final Biome OVERWORLD_FOREST = register("minecraft:overworld.forest", new BiomeForest("overworld.forest").setColor(0x26a615).setDefaults(0.875f, 0.675f, 0.5f));
+    public static final Biome OVERWORLD_GRASSLANDS = register("minecraft:overworld.grasslands", new Biome("overworld.grasslands").setColor(0xf0f048).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setDefaults(0.75f, 0.025f, 0.5f));
+    public static final Biome OVERWORLD_OUTBACK = register("minecraft:overworld.outback", new BiomeOutback("overworld.outback").setColor(0xd95e20).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setTopBlock(Blocks.DIRT_SCORCHED.id()).setFillerBlock(Blocks.DIRT_SCORCHED.id()).setDefaults(0.825f, 0.1f, 0.5f));
+    public static final Biome OVERWORLD_SHRUBLAND = register("minecraft:overworld.shrubland", new BiomeShrubland("overworld.shrubland").setColor(0xbaba38).setDefaults(0.675f, 0.175f, 0.5f));
+    public static final Biome OVERWORLD_TAIGA = register("minecraft:overworld.taiga", new BiomeTaiga("overworld.taiga").setColor(0x8abcff).setSurfaceSnow().setSurfaceIce().setDefaults(0.15f, 0.55f, 0.5f));
+    public static final Biome OVERWORLD_BOREAL_FOREST = register("minecraft:overworld.boreal_forest", new BiomeBorealForest("overworld.boreal_forest").setColor(0x148564).setDefaults(0.4f, 0.525f, 0.5f));
+    public static final Biome OVERWORLD_DESERT = register("minecraft:overworld.desert", new BiomeDesert("overworld.desert").setColor(0xEDE26F).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM).setTopBlock(Blocks.SAND.id()).setFillerBlock(Blocks.SAND.id()).setDefaults(0.925f, 0.05f, 0.5f));
+    public static final Biome OVERWORLD_PLAINS = register("minecraft:overworld.plains", new BiomePlains("overworld.plains").setColor(0xA3C649).setDefaults(0.875f, 0.25f, 0.5f));
+    public static final Biome OVERWORLD_GLACIER = register("minecraft:overworld.glacier", new Biome("overworld.glacier").setColor(0xcbf6ff).setSurfaceSnow().setTopBlock(Blocks.BLOCK_SNOW.id()).setFillerBlock(Blocks.BLOCK_SNOW.id()).setDefaults(0.15f, 0.005f, 0.5f));
+    public static final Biome OVERWORLD_TUNDRA = register("minecraft:overworld.tundra", new Biome("overworld.tundra").setColor(0x57e0ff).setSurfaceSnow().setSurfaceIce().setDefaults(0.15f, 0.055f, 0.5f));
+    public static final Biome OVERWORLD_MEADOW = register("minecraft:overworld.meadow", new BiomeBorealForest("overworld.meadow").setColor(0x8c8c22).setDefaults(0.4f, 0.025f, 0.5f));
+    public static final Biome DRIFT_DRIFT = register("minecraft:drift.drift", new BiomeDrift("drift.drift").setColor(0x8080FF).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setDefaults(0.5f, 0.0f, 0.0f));
+    public static final Biome OVERWORLD_BIRCH_FOREST = register("minecraft:overworld.birch_forest", new BiomeBirchForest("overworld.birch_forest").setColor(0x4bcb5e).setDefaults(0.675f, 0.4f, 0.5f));
     public static final Biome OVERWORLD_RETRO = register("minecraft:overworld.retro", new BiomeRetro("overworld.retro").setColor(0x76B14A).setTopBlock(Blocks.GRASS_RETRO.id()));
     public static final Biome OVERWORLD_HELL = register("minecraft:overworld.hell", new Biome("overworld.hell").setColor(0xD96223).setTopBlock(Blocks.DIRT_SCORCHED.id()).setTopBlock(Blocks.DIRT_SCORCHED.id()));
-    public static final Biome OVERWORLD_SWAMPLAND_MUDDY = register("minecraft:overworld.swampland.muddy", new BiomeSwamp("overworld.swampland.muddy").setColor(0x522700));
-    public static final Biome OVERWORLD_OUTBACK_GRASSY = register("minecraft:overworld.outback.grassy", new BiomeOutback("overworld.outback.grassy").setColor(0xf09037).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setTopBlock(Blocks.GRASS_SCORCHED.id()).setFillerBlock(Blocks.DIRT_SCORCHED.id()));
-    public static final Biome OVERWORLD_CAATINGA = register("minecraft:overworld.caatinga", new BiomeCaatinga("overworld.caatinga").setColor(0xdecda6).setTopBlock(Blocks.MUD_BAKED.id()).setFillerBlock(Blocks.MUD_BAKED.id()).setBlockedWeathers(Weathers.OVERWORLD_SNOW));
-    public static final Biome OVERWORLD_CAATINGA_PLAINS = register("minecraft:overworld.caatinga.plains", new Biome("overworld.caatinga.plains").setColor(0xa19477).setTopBlock(Blocks.MUD_BAKED.id()).setFillerBlock(Blocks.MUD_BAKED.id()).setBlockedWeathers(Weathers.OVERWORLD_SNOW));
+    public static final Biome OVERWORLD_SWAMPLAND_MUDDY = register("minecraft:overworld.swampland.muddy", new BiomeSwamp("overworld.swampland.muddy").setColor(0x522700).setDefaults(0.85f, 0.925f, 0.5f));
+    public static final Biome OVERWORLD_OUTBACK_GRASSY = register("minecraft:overworld.outback.grassy", new BiomeOutback("overworld.outback.grassy").setColor(0xf09037).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setTopBlock(Blocks.GRASS_SCORCHED.id()).setFillerBlock(Blocks.DIRT_SCORCHED.id()).setDefaults(0.825f, 0.1f, 1.0f));
+    public static final Biome OVERWORLD_CAATINGA = register("minecraft:overworld.caatinga", new BiomeCaatinga("overworld.caatinga").setColor(0xdecda6).setTopBlock(Blocks.MUD_BAKED.id()).setFillerBlock(Blocks.MUD_BAKED.id()).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setDefaults(0.95f, 0.015f, 0.5f));
+    public static final Biome OVERWORLD_CAATINGA_PLAINS = register("minecraft:overworld.caatinga.plains", new Biome("overworld.caatinga.plains").setColor(0xa19477).setTopBlock(Blocks.MUD_BAKED.id()).setFillerBlock(Blocks.MUD_BAKED.id()).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setDefaults(0.95f, 0.015f, 0.0f));
     public static final Biome NETHER_NETHER = register("minecraft:nether.nether", new BiomeNether("nether.nether").setColor(0xDD0000).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.COBBLE_NETHERRACK.id()).setFillerBlock(Blocks.COBBLE_NETHERRACK.id()));
     public static final Biome NETHER_VOLCANIC_ISLANDS = register("minecraft:nether.volcanic_islands", new BiomeVolcanoIslands("nether.volcanic_islands").setColor(0xDD0000).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.COBBLE_NETHERRACK.id()).setFillerBlock(Blocks.COBBLE_NETHERRACK.id()));
     public static final Biome NETHER_SULFUR_POOLS = register("minecraft:nether.sulfur_pools", new BiomeSulfurPools("nether.sulfur_pools").setColor(0xDD0000).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.COBBLE_NETHERRACK.id()).setFillerBlock(Blocks.COBBLE_NETHERRACK.id()));
@@ -40,16 +40,16 @@ public class Biomes
     public static final Biome NETHER_ASH_PLAINS = register("minecraft:nether.ash_plains", new BiomeAshPlains("nether.ash_plains").setColor(0xDD0000).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.SLATE.id()).setFillerBlock(Blocks.SLATE.id()));
     public static final Biome NETHER_BONEYARD = register("minecraft:nether.boneyard", new BiomeBoneyard("nether.boneyard").setColor(0xDD0000).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.SOULSAND.id()).setFillerBlock(Blocks.SOULSAND.id()));
 
-    public static final Biome OVERWORLD_LEGACY_RAINFOREST = register("minecraft:overworld.legacy.rainforest", new BiomeRainforestLegacy("overworld.legacy.rainforest").setColor(0xd9e023).setBlockedWeathers(Weathers.OVERWORLD_SNOW));
-    public static final Biome OVERWORLD_LEGACY_SWAMPLAND = register("minecraft:overworld.legacy.swampland", new BiomeSwampLegacy("overworld.legacy.swampland").setColor(0x07f9b2));
-    public static final Biome OVERWORLD_LEGACY_SEASONAL_FOREST = register("minecraft:overworld.legacy.seasonal_forest", new Biome("overworld.legacy.seasonal_forest").setColor(0x9be023));
-    public static final Biome OVERWORLD_LEGACY_FOREST = register("minecraft:overworld.legacy.forest", new BiomeForestLegacy("overworld.legacy.forest").setColor(0x056621));
-    public static final Biome OVERWORLD_LEGACY_SAVANNA = register("minecraft:overworld.legacy.savanna", new BiomeDesertLegacy("overworld.legacy.savanna").setColor(0xd9e023).setBlockedWeathers(Weathers.OVERWORLD_SNOW));
-    public static final Biome OVERWORLD_LEGACY_SHRUBLAND = register("minecraft:overworld.legacy.shrubland", new Biome("overworld.legacy.shrubland").setColor(0xa1ad20));
-    public static final Biome OVERWORLD_LEGACY_TAIGA = register("minecraft:overworld.legacy.taiga", new BiomeTaigaLegacy("overworld.legacy.taiga").setColor(0x2eb153).setSurfaceSnow().setSurfaceIce());
-    public static final Biome OVERWORLD_LEGACY_DESERT = register("minecraft:overworld.legacy.desert", new BiomeDesertLegacy("overworld.legacy.desert").setColor(0xfa9418).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM).setTopBlock(Blocks.SAND.id()).setFillerBlock(Blocks.SAND.id()));
-    public static final Biome OVERWORLD_LEGACY_PLAINS = register("minecraft:overworld.legacy.plains", new BiomeDesertLegacy("overworld.legacy.plains").setColor(0xffd910));
-    public static final Biome OVERWORLD_LEGACY_TUNDRA = register("minecraft:overworld.legacy.tundra", new Biome("overworld.legacy.tundra").setColor(0x57ebf9).setSurfaceSnow().setSurfaceIce());
+    public static final Biome OVERWORLD_LEGACY_RAINFOREST = register("minecraft:overworld.legacy.rainforest", new BiomeRainforestLegacy("overworld.legacy.rainforest").setColor(0xd9e023).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setDefaults(0.985f,  0.95f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_SWAMPLAND = register("minecraft:overworld.legacy.swampland", new BiomeSwampLegacy("overworld.legacy.swampland").setColor(0x07f9b2).setDefaults(0.75f, 0.4f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_SEASONAL_FOREST = register("minecraft:overworld.legacy.seasonal_forest", new Biome("overworld.legacy.seasonal_forest").setColor(0x9be023).setDefaults(0.985f, 0.675f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_FOREST = register("minecraft:overworld.legacy.forest", new BiomeForestLegacy("overworld.legacy.forest").setColor(0x056621).setDefaults(0.735f, 0.425f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_SAVANNA = register("minecraft:overworld.legacy.savanna", new BiomeDesertLegacy("overworld.legacy.savanna").setColor(0xd9e023).setBlockedWeathers(Weathers.OVERWORLD_SNOW).setDefaults(0.725f, 0.1f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_SHRUBLAND = register("minecraft:overworld.legacy.shrubland", new Biome("overworld.legacy.shrubland").setColor(0xa1ad20).setDefaults(0.735f, 0.275f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_TAIGA = register("minecraft:overworld.legacy.taiga", new BiomeTaigaLegacy("overworld.legacy.taiga").setColor(0x2eb153).setSurfaceSnow().setSurfaceIce().setDefaults(0.3f, 0.35f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_DESERT = register("minecraft:overworld.legacy.desert", new BiomeDesertLegacy("overworld.legacy.desert").setColor(0xfa9418).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM).setTopBlock(Blocks.SAND.id()).setFillerBlock(Blocks.SAND.id()).setDefaults(0.975f, 0.1f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_PLAINS = register("minecraft:overworld.legacy.plains", new BiomeDesertLegacy("overworld.legacy.plains").setColor(0xffd910).setDefaults(0.985f, 0.325f, 0.5f));
+    public static final Biome OVERWORLD_LEGACY_TUNDRA = register("minecraft:overworld.legacy.tundra", new Biome("overworld.legacy.tundra").setColor(0x57ebf9).setSurfaceSnow().setSurfaceIce().setDefaults(0.05f, 0.5f, 0.5f));
 
     public static Biome register(String key, Biome biome)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProvider.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProvider.java
index 42d548ae5..bd910ad9f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProvider.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProvider.java
@@ -4,12 +4,20 @@ import com.mojang.logging.LogUtils;
 import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import net.minecraft.core.data.registry.Registries;
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 public abstract class BiomeProvider {
     private static final Logger LOGGER = LogUtils.getLogger();
 
+    protected final @NotNull World world;
+
+    public BiomeProvider(final @NotNull World world) {
+        this.world = world;
+    }
+
     public Biome getBiome(final int x, final int y, final int z) {
         final Biome[] out = getBiomes(null, x, y, z, 1, 1, 1);
         return out[0];
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java
index 6d95fd3a7..201b7c338 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java
@@ -1,5 +1,6 @@
 package net.minecraft.core.world.biome.provider;
 
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.noise.FractalNoise2D;
@@ -20,7 +21,11 @@ public class BiomeProviderB173
     private final @NotNull FractalNoise2D<?> downfallMap;
     private final @NotNull FractalNoise2D<?> noiseMap;
 
-    public BiomeProviderB173(final long seed) {
+    public BiomeProviderB173(final @NotNull World world) {
+        super(world);
+
+        final long seed = world.getRandomSeed();
+
         this.temperatureMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 9871, 4));
         this.downfallMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 39811, 4));
         this.noiseMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321, 4));
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java
index 0d03b4adb..8d0508689 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java
@@ -1,26 +1,20 @@
 package net.minecraft.core.world.biome.provider;
 
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.noise.FractalNoise2D;
 import net.minecraft.core.world.noise.FractalNoise3D;
 import net.minecraft.core.world.noise.SimplexNoise;
 import net.minecraft.core.world.type.WorldTypes;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Arrays;
 
 public final class BiomeProviderNether
     extends BiomeProvider
 {
-    public static class BiomeOverlapPair {
-        public boolean hasOverlap;
-        public Biome biomeA;
-        public Biome biomeB;
-        public float biomeAPercentage;
-        public float biomeBPercentage;
-    }
-
-    private static final Biome[] biomesOrder = {
+    public static final Biome[] BIOMES_ORDER = {
             Biomes.NETHER_BONEYARD,
             Biomes.NETHER_ASH_PLAINS,
             Biomes.NETHER_CRYSTAL_FOREST,
@@ -41,8 +35,11 @@ public final class BiomeProviderNether
     private double fuzzinessZScale = 0.25;
     private double fuzzinessLacunarity = 1.0;
 
-    public BiomeProviderNether(long seed)
+    public BiomeProviderNether(final @NotNull World world)
     {
+        super(world);
+
+        final long seed = world.getRandomSeed();
         this.temperatureNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 5345, 4));
         this.fuzzinessNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 35864, 2));
     }
@@ -79,7 +76,7 @@ public final class BiomeProviderNether
 
                 for (int dy = 0; dy < ySize; dy++)
                 {
-                    double altitude = WorldTypes.NETHER_DEFAULT.getYPercentage((y + dy) << 3);
+                    double altitude = WorldTypes.NETHER_DEFAULT.getYPercentage(world, (y + dy) << 3);
                     biomes[dy * xSize * zSize + dz * xSize + dx] = lookupBiome(temperature, humidity, altitude, variety);
                 }
             }
@@ -181,104 +178,16 @@ public final class BiomeProviderNether
 
     @Override
     public Biome lookupBiome(double temperature, double humidity, double altitude, double variety) {
-        for (int i = 0; i < biomesOrder.length; i++) {
-            if (temperature <= (1.0 / biomesOrder.length) * (i + 1)) {
-                return biomesOrder[i];
+        for (int i = 0; i < BIOMES_ORDER.length; i++) {
+            if (temperature <= (1.0 / BIOMES_ORDER.length) * (i + 1)) {
+                return BIOMES_ORDER[i];
             }
         }
 
         return Biomes.NETHER_NETHER;
     }
 
-    public void getOverlap(double temperature, BiomeOverlapPair toUpdate) {
-        final float overlapAmount = 1f / (float)(biomesOrder.length * 4);
-
-        for (int i = 0; i < biomesOrder.length; i++) {
-            // The *strict* bounds of the biome, as used by this::lookupBiome()
-            final float minStrict = (1.0f / biomesOrder.length) * i;
-            final float maxStrict = (1.0f / biomesOrder.length) * (i + 1);
-            // The outer bounds of the biome, i.e. strict bounds plus overlap amount. If in this range, guaranteed overlap
-            final float minOuter = minStrict - overlapAmount;
-            final float maxOuter = maxStrict + overlapAmount;
-            // The inner bounds of the biome, i.e. strict bounds minus overlap amount. If in this range, guaranteed no overlap
-            final float minInner = minStrict + overlapAmount;
-            final float maxInner = maxStrict - overlapAmount;
-
-            // Edge cases
-            if ((i == 0 && temperature < minInner) ||
-                (i == biomesOrder.length - 1 && temperature >= maxInner)
-            ) {
-                toUpdate.hasOverlap = false;
-                toUpdate.biomeA = biomesOrder[i];
-                toUpdate.biomeAPercentage = 1.0f;
-                return;
-            }
-
-            // Check if in inner bounds
-            if (temperature >= minInner && temperature < maxInner) {
-                // In inner bounds - only one biome is present here
-                toUpdate.hasOverlap = false;
-                toUpdate.biomeA = biomesOrder[i];
-                toUpdate.biomeAPercentage = 1.0f;
-                return;
-            }
-
-            // Check if in outer bounds
-            if (temperature >= minOuter && temperature < maxOuter) {
-                // Check if in min outer bound
-                if (temperature < minInner) {
-                    toUpdate.hasOverlap = true;
-
-                    // Define biomes
-                    toUpdate.biomeA = biomesOrder[i - 1];
-                    toUpdate.biomeB = biomesOrder[i];
-
-                    // Define percentages
-                    final float range = minInner - minOuter;
-                    // minOuter <= temperature < minInner
-                    temperature -= minOuter; // 0 <= temperature < range
-                    temperature /= range; // 0 <= temperature < 1
-
-                    // Biome A goes to 0.0 as temperature goes to 1.0
-                    // Biome B goes to 1.0 as temperature goes to 1.0
-                    toUpdate.biomeAPercentage = 1.0f - (float) temperature;
-                    toUpdate.biomeBPercentage = (float) temperature;
-
-                    return;
-                }
-
-                // Check if in max outer bound
-                if (temperature >= maxInner) {
-                    toUpdate.hasOverlap = true;
-
-                    // Define biomes
-                    toUpdate.biomeA = biomesOrder[i];
-                    toUpdate.biomeB = biomesOrder[i + 1];
-
-                    // Define percentages
-                    final float range = maxOuter - maxInner;
-                    // maxInner <= temperature < maxOuter
-                    temperature -= maxInner; // 0 <= temperature < range
-                    temperature /= range; // 0 <= temperature < 1
-
-                    // Biome A goes to 0.0 as temperature goes to 1.0
-                    // Biome B goes to 1.0 as temperature goes to 1.0
-                    toUpdate.biomeAPercentage = 1.0f - (float) temperature;
-                    toUpdate.biomeBPercentage = (float) temperature;
-
-                    return;
-                }
-            }
-        }
-
-        // We should never get here!
-        toUpdate.hasOverlap = false;
-        toUpdate.biomeA = Biomes.NETHER_NETHER;
-        toUpdate.biomeAPercentage = 1.0f;
-        return;
-    }
-
     public static Biome[] allBiomes() {
-        return biomesOrder;
+        return BIOMES_ORDER;
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
index b71fd7301..1f0a50ced 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
@@ -1,6 +1,7 @@
 package net.minecraft.core.world.biome.provider;
 
 import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.biome.data.BiomeRange;
@@ -8,6 +9,7 @@ import net.minecraft.core.world.biome.data.BiomeRangeMap;
 import net.minecraft.core.world.noise.FractalNoise2D;
 import net.minecraft.core.world.noise.SimplexNoise;
 import net.minecraft.core.world.type.WorldType;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Set;
 
@@ -41,12 +43,11 @@ public final class BiomeProviderOverworld
     private double noiseZScale = 0.25;
     private double noiseLacunarity = 1.0;
 
-    private final WorldType worldType;
-
-    public BiomeProviderOverworld(long seed, WorldType worldType)
+    public BiomeProviderOverworld(final @NotNull World world)
     {
-        this.worldType = worldType;
+        super(world);
 
+        final long seed = world.getRandomSeed();
         this.temperatureMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 9871, 4));
         this.humidityMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 39811, 4));
         this.varietyMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed, 4));
@@ -115,7 +116,7 @@ public final class BiomeProviderOverworld
 
                 for (int dy = 0; dy < ySize; dy++)
                 {
-                    double altitude = worldType.getYPercentage((y + dy) << 3);
+                    double altitude = world.getWorldType().getYPercentage(world, (y + dy) << 3);
                     biomes[dy * xSize * zSize + dz * xSize + dx] = lookupBiome(temperature, humidity, altitude, variety);
                 }
             }
@@ -254,7 +255,7 @@ public final class BiomeProviderOverworld
                 {
                     double temperature = MathHelper.clamp(temperatures[dx * zSize + dz], 0.0, 1.0);
                     double humidity = MathHelper.clamp(humidities[dx * zSize + dz], 0.0, 1.0);
-                    double altitude = MathHelper.clamp(worldType.getYPercentage((y + dy) << 3), 0.0, 1.0);
+                    double altitude = MathHelper.clamp(this.world.getWorldType().getYPercentage(this.world, (y + dy) << 3), 0.0, 1.0);
                     double variety = MathHelper.clamp(varieties[dx * zSize + dz], 0.0, 1.0);
                     Biome biome = lookupBiome(temperature, humidity, altitude, variety);
                     Set<BiomeRange> ranges = brm.getRanges(biome);
@@ -378,15 +379,12 @@ public final class BiomeProviderOverworld
         brm.addRange(Biomes.OVERWORLD_DESERT,
                 new BiomeRange(0.85, 1.0, 0.0, 0.01, 0.0, 1.0, 0.0, 1.0)
         );
-
         brm.addRange(Biomes.OVERWORLD_OUTBACK,
                 new BiomeRange(0.75, 0.9, 0.0, 0.2, 0.0, 1.0, 0.0, 0.95)
         );
         brm.addRange(Biomes.OVERWORLD_OUTBACK_GRASSY,
                 new BiomeRange(0.75, 0.9, 0.0, 0.2, 0.0, 1.0, 0.95, 1.0)
         );
-
-
         brm.addRange(Biomes.OVERWORLD_CAATINGA,
                 new BiomeRange(0.9, 1.0, 0.01, 0.2, 0.0, 1.0, 0.1, 1.0)
         );
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderSingleBiome.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderSingleBiome.java
index eb38c7ca1..d95501a76 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderSingleBiome.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderSingleBiome.java
@@ -1,6 +1,8 @@
 package net.minecraft.core.world.biome.provider;
 
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Arrays;
 
@@ -12,8 +14,10 @@ public class BiomeProviderSingleBiome
     private final double defaultHumidity;
     private final double defaultVariety;
 
-    public BiomeProviderSingleBiome(Biome defaultBiome, double defaultTemperature, double defaultHumidity, double defaultVariety)
+    public BiomeProviderSingleBiome(final @NotNull World world, Biome defaultBiome, double defaultTemperature, double defaultHumidity, double defaultVariety)
     {
+        super(world);
+
         this.defaultBiome = defaultBiome;
         this.defaultTemperature = defaultTemperature;
         this.defaultHumidity = defaultHumidity;
diff --git a/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfigBuilder.java b/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfigBuilder.java
index 89f9ff7b4..02d0e1721 100644
--- a/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfigBuilder.java
+++ b/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfigBuilder.java
@@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import net.minecraft.core.world.season.Season;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -19,7 +20,7 @@ public class SeasonConfigBuilder
     private Type type = null;
     private List<Season> seasons = null;
     private Object2IntMap<Season> seasonLengthMap = null;
-    private Season singleSeason = null;
+    private @Nullable Season singleSeason = null;
 
     protected SeasonConfigBuilder() { }
 
@@ -39,7 +40,7 @@ public class SeasonConfigBuilder
         }
     }
 
-    public @NotNull SeasonConfigBuilder withSingleSeason(final Season season)
+    public @NotNull SeasonConfigBuilder withSingleSeason(final @Nullable Season season)
     {
         this.type = Type.SINGLE;
         this.seasons = null;
diff --git a/game/core/src/main/java/net/minecraft/core/world/config/spawning/SpawnerConfig.java b/game/core/src/main/java/net/minecraft/core/world/config/spawning/SpawnerConfig.java
index 8678031b7..3145e9c03 100644
--- a/game/core/src/main/java/net/minecraft/core/world/config/spawning/SpawnerConfig.java
+++ b/game/core/src/main/java/net/minecraft/core/world/config/spawning/SpawnerConfig.java
@@ -7,7 +7,9 @@ import com.mojang.nbt.tags.Tag;
 import net.minecraft.core.util.HardIllegalArgumentException;
 import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 
 import java.util.Collection;
@@ -20,28 +22,43 @@ public class SpawnerConfig {
     public boolean allowHostile = true;
     private final Map<NamespaceID, Boolean> mobSpawnOverrides = new HashMap<>();
 
+    private @Nullable WorldConfiguration.ChangeListener changeListener;
+
+    public void setChangeListener(final @Nullable WorldConfiguration.ChangeListener changeListener) {
+        this.changeListener = changeListener;
+    }
+
+    private void notifyChange() {
+        if (this.changeListener != null) {
+            this.changeListener.onChanged();
+        }
+    }
+
     public boolean canPassiveSpawn(@NotNull World world) {
         return this.allowPassive;
     }
 
-    public void setPassiveSpawning(boolean flag) {
-        this.allowPassive = flag;
+    public void setPassiveSpawning(boolean allowPassive) {
+        this.allowPassive = allowPassive;
+        this.notifyChange();
     }
 
     public boolean canHostileSpawn(@NotNull World world) {
         return this.allowHostile && world.getDifficulty().canHostileMobsSpawn();
     }
 
-    public void setHostileSpawning(boolean flag) {
-        this.allowHostile = flag;
+    public void setHostileSpawning(boolean hostileSpawning) {
+        this.allowHostile = hostileSpawning;
+        this.notifyChange();
     }
 
     public boolean canMobSpawn(@NotNull NamespaceID mobID) {
         return this.mobSpawnOverrides.getOrDefault(mobID, true);
     }
 
-    public void setMobSpawn(@NotNull NamespaceID mobID, boolean flag) {
-        this.mobSpawnOverrides.put(mobID, flag);
+    public void setMobSpawn(@NotNull NamespaceID mobID, boolean enabled) {
+        this.mobSpawnOverrides.put(mobID, enabled);
+        this.notifyChange();
     }
 
     public void set(@NotNull SpawnerConfig config) {
@@ -50,6 +67,8 @@ public class SpawnerConfig {
 
         this.allowHostile = config.allowHostile;
         this.allowPassive = config.allowPassive;
+
+        this.notifyChange();
     }
 
     public Collection<Map.Entry<NamespaceID, Boolean>> getSpawnEntries() {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/IceFloeLargeFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/IceFloeLargeFeature.java
index 3bb495e7c..7becac3cd 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/IceFloeLargeFeature.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/IceFloeLargeFeature.java
@@ -40,7 +40,7 @@ public class IceFloeLargeFeature
         }
 
         final @NotNull WorldType worldType = world.getWorldType();
-        final int oceanY = worldType.getMinY() + worldType.getOceanY();
+        final int oceanY = worldType.getMinY(world) + worldType.getOceanY();
 
         final @NotNull TilePos tilePos = new TilePos();
         final @NotNull WorleyNoise.Result worleyResult = new WorleyNoise.Result();
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java
index e8b77ae80..e8edf3c8d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java
@@ -45,8 +45,8 @@ public abstract class ChunkFeatureDecorator
         final int worldX = chunkX * 16;
         final int worldZ = chunkZ * 16;
 
-        final int minY = this.world.getWorldType().getMinY();
-        final int maxY = this.world.getWorldType().getMaxY();
+        final int minY = this.world.getWorldType().getMinY(world);
+        final int maxY = this.world.getWorldType().getMaxY(world);
         final int rangeY = (maxY + 1) - minY;
 
         final @NotNull Random rand = new Random(this.world.getRandomSeed());
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
index f795cddc6..727182ed3 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
@@ -66,6 +66,9 @@ public class ChunkGeneratorClassic
         int chunkX = chunk.pos.x;
         int chunkZ = chunk.pos.z;
 
+        final int minY = world.getWorldType().getMinY(world);
+        final int maxY = world.getWorldType().getMaxY(world);
+
         final float mod = 1.3F;
 
         final int[] heightMap = new int[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z];
@@ -108,15 +111,15 @@ public class ChunkGeneratorClassic
                 int newHeight;
                 final int val2 = (newHeight = newHeightMap[x + z * Chunk.CHUNK_SIZE_X] + this.world.getWorldType().getOceanY()) + val;
                 newHeightMap[x + z * Chunk.CHUNK_SIZE_X] = Math.max(newHeight, val2);
-                if (newHeightMap[x + z * Chunk.CHUNK_SIZE_X] > this.world.getWorldType().getMaxY() - 2) {
-                    newHeightMap[x + z * Chunk.CHUNK_SIZE_X] = this.world.getWorldType().getMaxY() - 2;
+                if (newHeightMap[x + z * Chunk.CHUNK_SIZE_X] > maxY - 2) {
+                    newHeightMap[x + z * Chunk.CHUNK_SIZE_X] = maxY - 2;
                 }
 
                 if (newHeightMap[x + z * Chunk.CHUNK_SIZE_X] < 1) {
                     newHeightMap[x + z * Chunk.CHUNK_SIZE_X] = 1;
                 }
 
-                for (int y = this.world.getWorldType().getMinY(); y < this.world.getWorldType().getMaxY(); y++) {
+                for (int y = minY; y < maxY; y++) {
                     final int index = Chunk.makeBlockIndex(x, y, z);
                     int blockID = 0;
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/TerrainGeneratorLerp.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/TerrainGeneratorLerp.java
index e4ecc9a6a..b3e12b394 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/TerrainGeneratorLerp.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/TerrainGeneratorLerp.java
@@ -21,7 +21,10 @@ public abstract class TerrainGeneratorLerp
 
     @Override
     public @NotNull ChunkGeneratorResult generateTerrain(@NotNull Chunk chunk, double @NotNull [] densityMap) {
-        int terrainHeight = (this.world.getWorldType().getMaxY() + 1) - this.world.getWorldType().getMinY();
+        final int minY = world.getWorldType().getMinY(world);
+        final int maxY = world.getWorldType().getMaxY(world);
+
+        int terrainHeight = (maxY + 1) - minY;
 
         this.rand.setSeed((long) chunk.pos.x * 0x4F9939F508L + (long) chunk.pos.z * 0x1EF1565BD5L);
 
@@ -116,7 +119,7 @@ public abstract class TerrainGeneratorLerp
                             for (int zInBlob = 0; zInBlob < zBlocksPerBlob; zInBlob++) {
                                 // Determine the coordinates for the block within the blob.
                                 int blockX = xInBlob + blobX * xBlocksPerBlob;
-                                int blockY = yInBlob + blobY * yBlocksPerBlob + this.world.getWorldType().getMinY();
+                                int blockY = yInBlob + blobY * yBlocksPerBlob + minY;
                                 int blockZ = zInBlob + blobZ * zBlocksPerBlob;
 
                                 int id = getBlockAt(chunk, blockX, blockY, blockZ, zLerpDensity);
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
index 00b03069e..58e788487 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
@@ -29,7 +29,7 @@ public class DensityGeneratorDrift
 
     @Override
     public double @NotNull [] generateDensityMap(@NotNull Chunk chunk) {
-        int terrainHeight = (this.world.getWorldType().getMaxY() + 1) - this.world.getWorldType().getMinY();
+        int terrainHeight = (this.world.getWorldType().getMaxY(world) + 1) - this.world.getWorldType().getMinY(world);
 
         int xSize = 4 + 1;
         int ySize = (terrainHeight / 8) + 1;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
index f9a00f5d1..50646cf94 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
@@ -31,8 +31,8 @@ public class ChunkDecoratorNether
         int chunkX = chunk.pos.x;
         int chunkZ = chunk.pos.z;
 
-        int minY = this.world.getWorldType().getMinY();
-        int maxY = this.world.getWorldType().getMaxY();
+        int minY = this.world.getWorldType().getMinY(world);
+        int maxY = this.world.getWorldType().getMaxY(world);
         int rangeY = (maxY + 1) - minY;
 
         Random rand = new Random((long) chunkX * 0x4f9939f508L + (long) chunkZ * 0x1ef1565bd5L);
@@ -167,7 +167,7 @@ public class ChunkDecoratorNether
         }
 
         int oceanY = this.world.getWorldType().getOceanY();
-        int midY = oceanY + (this.world.getWorldType().getMaxY() - oceanY) / 2;
+        int midY = oceanY + (this.world.getWorldType().getMaxY(world) - oceanY) / 2;
         for (int dx = x + 8; dx < x + 8 + 16; dx++) {
             for (int dz = z + 8; dz < z + 8 + 16; dz++) {
                 int dy = midY;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
index cf29fbf42..5f991a5d2 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
@@ -20,6 +20,14 @@ public class DensityGeneratorNether
         double[] generateDensityMap(Chunk chunk, int terrainHeight, int xSize, int ySize, int zSize, int x, int y, int z);
     }
 
+    public static class BiomeOverlapPair {
+        public boolean hasOverlap;
+        public Biome biomeA;
+        public Biome biomeB;
+        public float biomeAPercentage;
+        public float biomeBPercentage;
+    }
+
     private final @NotNull World world;
 
     private final @NotNull Noise3D minLimitNoise;
@@ -65,7 +73,7 @@ public class DensityGeneratorNether
     public double @NotNull [] generateDensityMap(@NotNull Chunk chunk) {
         WorldType worldType = this.world.getWorldType();
 
-        int terrainHeight = ((worldType.getMaxY() + 1) - worldType.getMinY());
+        int terrainHeight = ((worldType.getMaxY(world) + 1) - worldType.getMinY(world));
         int xSize = 4 + 1;
         int ySize = (terrainHeight / 8) + 1;
         int zSize = 4 + 1;
@@ -79,8 +87,7 @@ public class DensityGeneratorNether
         double[] densityMapArray = new double[xSize * ySize * zSize];
         Map<Biome, double[]> perBiomeDensityMaps = new HashMap<>();
 
-        BiomeProviderNether biomeProvider = (BiomeProviderNether) this.world.getBiomeProvider();
-        BiomeProviderNether.BiomeOverlapPair[] overlapPairs = new BiomeProviderNether.BiomeOverlapPair[xSize * zSize];
+        BiomeOverlapPair[] overlapPairs = new BiomeOverlapPair[xSize * zSize];
 
         // Cache density maps for biome(s)
         int xSizeScale = 16 / xSize;
@@ -89,8 +96,8 @@ public class DensityGeneratorNether
             for (int dz = 0; dz < zSize; dz++) {
                 int iz = dz * xSizeScale + xSizeScale / 2;
                 double temperature = chunk.temperature[ix * 16 + iz];
-                BiomeProviderNether.BiomeOverlapPair overlapPair = overlapPairs[dx * xSize + dz] = new BiomeProviderNether.BiomeOverlapPair();
-                biomeProvider.getOverlap(temperature, overlapPair);
+                BiomeOverlapPair overlapPair = overlapPairs[dx * xSize + dz] = new BiomeOverlapPair();
+                this.getOverlap(temperature, overlapPair);
 
                 if (!perBiomeDensityMaps.containsKey(overlapPair.biomeA)) {
                     perBiomeDensityMaps.put(overlapPair.biomeA, this.densityGeneratorMap.get(overlapPair.biomeA).generateDensityMap(chunk, (int) (terrainHeight * 0.75f), xSize, threeQuarterYSize, zSize, x, y, z));
@@ -106,7 +113,7 @@ public class DensityGeneratorNether
         // Merge density maps
         for (int dx = 0; dx < xSize; dx++) {
             for (int dz = 0; dz < zSize; dz++) {
-                BiomeProviderNether.BiomeOverlapPair overlapPair = overlapPairs[dx * xSize + dz];
+                BiomeOverlapPair overlapPair = overlapPairs[dx * xSize + dz];
                 double[] densityMapA = perBiomeDensityMaps.get(overlapPair.biomeA);
                 double[] densityMapB = null;
                 if (overlapPair.hasOverlap) {
@@ -768,5 +775,91 @@ public class DensityGeneratorNether
         return densityMapArray;
     }
 
+    public void getOverlap(double temperature, BiomeOverlapPair toUpdate) {
+        final float overlapAmount = 1f / (float)(BiomeProviderNether.BIOMES_ORDER.length * 4);
+
+        for (int i = 0; i < BiomeProviderNether.BIOMES_ORDER.length; i++) {
+            // The *strict* bounds of the biome, as used by this::lookupBiome()
+            final float minStrict = (1.0f / BiomeProviderNether.BIOMES_ORDER.length) * i;
+            final float maxStrict = (1.0f / BiomeProviderNether.BIOMES_ORDER.length) * (i + 1);
+            // The outer bounds of the biome, i.e. strict bounds plus overlap amount. If in this range, guaranteed overlap
+            final float minOuter = minStrict - overlapAmount;
+            final float maxOuter = maxStrict + overlapAmount;
+            // The inner bounds of the biome, i.e. strict bounds minus overlap amount. If in this range, guaranteed no overlap
+            final float minInner = minStrict + overlapAmount;
+            final float maxInner = maxStrict - overlapAmount;
+
+            // Edge cases
+            if ((i == 0 && temperature < minInner) ||
+                (i == BiomeProviderNether.BIOMES_ORDER.length - 1 && temperature >= maxInner)
+            ) {
+                toUpdate.hasOverlap = false;
+                toUpdate.biomeA = BiomeProviderNether.BIOMES_ORDER[i];
+                toUpdate.biomeAPercentage = 1.0f;
+                return;
+            }
+
+            // Check if in inner bounds
+            if (temperature >= minInner && temperature < maxInner) {
+                // In inner bounds - only one biome is present here
+                toUpdate.hasOverlap = false;
+                toUpdate.biomeA = BiomeProviderNether.BIOMES_ORDER[i];
+                toUpdate.biomeAPercentage = 1.0f;
+                return;
+            }
+
+            // Check if in outer bounds
+            if (temperature >= minOuter && temperature < maxOuter) {
+                // Check if in min outer bound
+                if (temperature < minInner) {
+                    toUpdate.hasOverlap = true;
+
+                    // Define biomes
+                    toUpdate.biomeA = BiomeProviderNether.BIOMES_ORDER[i - 1];
+                    toUpdate.biomeB = BiomeProviderNether.BIOMES_ORDER[i];
+
+                    // Define percentages
+                    final float range = minInner - minOuter;
+                    // minOuter <= temperature < minInner
+                    temperature -= minOuter; // 0 <= temperature < range
+                    temperature /= range; // 0 <= temperature < 1
+
+                    // Biome A goes to 0.0 as temperature goes to 1.0
+                    // Biome B goes to 1.0 as temperature goes to 1.0
+                    toUpdate.biomeAPercentage = 1.0f - (float) temperature;
+                    toUpdate.biomeBPercentage = (float) temperature;
+
+                    return;
+                }
+
+                // Check if in max outer bound
+                if (temperature >= maxInner) {
+                    toUpdate.hasOverlap = true;
+
+                    // Define biomes
+                    toUpdate.biomeA = BiomeProviderNether.BIOMES_ORDER[i];
+                    toUpdate.biomeB = BiomeProviderNether.BIOMES_ORDER[i + 1];
+
+                    // Define percentages
+                    final float range = maxOuter - maxInner;
+                    // maxInner <= temperature < maxOuter
+                    temperature -= maxInner; // 0 <= temperature < range
+                    temperature /= range; // 0 <= temperature < 1
+
+                    // Biome A goes to 0.0 as temperature goes to 1.0
+                    // Biome B goes to 1.0 as temperature goes to 1.0
+                    toUpdate.biomeAPercentage = 1.0f - (float) temperature;
+                    toUpdate.biomeBPercentage = (float) temperature;
 
+                    return;
+                }
+            }
+        }
+
+        // We should never get here!
+        toUpdate.hasOverlap = false;
+        toUpdate.biomeA = Biomes.NETHER_NETHER;
+        toUpdate.biomeAPercentage = 1.0f;
+        return;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
index 39d364b46..98a4889b0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
@@ -30,8 +30,8 @@ public class SurfaceGeneratorNether
     @Override
     public void generateSurface(@NotNull Chunk chunk, @NotNull ChunkGeneratorResult result) {
         int oceanY = this.world.getWorldType().getOceanY();
-        int minY = this.world.getWorldType().getMinY();
-        int maxY = this.world.getWorldType().getMaxY();
+        int minY = this.world.getWorldType().getMinY(world);
+        int maxY = this.world.getWorldType().getMaxY(world);
         int chunkX = chunk.pos.x;
         int chunkZ = chunk.pos.z;
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
index 616e14710..1e165ed96 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
@@ -33,6 +33,8 @@ public class TerrainGeneratorNether
     private int lastChunkZ = Integer.MIN_VALUE;
     private final @NotNull Noise3D noise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(0L, 4, 0));
     private final double @NotNull [] cache = new double[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z * (Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y)];
+    private final int minY;
+    private final int maxY;
 
     public TerrainGeneratorNether(@NotNull World world) {
         super(world);
@@ -45,6 +47,9 @@ public class TerrainGeneratorNether
         this.fluidLookup.put(Biomes.NETHER_CRYSTAL_FOREST, Blocks.FLUID_WATER_STILL.id());
         this.fluidLookup.put(Biomes.NETHER_ASH_PLAINS, Blocks.OBSIDIAN.id());
         this.fluidLookup.put(Biomes.NETHER_BONEYARD, Blocks.COBBLE_NETHERRACK.id());
+
+        this.minY = world.getWorldType().getMinY(world);
+        this.maxY = world.getWorldType().getMaxY(world);
     }
 
     @Override
@@ -85,11 +90,11 @@ public class TerrainGeneratorNether
         }
 
         WorldType type = this.world.getWorldType();
-        int quarterHeight = type.getMaxY() / 4;
+        int quarterHeight = maxY / 4;
 
         if (y < quarterHeight) {
             return 0;
-        } else if (y >= type.getMaxY() - this.rand.nextInt(5)) {
+        } else if (y >= maxY - this.rand.nextInt(5)) {
             return Blocks.BEDROCK.id();
         }
 //        else if (y >= quarterHeight - rand.nextInt(5) && y <= quarterHeight + 5 - rand.nextInt(5))
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
index a0dbfe1c9..79128fb4b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
@@ -49,8 +49,8 @@ public class ChunkDecoratorOverworld
         int chunkX = chunk.pos.x;
         int chunkZ = chunk.pos.z;
 
-        int minY = this.world.getWorldType().getMinY();
-        int maxY = this.world.getWorldType().getMaxY();
+        int minY = this.world.getWorldType().getMinY(world);
+        int maxY = this.world.getWorldType().getMaxY(world);
         int rangeY = (maxY + 1) - minY;
 
         float oreHeightModifier = rangeY / 128f;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
index 857db278a..87df20399 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
@@ -151,7 +151,7 @@ public class DensityGeneratorOverworld
 
     @Override
     public double @NotNull [] generateDensityMap(@NotNull Chunk chunk) {
-        int terrainHeight = (this.world.getWorldType().getMaxY() + 1) - this.world.getWorldType().getMinY();
+        int terrainHeight = (this.world.getWorldType().getMaxY(world) + 1) - this.world.getWorldType().getMinY(world);
 
         int xSize = 4 + 1;
         int ySize = (terrainHeight / 8) + 1;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
index f9c10f834..07ecdc60e 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
@@ -51,8 +51,8 @@ public class SurfaceGeneratorOverworld
     public void generateSurface(@NotNull Chunk chunk, @NotNull ChunkGeneratorResult result)
     {
         int oceanY = world.getWorldType().getOceanY();
-        int minY = world.getWorldType().getMinY();
-        int maxY = world.getWorldType().getMaxY();
+        int minY = world.getWorldType().getMinY(world);
+        int maxY = world.getWorldType().getMaxY(world);
         int terrainHeight = (maxY + 1) - minY;
         int chunkX = chunk.pos.x;
         int chunkZ = chunk.pos.z;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/TerrainGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/TerrainGeneratorOverworld.java
index 62f3b3300..6c92100ee 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/TerrainGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/TerrainGeneratorOverworld.java
@@ -14,12 +14,16 @@ public class TerrainGeneratorOverworld
     extends TerrainGeneratorLerp
 {
     private final DensityGenerator densityGenerator;
+    private final int minY;
+    private final int maxY;
 
     protected TerrainGeneratorOverworld(@NotNull World world, @NotNull DensityGenerator densityGenerator)
     {
         super(world);
 
         this.densityGenerator = densityGenerator;
+        this.minY = world.getWorldType().getMinY(world);
+        this.maxY = world.getWorldType().getMaxY(world);
     }
 
     public TerrainGeneratorOverworld(@NotNull World world)
@@ -32,7 +36,7 @@ public class TerrainGeneratorOverworld
     {
         WorldType type = this.world.getWorldType();
 
-        if (y <= type.getMinY() + this.rand.nextInt(5))
+        if (y <= minY + this.rand.nextInt(5))
         {
             return Blocks.BEDROCK.id();
         }
@@ -40,7 +44,7 @@ public class TerrainGeneratorOverworld
         {
             return type.getFillerBlockId();
         }
-        else if (y >= type.getMinY() && y < type.getMinY() + type.getOceanY())
+        else if (y >= minY && y < minY + type.getOceanY())
         {
             return type.getOceanBlockId();
         }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
index 9c3ce9602..f2353f4d7 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
@@ -34,8 +34,8 @@ public class ChunkDecoratorOverworldB173
         final int x = chunk.pos.x;
         final int z = chunk.pos.z;
 
-        final int minY = this.world.getWorldType().getMinY();
-        final int maxY = this.world.getWorldType().getMaxY();
+        final int minY = this.world.getWorldType().getMinY(world);
+        final int maxY = this.world.getWorldType().getMaxY(world);
         final int rangeY = (maxY + 1) - minY;
 
         final int wx = x * 16;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkGeneratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkGeneratorOverworldB173.java
index 05bee89e7..316a71b26 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkGeneratorOverworldB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkGeneratorOverworldB173.java
@@ -14,7 +14,7 @@ public class ChunkGeneratorOverworldB173
             new ChunkDecoratorOverworldB173(world),
             new TerrainGeneratorOverworldB173(world),
             new SurfaceGeneratorOverworldB173(world),
-            new LargeFeature[]{new RetroCavesLargeFeature(world.getWorldType().getMinY(), world.getWorldType().getMaxY() + 1)}
+            new LargeFeature[]{new RetroCavesLargeFeature(world.getWorldType().getMinY(world), world.getWorldType().getMaxY(world) + 1)}
         );
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
index f1723b767..f65f70537 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
@@ -232,7 +232,7 @@ public class ChunkDecoratorOverworldHell
         final int worldX = x * 16;
         final int worldZ = z * 16;
 
-        final int minY = world.getWorldType().getMinY();
+        final int minY = world.getWorldType().getMinY(world);
 
         if (world.getBlockId(worldX, minY + world.getWorldType().getOceanY() - 1, worldZ) == world.getWorldType().getOceanBlockId()) {
             world.setBlockWithNotify(worldX, minY + world.getWorldType().getOceanY() - 1, worldZ, world.getWorldType().getOceanBlockId());
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
index dcc1771f2..f0810ce1f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
@@ -42,8 +42,8 @@ public class ChunkDecoratorOverworldRetro
         int chunkX = chunk.pos.x;
         int chunkZ = chunk.pos.z;
 
-        int minY = this.world.getWorldType().getMinY();
-        int maxY = this.world.getWorldType().getMaxY();
+        int minY = this.world.getWorldType().getMinY(world);
+        int maxY = this.world.getWorldType().getMaxY(world);
         int rangeY = (maxY + 1) - minY;
 
         BlockLogicSand.fallInstantly = true;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkGeneratorOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkGeneratorOverworldRetro.java
index f94ecf8f1..7c89dd75b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkGeneratorOverworldRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkGeneratorOverworldRetro.java
@@ -15,7 +15,7 @@ public class ChunkGeneratorOverworldRetro
             new ChunkDecoratorOverworldRetro(world),
             new TerrainGeneratorOverworldRetro(world),
             new SurfaceGeneratorOverworldRetro(world),
-            new LargeFeature[]{new RetroCavesLargeFeature(world.getWorldType().getMinY(), world.getWorldType().getMaxY() + 1)}
+            new LargeFeature[]{new RetroCavesLargeFeature(world.getWorldType().getMinY(world), world.getWorldType().getMaxY(world) + 1)}
         );
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/DimensionData.java b/game/core/src/main/java/net/minecraft/core/world/save/DimensionData.java
index ada53f8b5..09b3ca0db 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/DimensionData.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/DimensionData.java
@@ -1,15 +1,15 @@
 package net.minecraft.core.world.save;
 
 import com.mojang.logging.LogUtils;
-import com.mojang.nbt.tags.ByteTag;
 import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.NbtIo;
-import net.minecraft.core.data.legacy.LegacyWorldTypes;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.settings.SettingNodesValues;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import net.minecraft.core.world.settings.WorldSettingNodes;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypeGroups;
-import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.Weathers;
 import org.jetbrains.annotations.NotNull;
@@ -30,7 +30,15 @@ public class DimensionData {
             worldType = WorldTypeGroups.DEFAULT.get(dimension);
         }
 
-        final @NotNull DimensionData dimensionData = new DimensionData(worldType);
+        final @NotNull SettingNodesValues dimensionSettings;
+        if (tag.containsKey("DimensionSettings")) {
+            final @NotNull CompoundTag dimensionSettingsTag = tag.getCompound("DimensionSettings");
+            dimensionSettings = SettingNodesValues.deserialize(WorldSettingNodes.getRootNode(), dimension, dimensionSettingsTag);
+        } else {
+            dimensionSettings = new SettingNodesValues(WorldSettingNodes.getRootNode(), dimension);
+        }
+
+        final @NotNull DimensionData dimensionData = new DimensionData(worldType, dimensionSettings);
 
         final @NotNull CompoundTag weatherTag = tag.getCompound("Weather");
         dimensionData.weatherCurrentId = weatherTag.getInteger("CurrentID");
@@ -45,6 +53,10 @@ public class DimensionData {
     public static @NotNull CompoundTag toCompoundTag(final @NotNull DimensionData dimensionData, final @NotNull CompoundTag out) {
         out.putString("WorldType", Objects.requireNonNull(Registries.WORLD_TYPES.getKey(dimensionData.worldType)));
 
+        final @NotNull CompoundTag dimensionSettingsTag = new CompoundTag();
+        SettingNodesValues.serialize(dimensionData.dimensionSettings, dimensionSettingsTag);
+        out.put("DimensionSettings", dimensionSettingsTag);
+
         final @NotNull CompoundTag weatherTag = new CompoundTag();
         weatherTag.putInt("CurrentID", dimensionData.weatherCurrentId);
         weatherTag.putInt("NextID", dimensionData.weatherNextId);
@@ -85,21 +97,35 @@ public class DimensionData {
     }
 
     private final @NotNull WorldType worldType;
+    private final @NotNull SettingNodesValues dimensionSettings;
     private int weatherCurrentId = -1;
     private int weatherNextId = -1;
     private long weatherDuration;
     private float weatherIntensity;
     private float weatherPower;
 
-    public DimensionData(
-        final @NotNull WorldType worldType
+    private DimensionData(
+        final @NotNull WorldType worldType,
+        final @NotNull SettingNodesValues dimensionSettings
     ) {
         this.worldType = worldType;
+        this.dimensionSettings = dimensionSettings;
     }
 
-    public DimensionData(final @NotNull DimensionData dimensionData) {
-        this(dimensionData.worldType);
+    public DimensionData(
+        final @NotNull Dimension dimension,
+        final @NotNull WorldConfiguration worldConfiguration
+    ) {
+        this(
+            worldConfiguration.getWorldTypeGroup().get(dimension),
+            worldConfiguration.getDimensionSettings(dimension)
+        );
+    }
 
+    public DimensionData(final @NotNull DimensionData dimensionData, final @NotNull Dimension dimension) {
+        this.worldType = dimensionData.worldType;
+        this.dimensionSettings = new SettingNodesValues(WorldSettingNodes.getRootNode(), dimension);
+        this.dimensionSettings.setAll(dimensionData.dimensionSettings);
         this.weatherCurrentId = dimensionData.weatherCurrentId;
         this.weatherNextId = dimensionData.weatherNextId;
         this.weatherDuration = dimensionData.weatherDuration;
@@ -111,6 +137,10 @@ public class DimensionData {
         return this.worldType;
     }
 
+    public @NotNull SettingNodesValues getDimensionSettings() {
+        return this.dimensionSettings;
+    }
+
     public @Nullable Weather getCurrentWeather() {
         if (this.weatherCurrentId < 0) {
             return null;
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/LevelData.java b/game/core/src/main/java/net/minecraft/core/world/save/LevelData.java
index b33218d76..76247fd7c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/LevelData.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/LevelData.java
@@ -7,6 +7,7 @@ import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.NbtIo;
 import net.minecraft.core.world.config.spawning.SpawnerConfig;
 import net.minecraft.core.world.pos.TilePos;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -19,13 +20,13 @@ import java.util.UUID;
 public class LevelData {
     private static final @NotNull Logger LOGGER = LogUtils.getLogger();
 
-    public static @NotNull LevelData fromCompoundTag(final @NotNull CompoundTag tag) {
+    public static @NotNull LevelData deserialize(final @NotNull CompoundTag tag) {
         final long randomSeed = tag.getLong("RandomSeed");
         final @NotNull String levelName = tag.getString("LevelName");
 
         final @NotNull GameRuleCollection gameRules;
         if (tag.containsKey("GameRules")) {
-            final CompoundTag gameRulesTag = tag.getCompound("GameRules");
+            final @NotNull CompoundTag gameRulesTag = tag.getCompound("GameRules");
             gameRules = GameRuleCollection.readFromNBT(gameRulesTag);
         } else {
             gameRules = new GameRuleCollection();
@@ -33,8 +34,8 @@ public class LevelData {
 
         final @NotNull SpawnerConfig spawnerConfig;
         if (tag.containsKey("SpawnConfig")) {
-            final CompoundTag spawnConfigTag = tag.getCompound("SpawnConfig");
-            spawnerConfig = SpawnerConfig.createFromTag(spawnConfigTag);
+            final @NotNull CompoundTag spawnerConfigTag = tag.getCompound("SpawnConfig");
+            spawnerConfig = SpawnerConfig.createFromTag(spawnerConfigTag);
         } else {
             spawnerConfig = new SpawnerConfig();
         }
@@ -70,7 +71,7 @@ public class LevelData {
         return data;
     }
 
-    public static @NotNull CompoundTag toCompoundTag(final @NotNull LevelData levelData, final @NotNull CompoundTag out) {
+    public static @NotNull CompoundTag serialize(final @NotNull LevelData levelData, final @NotNull CompoundTag out) {
         out.putLong("RandomSeed", levelData.randomSeed);
         out.putInt("SpawnX", levelData.spawnPos.x);
         out.putInt("SpawnY", levelData.spawnPos.y);
@@ -84,7 +85,7 @@ public class LevelData {
         out.putInt("Difficulty", levelData.difficulty.id());
         out.putBoolean("DifficultyLock", levelData.difficultyLocked);
 
-        final CompoundTag gameRulesTag = new CompoundTag();
+        final @NotNull CompoundTag gameRulesTag = new CompoundTag();
         GameRuleCollection.writeToNBT(gameRulesTag, levelData.gameRules);
         out.put("GameRules", gameRulesTag);
 
@@ -92,7 +93,7 @@ public class LevelData {
             out.putString("LastPlayerUUID", levelData.lastPlayerUUID.toString());
         }
 
-        final CompoundTag spawnerConfigTag = new CompoundTag();
+        final @NotNull CompoundTag spawnerConfigTag = new CompoundTag();
         levelData.spawnerConfig.writeToTag(spawnerConfigTag);
         out.put("SpawnConfig", spawnerConfigTag);
 
@@ -118,7 +119,7 @@ public class LevelData {
         }
 
         if (nbtRootData != null) {
-            return LevelData.fromCompoundTag(nbtRootData);
+            return LevelData.deserialize(nbtRootData);
         } else {
             throw new IOException();
         }
@@ -166,17 +167,15 @@ public class LevelData {
         );
     }
 
-    public LevelData(
-        final long randomSeed,
-        final @NotNull String name,
-        final @NotNull GameRuleCollection gameRules
-    ) {
+    public LevelData(final @NotNull WorldConfiguration worldConfiguration) {
         this(
-            randomSeed,
-            name,
-            gameRules,
-            new SpawnerConfig()
+            worldConfiguration.getFinalNumericSeed(),
+            worldConfiguration.getFinalWorldName(),
+            worldConfiguration.getGameRules(),
+            worldConfiguration.getSpawnerConfig()
         );
+
+        this.setCheatsEnabled(worldConfiguration.getCheatsEnabled());
     }
 
     public LevelData(final @NotNull LevelData levelData) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/LevelStorageBase.java b/game/core/src/main/java/net/minecraft/core/world/save/LevelStorageBase.java
index 672b374c2..69fa2e715 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/LevelStorageBase.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/LevelStorageBase.java
@@ -123,7 +123,7 @@ public abstract class LevelStorageBase implements LevelStorage
 	@Override
 	public void saveLevelDataAndPlayerData(@NotNull LevelData levelData, @NotNull List<Player> playerList)
 	{
-		CompoundTag dataTag = LevelData.toCompoundTag(levelData, new CompoundTag());
+		CompoundTag dataTag = LevelData.serialize(levelData, new CompoundTag());
 		CompoundTag savedTag = new CompoundTag();
 		savedTag.put("Data", dataTag);
 		try
@@ -166,7 +166,7 @@ public abstract class LevelStorageBase implements LevelStorage
 	@Override
 	public void saveLevelData(@NotNull LevelData levelData)
 	{
-		saveLevelDataRaw(LevelData.toCompoundTag(levelData, new CompoundTag()));
+		saveLevelDataRaw(LevelData.serialize(levelData, new CompoundTag()));
 	}
 
 	@Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/SaveFormatBase.java b/game/core/src/main/java/net/minecraft/core/world/save/SaveFormatBase.java
index 3f8a8fadc..7660a31f3 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/SaveFormatBase.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/SaveFormatBase.java
@@ -38,7 +38,7 @@ public abstract class SaveFormatBase
     {
         CompoundTag tag = getLevelDataRaw(worldDirName);
         if (tag == null) return null;
-        return LevelData.fromCompoundTag(tag);
+        return LevelData.deserialize(tag);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/WorldConfigurationReader.java b/game/core/src/main/java/net/minecraft/core/world/save/WorldConfigurationReader.java
new file mode 100644
index 000000000..3dfa9c8b6
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/save/WorldConfigurationReader.java
@@ -0,0 +1,24 @@
+package net.minecraft.core.world.save;
+
+import net.minecraft.core.data.gamerule.GameRuleCollection;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.config.spawning.SpawnerConfig;
+import net.minecraft.core.world.settings.SettingNodesValues;
+import net.minecraft.core.world.type.WorldType;
+import org.jetbrains.annotations.NotNull;
+
+public interface WorldConfigurationReader {
+    long getFinalNumericSeed();
+
+    @NotNull String getFinalWorldName();
+
+    @NotNull GameRuleCollection getGameRules();
+
+    @NotNull SpawnerConfig getSpawnerConfig();
+
+    boolean getCheatsEnabled();
+
+    @NotNull WorldType getWorldType(final @NotNull Dimension dimension);
+
+    @NotNull SettingNodesValues getDimensionSettings(final @NotNull Dimension dimension);
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19133To19134.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19133To19134.java
index 516e62308..297412ccc 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19133To19134.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19133To19134.java
@@ -3,11 +3,16 @@ package net.minecraft.core.world.save.conversion;
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.data.legacy.LegacyWorldTypes;
+import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.ProgressListener;
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.save.DimensionData;
 import net.minecraft.core.world.save.ISaveFormat;
 import net.minecraft.core.world.save.SaveFormats;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import net.minecraft.core.world.type.WorldTypeGroups;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 
@@ -71,11 +76,25 @@ public class SaveConverter19133To19134
                 if (worldTypes != null)
                 {
                     int worldType = worldTypes[dim.id];
-                    dimensionData = new DimensionData(LegacyWorldTypes.getWorldTypeById(worldType));
+                    final @NotNull WorldConfiguration worldConfiguration = new WorldConfiguration();
+                    for (final @NotNull WorldTypeGroups.Group group : WorldTypeGroups.GROUPS) {
+                        if (group.get(dim).equals(Registries.WORLD_TYPES.getItemByNumericId(worldType))) {
+                            worldConfiguration.setWorldTypeGroup(group);
+                            break;
+                        }
+                    }
+                    dimensionData = new DimensionData(dim, worldConfiguration);
                 }
                 else
                 {
-                    dimensionData = new DimensionData(dim.defaultWorldType);
+                    final @NotNull WorldConfiguration worldConfiguration = new WorldConfiguration();
+                    for (final @NotNull WorldTypeGroups.Group group : WorldTypeGroups.GROUPS) {
+                        if (group.get(dim).equals(dim.defaultWorldType)) {
+                            worldConfiguration.setWorldTypeGroup(group);
+                            break;
+                        }
+                    }
+                    dimensionData = new DimensionData(dim, worldConfiguration);
                 }
                 toFormat.getLevelStorage(worldDirName, false).saveDimensionData(dim.id, dimensionData);
             }
diff --git a/game/core/src/main/java/net/minecraft/core/world/season/Season.java b/game/core/src/main/java/net/minecraft/core/world/season/Season.java
index c7cbfc2ba..988048e36 100644
--- a/game/core/src/main/java/net/minecraft/core/world/season/Season.java
+++ b/game/core/src/main/java/net/minecraft/core/world/season/Season.java
@@ -37,9 +37,8 @@ public abstract class Season
 		this.hasDeeperSnow = hasDeeperSnow;
 	}
 
-	public String getId()
-	{
-		return id;
+	public @NotNull String getId() {
+		return this.id;
 	}
 
 	public @NotNull String getLanguageKey() {
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/ContainerSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/ContainerSettingNode.java
index 7f84c0905..b2e94e477 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/ContainerSettingNode.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/ContainerSettingNode.java
@@ -1,5 +1,7 @@
 package net.minecraft.core.world.settings;
 
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import org.jetbrains.annotations.NotNull;
 
 public class ContainerSettingNode implements SettingNode {
@@ -10,6 +12,17 @@ public class ContainerSettingNode implements SettingNode {
         this.childrenProvider = childrenProvider;
     }
 
+    @Override
+    public @NotNull SettingNode withChild(final @NotNull SettingNode child) {
+        if (!(this.childrenProvider instanceof final @NotNull ListSettingNodeChildrenProvider childrenProvider)) {
+            throw new RuntimeException("Incorrect child provider to manually add child!");
+        }
+
+        childrenProvider.withChild(child);
+
+        return this;
+    }
+
     public final @NotNull ContainerSettingNode withVisibilityListener(final @NotNull SettingNodeVisibilityListener visibilityListener) {
         this.visibilityListener = visibilityListener;
 
@@ -22,12 +35,12 @@ public class ContainerSettingNode implements SettingNode {
     }
 
     @Override
-    public boolean isVisible(final @NotNull WorldConfiguration worldConfiguration) {
-        return this.visibilityListener.isVisible(worldConfiguration);
+    public boolean isVisible(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.visibilityListener.isVisible(config);
     }
 
     @Override
-    public boolean areChildrenVisible(final @NotNull WorldConfiguration worldConfiguration) {
-        return this.visibilityListener.isVisible(worldConfiguration);
+    public boolean areChildrenVisible(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.visibilityListener.isVisible(config);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/DefaultSettingNodes.java b/game/core/src/main/java/net/minecraft/core/world/settings/DefaultSettingNodes.java
deleted file mode 100644
index 80b4b8650..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/settings/DefaultSettingNodes.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.minecraft.core.world.settings;
-
-import net.minecraft.core.lang.text.TranslatableText;
-import net.minecraft.core.world.season.Seasons;
-import net.minecraft.core.world.settings.impl.SeasonSettingNode;
-import org.jetbrains.annotations.NotNull;
-
-public final class DefaultSettingNodes {
-    private DefaultSettingNodes() throws IllegalAccessException {
-        throw new IllegalAccessException("No DefaultSettingNodes for you!");
-    }
-
-    private static final @NotNull SettingNode ROOT_NODE;
-    static {
-        ROOT_NODE = new ContainerSettingNode(
-            new ListSettingNodeChildrenProvider()
-                .withChildren(
-                    new SeasonSettingNode("minecraft:world_settings/single_season", new TranslatableText("world_settings.single_season.name"), SeasonSettingNode.DISABLED)
-                        .withValue(new SeasonSettingNode.SeasonEntry(Seasons.OVERWORLD_SPRING))
-                        .withValue(new SeasonSettingNode.SeasonEntry(Seasons.OVERWORLD_SUMMER))
-                        .withValue(new SeasonSettingNode.SeasonEntry(Seasons.OVERWORLD_FALL))
-                        .withValue(new SeasonSettingNode.SeasonEntry(Seasons.OVERWORLD_WINTER))
-                        .withValue(new SeasonSettingNode.SeasonEntry(Seasons.OVERWORLD_WINTER_ENDLESS))
-                )
-        );
-    }
-
-    public static @NotNull SettingNode getRootNode() {
-        return ROOT_NODE;
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/EnumValueGenericSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/EnumValueGenericSettingNode.java
deleted file mode 100644
index 1a5e312d4..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/settings/EnumValueGenericSettingNode.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.minecraft.core.world.settings;
-
-import net.minecraft.core.lang.text.IntoText;
-import net.minecraft.core.lang.text.Text;
-import org.jetbrains.annotations.NotNull;
-
-public class EnumValueGenericSettingNode<T extends Enum<T> & IntoText> extends ValueGenericSettingNode<T> {
-    public EnumValueGenericSettingNode(final @NotNull String key, final @NotNull Text name, final @NotNull T value) {
-        super(key, name, value);
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/GenericSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/GenericSettingNode.java
index 58cabe811..79ff8a9ba 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/GenericSettingNode.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/GenericSettingNode.java
@@ -1,5 +1,7 @@
 package net.minecraft.core.world.settings;
 
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -7,7 +9,6 @@ public abstract class GenericSettingNode implements KeyedSettingNode {
     private final @NotNull String key;
     private @Nullable SettingNodeChildrenProvider childrenProvider = null;
     private @NotNull SettingNodeVisibilityListener selfVisibilityListener = SettingNodeVisibilityListener::alwaysVisible;
-    private @NotNull SettingNodeVisibilityListener childrenVisibilityListener = SettingNodeVisibilityListener::alwaysVisible;
 
     public GenericSettingNode(final @NotNull String key) {
         this.key = key;
@@ -15,6 +16,22 @@ public abstract class GenericSettingNode implements KeyedSettingNode {
         KeyedSettingNode.checkKeyIsUnique(key);
     }
 
+    @Override
+    public @NotNull SettingNode withChild(final @NotNull SettingNode child) {
+        if (this.childrenProvider != null && !(this.childrenProvider instanceof ListSettingNodeChildrenProvider)) {
+            throw new RuntimeException("Incorrect child provider to manually add child!");
+        }
+
+        if (this.childrenProvider == null) {
+            this.childrenProvider = new ListSettingNodeChildrenProvider();
+        }
+
+        final @NotNull ListSettingNodeChildrenProvider childrenProvider = (ListSettingNodeChildrenProvider) this.childrenProvider;
+        childrenProvider.withChild(child);
+
+        return this;
+    }
+
     @Override
     public @NotNull String getKey() {
         return this.key;
@@ -32,8 +49,8 @@ public abstract class GenericSettingNode implements KeyedSettingNode {
     }
 
     @Override
-    public boolean isVisible(final @NotNull WorldConfiguration worldConfiguration) {
-        return this.selfVisibilityListener.isVisible(worldConfiguration);
+    public boolean isVisible(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.selfVisibilityListener.isVisible(config);
     }
 
     public final @NotNull GenericSettingNode withVisibilityListener(final @NotNull SettingNodeVisibilityListener visibilityListener) {
@@ -41,15 +58,4 @@ public abstract class GenericSettingNode implements KeyedSettingNode {
 
         return this;
     }
-
-    @Override
-    public boolean areChildrenVisible(final @NotNull WorldConfiguration worldConfiguration) {
-        return this.isVisible(worldConfiguration) && this.childrenVisibilityListener.isVisible(worldConfiguration);
-    }
-
-    public final @NotNull GenericSettingNode withChildrenVisibilityListener(final @NotNull SettingNodeVisibilityListener visibilityListener) {
-        this.childrenVisibilityListener = visibilityListener;
-
-        return this;
-    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/ListSettingNodeChildrenProvider.java b/game/core/src/main/java/net/minecraft/core/world/settings/ListSettingNodeChildrenProvider.java
index 77dbd7164..bac434eaa 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/ListSettingNodeChildrenProvider.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/ListSettingNodeChildrenProvider.java
@@ -15,17 +15,12 @@ public class ListSettingNodeChildrenProvider implements SettingNodeChildrenProvi
     private final @NotNull Map<@NotNull String, @NotNull KeyedSettingNode> keyedChildren = new Object2ObjectOpenHashMap<>();
 
     @Override
-    public int length(final @NotNull WorldConfiguration worldConfiguration) {
+    public int length() {
         return this.children.size();
     }
 
     @Override
-    public @NotNull Iterator<@NotNull SettingNode> getChildren(final @NotNull WorldConfiguration worldConfiguration) {
-        return this.children.iterator();
-    }
-
-    @Override
-    public @Nullable KeyedSettingNode getChildByKey(final @NotNull String key, final @NotNull WorldConfiguration worldConfiguration) {
+    public @Nullable KeyedSettingNode getChildByKey(final @NotNull String key) {
         return this.keyedChildren.get(key);
     }
 
@@ -45,4 +40,9 @@ public class ListSettingNodeChildrenProvider implements SettingNodeChildrenProvi
 
         return this;
     }
+
+    @Override
+    public @NotNull Iterator<@NotNull SettingNode> iterator() {
+        return this.children.iterator();
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/ListValueGenericSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/ListValueGenericSettingNode.java
deleted file mode 100644
index e2f31436f..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/settings/ListValueGenericSettingNode.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.minecraft.core.world.settings;
-
-import it.unimi.dsi.fastutil.objects.ObjectArrayList;
-import net.minecraft.core.lang.text.IntoText;
-import net.minecraft.core.lang.text.Text;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-public class ListValueGenericSettingNode<T extends IntoText> extends ValueGenericSettingNode<T> {
-    private final @NotNull List<@NotNull T> values = new ObjectArrayList<>();
-
-    public ListValueGenericSettingNode(final @NotNull String key, final @NotNull Text name, final @NotNull T defaultValue) {
-        super(key, name, defaultValue);
-
-        this.values.add(defaultValue);
-    }
-
-    public @NotNull List<T> getValues() {
-        return this.values;
-    }
-
-    public @NotNull ListValueGenericSettingNode<T> withValue(final @NotNull T value) {
-        this.values.add(value);
-
-        return this;
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/ListValueSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/ListValueSettingNode.java
new file mode 100644
index 000000000..845caf35e
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/ListValueSettingNode.java
@@ -0,0 +1,16 @@
+package net.minecraft.core.world.settings;
+
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public interface ListValueSettingNode<T> extends ValueSettingNode<T> {
+    @NotNull List<@NotNull T> getValues(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config);
+
+    @Override
+    default boolean validateValue(final @NotNull T value, final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.getValues(dimension, config).contains(value);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/PercentageValueGenericSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/PercentageValueGenericSettingNode.java
deleted file mode 100644
index 61ce58557..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/settings/PercentageValueGenericSettingNode.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.minecraft.core.world.settings;
-
-import net.minecraft.core.lang.text.LiteralText;
-import net.minecraft.core.lang.text.Text;
-import org.jetbrains.annotations.NotNull;
-
-public class PercentageValueGenericSettingNode extends ValueGenericSettingNode<@NotNull Float> implements RangeValueSettingNode<@NotNull Float> {
-    public PercentageValueGenericSettingNode(final @NotNull String key, final @NotNull Text name, final float defaultValue) {
-        super(key, name, defaultValue);
-    }
-
-    @Override
-    public @NotNull Float getMinimum(final @NotNull WorldConfiguration worldConfiguration) {
-        return 0.0f;
-    }
-
-    @Override
-    public @NotNull Float getMaximum(final @NotNull WorldConfiguration worldConfiguration) {
-        return 1.0f;
-    }
-
-    @Override
-    public @NotNull Text getValueText(final @NotNull Float value) {
-        return new LiteralText((int)(value * 100.0) + "%");
-    }
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/RangeValueSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/RangeValueSettingNode.java
index 324ae2e89..134fc3899 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/RangeValueSettingNode.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/RangeValueSettingNode.java
@@ -1,8 +1,10 @@
 package net.minecraft.core.world.settings;
 
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import org.jetbrains.annotations.NotNull;
 
 public interface RangeValueSettingNode<T> extends ValueSettingNode<T> {
-    @NotNull T getMinimum(final @NotNull WorldConfiguration worldConfiguration);
-    @NotNull T getMaximum(final @NotNull WorldConfiguration worldConfiguration);
+    @NotNull T getMinimumValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config);
+    @NotNull T getMaximumValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config);
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNode.java
index b7811ee47..dd7b435c6 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNode.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNode.java
@@ -1,28 +1,29 @@
 package net.minecraft.core.world.settings;
 
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Iterator;
-
 public interface SettingNode {
     @Nullable SettingNodeChildrenProvider getChildrenProvider();
 
-    boolean isVisible(final @NotNull WorldConfiguration worldConfiguration);
+    boolean isVisible(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config);
+
+    boolean areChildrenVisible(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config);
 
-    boolean areChildrenVisible(final @NotNull WorldConfiguration worldConfiguration);
+    @NotNull SettingNode withChild(final @NotNull SettingNode child);
 
-    default @Nullable KeyedSettingNode getChildByKey(final @NotNull String key, final @NotNull WorldConfiguration worldConfiguration) {
+    default @Nullable KeyedSettingNode getChildByKey(final @NotNull String key) {
         final @Nullable SettingNodeChildrenProvider childrenProvider = this.getChildrenProvider();
         if (childrenProvider != null) {
-            final @Nullable KeyedSettingNode myChild = childrenProvider.getChildByKey(key, worldConfiguration);
+            final @Nullable KeyedSettingNode myChild = childrenProvider.getChildByKey(key);
             if (myChild != null) {
                 return myChild;
             }
-            
-            for (final @NotNull Iterator<@NotNull SettingNode> it = childrenProvider.getChildren(worldConfiguration); it.hasNext(); ) {
-                final @NotNull SettingNode child = it.next();
-                final @Nullable KeyedSettingNode childsChild = child.getChildByKey(key, worldConfiguration); // recursion here
+
+            for (final @NotNull SettingNode child : childrenProvider) {
+                final @Nullable KeyedSettingNode childsChild = child.getChildByKey(key); // recursion here
                 if (childsChild != null) {
                     return childsChild;
                 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeChildrenProvider.java b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeChildrenProvider.java
index c5794c923..83094c5c0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeChildrenProvider.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeChildrenProvider.java
@@ -5,10 +5,8 @@ import org.jetbrains.annotations.Nullable;
 
 import java.util.Iterator;
 
-public interface SettingNodeChildrenProvider {
-    int length(final @NotNull WorldConfiguration worldConfiguration);
+public interface SettingNodeChildrenProvider extends Iterable<@NotNull SettingNode> {
+    int length();
 
-    @NotNull Iterator<@NotNull SettingNode> getChildren(final @NotNull WorldConfiguration worldConfiguration);
-
-    @Nullable KeyedSettingNode getChildByKey(final @NotNull String key, final @NotNull WorldConfiguration worldConfiguration);
+    @Nullable KeyedSettingNode getChildByKey(final @NotNull String key);
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeList.java b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeList.java
deleted file mode 100644
index a7fb4c0f2..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeList.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package net.minecraft.core.world.settings;
-
-public class SettingNodeList {
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeVisibilityListener.java b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeVisibilityListener.java
index d62f53896..05a6c0820 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeVisibilityListener.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodeVisibilityListener.java
@@ -1,17 +1,18 @@
 package net.minecraft.core.world.settings;
 
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import org.jetbrains.annotations.NotNull;
 
 public interface SettingNodeVisibilityListener {
-    boolean isVisible(final @NotNull WorldConfiguration worldConfiguration);
+    boolean isVisible(final @NotNull WorldConfigurationReader config);
 
     @SuppressWarnings("unused")
-    static boolean alwaysVisible(final @NotNull WorldConfiguration worldConfiguration) {
+    static boolean alwaysVisible(final @NotNull WorldConfigurationReader config) {
         return true;
     }
 
     @SuppressWarnings("unused")
-    static boolean neverVisible(final @NotNull WorldConfiguration worldConfiguration) {
+    static boolean neverVisible(final @NotNull WorldConfigurationReader config) {
         return false;
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodesValues.java b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodesValues.java
index 558498999..41ca5a927 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodesValues.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/SettingNodesValues.java
@@ -1,18 +1,85 @@
 package net.minecraft.core.world.settings;
 
+import com.mojang.logging.LogUtils;
+import com.mojang.nbt.tags.CompoundTag;
+import com.mojang.nbt.tags.Tag;
 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
 
 import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.zip.DataFormatException;
 
 public class SettingNodesValues {
+    private static final @NotNull Logger LOGGER = LogUtils.getLogger();
+
+    @SuppressWarnings("unchecked")
+    public static @NotNull CompoundTag serialize(final @NotNull SettingNodesValues values, final @NotNull CompoundTag out) {
+        values.keyedNodeValues.forEach((key, value) -> {
+            final @NotNull ValueSettingNode<Object> nodeAsObject = (ValueSettingNode<Object>) key;
+            out.put(key.getKey(), nodeAsObject.serializeValue(value));
+        });
+
+        return out;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static @NotNull SettingNodesValues deserialize(final @NotNull SettingNode rootNode, final @NotNull Dimension dimension, final @NotNull CompoundTag in) {
+        final @NotNull SettingNodesValues settingNodesValues = new SettingNodesValues(rootNode, dimension);
+
+        for (final @NotNull Tag<?> tag : in.getValues()) {
+            final @NotNull String tagName = tag.getTagName();
+            final @Nullable SettingNode node = rootNode.getChildByKey(tagName);
+
+            if (node instanceof final @NotNull ValueSettingNode<?> objectValueNode) {
+                try {
+                    final @Nullable Object value = objectValueNode.deserializeValue(tag);
+                    settingNodesValues.setNodeValue((ValueSettingNode<Object>) objectValueNode, value);
+                } catch (final @NotNull DataFormatException e) {
+                    LOGGER.warn("Threw exception while deserializing setting node", e);
+                }
+            }
+        }
+
+        return settingNodesValues;
+    }
+
     private final @NotNull SettingNode rootNode;
+    private final @NotNull Dimension dimension;
     private final @NotNull Map<@NotNull ValueSettingNode<?>, @NotNull Object> keyedNodeValues = new Object2ObjectOpenHashMap<>();
     private final @NotNull Map<@NotNull String, @NotNull ValueSettingNode<?>> nodesByKey = new Object2ObjectOpenHashMap<>();
 
-    public SettingNodesValues(final @NotNull SettingNode rootNode) {
+    private boolean notificationsSuppressed = false;
+    private @Nullable WorldConfiguration.ChangeListener changeListener;
+
+    public SettingNodesValues(final @NotNull SettingNode rootNode, final @NotNull Dimension dimension) {
         this.rootNode = rootNode;
+        this.dimension = dimension;
+    }
+
+    public void setChangeListener(final @Nullable WorldConfiguration.ChangeListener changeListener) {
+        this.changeListener = changeListener;
+    }
+
+    private void notifyChanged() {
+        if (this.changeListener != null && !this.notificationsSuppressed) {
+            this.changeListener.onChanged();
+        }
+    }
+
+    public void setAll(final @NotNull SettingNodesValues src) {
+        this.keyedNodeValues.clear();
+        this.nodesByKey.clear();
+
+        for (final @NotNull ValueSettingNode<?> node : src.keyedNodeValues.keySet()) {
+            this.keyedNodeValues.put(node, Objects.requireNonNull(src.keyedNodeValues.get(node)));
+            this.nodesByKey.put(node.getKey(), node);
+        }
     }
 
     public @NotNull SettingNode getRootNode() {
@@ -20,24 +87,45 @@ public class SettingNodesValues {
     }
 
     @SuppressWarnings("unchecked")
-    public <T> @NotNull T getNodeValue(final @NotNull ValueSettingNode<T> node) {
-        final @Nullable T value = (T) this.keyedNodeValues.get(node);
-        if (value != null) {
-            return value;
+    public <T> @NotNull T getNodeValue(final @NotNull ValueSettingNode<T> node, final @NotNull WorldConfigurationReader worldConfigurationReader) {
+        if (!this.keyedNodeValues.containsKey(node)) {
+            this.keyedNodeValues.put(node, node.getDefaultValue(this.dimension, worldConfigurationReader));
         }
+        return (T) Objects.requireNonNull(this.keyedNodeValues.get(node));
+    }
 
-        final @NotNull T defaultValue = node.getDefaultValue();
-        this.keyedNodeValues.put(node, node.getDefaultValue());
-        this.nodesByKey.put(node.getKey(), node);
+    @SuppressWarnings("unchecked")
+    public <T> @NotNull T getNodeValueOr(final @NotNull ValueSettingNode<T> node, final @NotNull T or) {
+        if (!this.keyedNodeValues.containsKey(node)) {
+            return or;
+        }
+        return (T) Objects.requireNonNull(this.keyedNodeValues.get(node));
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> @NotNull T getNodeValue(final @NotNull String key, final @NotNull Class<T> valueClass, final @NotNull WorldConfigurationReader worldConfigurationReader) {
+        @Nullable ValueSettingNode<?> node = this.nodesByKey.get(key);
+        if (node == null) {
+            final @Nullable KeyedSettingNode keyedSettingNode = this.rootNode.getChildByKey(key);
+            if (keyedSettingNode instanceof final @NotNull ValueSettingNode<?> nodeByKeyFromRoot) {
+                node = nodeByKeyFromRoot;
+            } else {
+                throw new IllegalArgumentException("Node does not have a value!");
+            }
+        }
 
-        return defaultValue;
+        if (!(valueClass.isAssignableFrom(node.getValueClass()))) {
+            throw new IllegalArgumentException("Node type " + node.getValueClass().getSimpleName() + " does not equal requested type " + valueClass.getSimpleName() + "!");
+        }
+
+        return (T) this.getNodeValue(node, worldConfigurationReader);
     }
 
     @SuppressWarnings("unchecked")
-    public <T> @NotNull T getNodeValue(final @NotNull String key, final @NotNull Class<T> valueClass, final @NotNull WorldConfiguration worldConfiguration) {
+    public <T> @NotNull T getNodeValueOr(final @NotNull String key, final @NotNull Class<T> valueClass, final @NotNull T or) {
         @Nullable ValueSettingNode<?> node = this.nodesByKey.get(key);
         if (node == null) {
-            final @Nullable KeyedSettingNode keyedSettingNode = this.rootNode.getChildByKey(key, worldConfiguration);
+            final @Nullable KeyedSettingNode keyedSettingNode = this.rootNode.getChildByKey(key);
             if (keyedSettingNode instanceof final @NotNull ValueSettingNode<?> nodeByKeyFromRoot) {
                 node = nodeByKeyFromRoot;
             } else {
@@ -49,19 +137,20 @@ public class SettingNodesValues {
             throw new IllegalArgumentException("Node type " + node.getValueClass().getSimpleName() + " does not equal requested type " + valueClass.getSimpleName() + "!");
         }
 
-        return (T) this.getNodeValue(node);
+        return (T) this.getNodeValueOr((ValueSettingNode<? super T>) node, or);
     }
 
     public <T> void setNodeValue(final @NotNull ValueSettingNode<T> node, final @NotNull T value) {
         this.keyedNodeValues.put(node, value);
         this.nodesByKey.put(node.getKey(), node);
+        this.notifyChanged();
     }
 
     @SuppressWarnings("unchecked")
-    public <T> void setNodeValue(final @NotNull String key, final @NotNull T value, final @NotNull WorldConfiguration worldConfiguration) {
+    public <T> void setNodeValue(final @NotNull String key, final @NotNull T value) {
         @Nullable ValueSettingNode<?> node = this.nodesByKey.get(key);
         if (node == null) {
-            final @Nullable KeyedSettingNode keyedSettingNode = this.rootNode.getChildByKey(key, worldConfiguration);
+            final @Nullable KeyedSettingNode keyedSettingNode = this.rootNode.getChildByKey(key);
             if (keyedSettingNode instanceof final @NotNull ValueSettingNode<?> nodeByKeyFromRoot) {
                 node = nodeByKeyFromRoot;
             } else {
@@ -75,4 +164,10 @@ public class SettingNodesValues {
 
         this.setNodeValue((ValueSettingNode<T>) node, value);
     }
+
+    public void withNotificationsSuppressed(final @NotNull Consumer<@NotNull SettingNodesValues> consumer) {
+        this.notificationsSuppressed = true;
+        consumer.accept(this);
+        this.notificationsSuppressed = false;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/ValueGenericSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/ValueGenericSettingNode.java
index 6ec1dc0a2..11a6ca604 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/ValueGenericSettingNode.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/ValueGenericSettingNode.java
@@ -1,45 +1,42 @@
 package net.minecraft.core.world.settings;
 
-import net.minecraft.core.lang.text.IntoText;
-import net.minecraft.core.lang.text.LiteralText;
 import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.Objects;
-
-public class ValueGenericSettingNode<T> extends GenericSettingNode implements ValueSettingNode<T> {
+public abstract class ValueGenericSettingNode<T> extends GenericSettingNode implements ValueSettingNode<T> {
     private final @NotNull Text name;
-    private final @NotNull T value;
+    private final @NotNull Class<@NotNull T> valueClass;
+
+    private @NotNull ValueSettingNodeVisibilityListener<T> childrenVisibilityListener = ValueSettingNodeVisibilityListener::alwaysVisible;
 
-    public ValueGenericSettingNode(final @NotNull String key, final @NotNull Text name, final @NotNull T defaultValue) {
+    @SuppressWarnings("unchecked")
+    public ValueGenericSettingNode(final @NotNull String key, final @NotNull Text name, final @NotNull Class<T> valueClass) {
         super(key);
 
         this.name = name;
-        this.value = defaultValue;
+        this.valueClass = valueClass;
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public @NotNull Class<@NotNull T> getValueClass() {
-        return (Class<@NotNull T>) this.value.getClass();
+        return this.valueClass;
     }
 
     @Override
-    public final @NotNull T getDefaultValue() {
-        return this.value;
+    public @NotNull Text getName() {
+        return this.name;
     }
 
-    @Override
-    public @NotNull Text getValueText(final @NotNull T value) {
-        if (value instanceof final @NotNull IntoText intoText) {
-            return intoText.intoText();
-        } else {
-            return new LiteralText(Objects.requireNonNull(value.toString()));
-        }
+    public final @NotNull ValueGenericSettingNode<T> withChildrenVisibilityListener(final @NotNull ValueSettingNodeVisibilityListener<T> childrenVisibilityListener) {
+        this.childrenVisibilityListener = childrenVisibilityListener;
+
+        return this;
     }
 
     @Override
-    public @NotNull Text getName() {
-        return this.name;
+    public boolean areChildrenVisible(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.isVisible(dimension, config) && this.childrenVisibilityListener.isVisible(config, config.getDimensionSettings(dimension).getNodeValue(this, config));
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/ValueSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/ValueSettingNode.java
index ea2c3e7d0..7c29128c4 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/ValueSettingNode.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/ValueSettingNode.java
@@ -1,12 +1,23 @@
 package net.minecraft.core.world.settings;
 
+import com.mojang.nbt.tags.Tag;
 import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.zip.DataFormatException;
+
 public interface ValueSettingNode<T> extends SettingNode, NamedSettingNode, KeyedSettingNode {
     @NotNull Class<@NotNull T> getValueClass();
 
-    @NotNull T getDefaultValue();
+    @NotNull T getDefaultValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config);
+
+    boolean validateValue(final @NotNull T value, final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config);
 
     @NotNull Text getValueText(final @NotNull T value);
+
+    @NotNull Tag<?> serializeValue(final @NotNull T value);
+
+    @NotNull T deserializeValue(final @NotNull Tag<?> tag) throws DataFormatException;
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/ValueSettingNodeVisibilityListener.java b/game/core/src/main/java/net/minecraft/core/world/settings/ValueSettingNodeVisibilityListener.java
new file mode 100644
index 000000000..83cf38403
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/ValueSettingNodeVisibilityListener.java
@@ -0,0 +1,18 @@
+package net.minecraft.core.world.settings;
+
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import org.jetbrains.annotations.NotNull;
+
+public interface ValueSettingNodeVisibilityListener<T> {
+    boolean isVisible(final @NotNull WorldConfigurationReader config, final @NotNull T value);
+
+    @SuppressWarnings("unused")
+    static boolean alwaysVisible(final @NotNull WorldConfigurationReader config, final @NotNull Object value) {
+        return true;
+    }
+
+    @SuppressWarnings("unused")
+    static boolean neverVisible(final @NotNull WorldConfigurationReader config, final @NotNull Object value) {
+        return false;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/WorldConfiguration.java b/game/core/src/main/java/net/minecraft/core/world/settings/WorldConfiguration.java
index 9f2cdfb7b..fd116a7a4 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/WorldConfiguration.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/WorldConfiguration.java
@@ -1,39 +1,86 @@
 package net.minecraft.core.world.settings;
 
+import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
 import net.minecraft.core.data.gamerule.GameRuleCollection;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.player.gamemode.Gamemodes;
 import net.minecraft.core.util.helper.ChatAllowedCharacters;
 import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.config.spawning.SpawnerConfig;
 import net.minecraft.core.world.save.ISaveFormat;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypeGroups;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.Map;
+import java.util.Objects;
 import java.util.Random;
 
-public class WorldConfiguration {
+public class WorldConfiguration implements WorldConfigurationReader {
+    public interface ChangeListener {
+        void onChanged();
+    }
+
     private @NotNull String worldName = "";
     private long numericSeed = new Random().nextLong();
     private @NotNull String stringSeed = "";
     private boolean cheatsEnabled = false;
     private @NotNull Gamemode gamemode = Gamemodes.SURVIVAL;
     private @NotNull WorldTypeGroups.Group worldTypeGroup = WorldTypeGroups.DEFAULT;
-    private @Nullable Biome startingBiome = null;
     private final @NotNull GameRuleCollection gameRuleCollection = new GameRuleCollection();
     private final @NotNull SpawnerConfig spawnerConfig = new SpawnerConfig();
-    private final @NotNull SettingNodesValues settingNodesValues = new SettingNodesValues(DefaultSettingNodes.getRootNode());
+    private final @NotNull Map<@NotNull Dimension, @NotNull SettingNodesValues> worldSettings = new Object2ObjectArrayMap<>();
+    private @Nullable ChangeListener changeListener;
 
     public WorldConfiguration() {
+        for (final @NotNull Dimension dimension : Dimension.getDimensionList().values()) {
+            this.worldSettings.put(dimension, new SettingNodesValues(WorldSettingNodes.getRootNode(), dimension));
+        }
+    }
+
+    public void setChangeListener(final @Nullable ChangeListener changeListener) {
+        this.changeListener = changeListener;
+        this.gameRuleCollection.setChangeListener(this.changeListener);
+        this.spawnerConfig.setChangeListener(this.changeListener);
+        for (final @NotNull SettingNodesValues values : this.worldSettings.values()) {
+            values.setChangeListener(this.changeListener);
+        }
+    }
+
+    private void notifyChanged() {
+        if (this.changeListener != null) {
+            this.changeListener.onChanged();
+        }
+    }
+
+    public @NotNull WorldConfiguration copy() {
+        final @NotNull WorldConfiguration copy = new WorldConfiguration();
+        copy.setWorldName(this.worldName);
+        copy.setNumericSeed(this.numericSeed);
+        copy.setStringSeed(this.stringSeed);
+        copy.setCheatsEnabled(this.cheatsEnabled);
+        copy.setGamemode(this.gamemode);
+        copy.setWorldTypeGroup(this.worldTypeGroup);
+
+        copy.gameRuleCollection.setValues(this.gameRuleCollection);
+        copy.spawnerConfig.set(this.spawnerConfig);
+        for (final @NotNull var key : this.worldSettings.keySet()) {
+            final @NotNull SettingNodesValues values = Objects.requireNonNull(this.worldSettings.get(key));
+            Objects.requireNonNull(copy.worldSettings.get(key)).setAll(values);
+        }
+
+        return copy;
     }
 
     public @NotNull String getWorldName() {
         return this.worldName;
     }
 
+    @Override
     public @NotNull String getFinalWorldName() {
         if (MathHelper.stringNullOrLengthZero(this.worldName)) {
             return I18n.getInstance().translateKey("gui.create_world.label.new_world");
@@ -44,12 +91,14 @@ public class WorldConfiguration {
 
     public void setWorldName(final @NotNull String worldName) {
         this.worldName = worldName;
+        this.notifyChanged();
     }
 
     public long getNumericSeed() {
         return this.numericSeed;
     }
 
+    @Override
     public long getFinalNumericSeed() {
         if (MathHelper.stringNullOrLengthZero(this.stringSeed)) {
             return this.numericSeed;
@@ -69,6 +118,12 @@ public class WorldConfiguration {
 
     public void regenNumericSeed() {
         this.numericSeed = new Random().nextLong();
+        this.notifyChanged();
+    }
+
+    public void setNumericSeed(final long seed) {
+        this.numericSeed = seed;
+        this.notifyChanged();
     }
 
     public @NotNull String getStringSeed() {
@@ -77,14 +132,17 @@ public class WorldConfiguration {
 
     public void setStringSeed(final @NotNull String seed) {
         this.stringSeed = seed;
+        this.notifyChanged();
     }
 
+    @Override
     public boolean getCheatsEnabled() {
         return this.cheatsEnabled;
     }
 
     public void setCheatsEnabled(final boolean cheatsEnabled) {
         this.cheatsEnabled = cheatsEnabled;
+        this.notifyChanged();
     }
 
     public @NotNull Gamemode getGamemode() {
@@ -93,34 +151,36 @@ public class WorldConfiguration {
 
     public void setGamemode(final @NotNull Gamemode gamemode) {
         this.gamemode = gamemode;
+        this.notifyChanged();
     }
 
     public @NotNull WorldTypeGroups.Group getWorldTypeGroup() {
         return this.worldTypeGroup;
     }
 
+    @Override
+    public @NotNull WorldType getWorldType(final @NotNull Dimension dimension) {
+        return this.worldTypeGroup.get(dimension);
+    }
+
     public void setWorldTypeGroup(final @NotNull WorldTypeGroups.Group worldTypeGroup) {
         this.worldTypeGroup = worldTypeGroup;
+        this.notifyChanged();
     }
 
-    public @NotNull GameRuleCollection getGameRuleCollection() {
+    @Override
+    public @NotNull GameRuleCollection getGameRules() {
         return this.gameRuleCollection;
     }
 
+    @Override
     public @NotNull SpawnerConfig getSpawnerConfig() {
         return this.spawnerConfig;
     }
 
-    public void setStartingBiome(@Nullable Biome biome) {
-        this.startingBiome = biome;
-    }
-
-    public @Nullable Biome getStartingBiome() {
-        return this.startingBiome;
-    }
-
-    public @NotNull SettingNodesValues getSettingNodesValues() {
-        return this.settingNodesValues;
+    @Override
+    public @NotNull SettingNodesValues getDimensionSettings(final @NotNull Dimension dimension) {
+        return Objects.requireNonNull(this.worldSettings.get(dimension));
     }
 
     public @NotNull String getFolderName(final @NotNull ISaveFormat saveFormat) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/WorldSettingNodes.java b/game/core/src/main/java/net/minecraft/core/world/settings/WorldSettingNodes.java
new file mode 100644
index 000000000..2573e5d88
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/WorldSettingNodes.java
@@ -0,0 +1,57 @@
+package net.minecraft.core.world.settings;
+
+import net.minecraft.core.lang.text.TranslatableText;
+import net.minecraft.core.world.settings.impl.BiomeSettingNode;
+import net.minecraft.core.world.settings.impl.BooleanSettingNode;
+import net.minecraft.core.world.settings.impl.SeasonSettingNode;
+import net.minecraft.core.world.settings.impl.WorldHeightSettingNode;
+import org.jetbrains.annotations.NotNull;
+
+public final class WorldSettingNodes {
+    private WorldSettingNodes() throws IllegalAccessException {
+        throw new IllegalAccessException("No WorldSettingNodes for you!");
+    }
+
+    public static final @NotNull WorldHeightSettingNode WORLD_HEIGHT_BOTTOM =
+        new WorldHeightSettingNode("minecraft:world_settings/world_height/bottom", new TranslatableText("world_settings.world_height.bottom.name"), WorldHeightSettingNode.DEFAULT_MIN, WorldHeightSettingNode.ValueType.BOTTOM);
+    public static final @NotNull WorldHeightSettingNode WORLD_HEIGHT_TOP =
+        new WorldHeightSettingNode("minecraft:world_settings/world_height/top", new TranslatableText("world_settings.world_height.top.name"), WorldHeightSettingNode.DEFAULT_MAX, WorldHeightSettingNode.ValueType.TOP);
+    public static final @NotNull BooleanSettingNode SINGLE_SEASON_ENABLED = (BooleanSettingNode)
+        new BooleanSettingNode("minecraft:world_settings/single_season/enabled", new TranslatableText("world_settings.single_season.enabled.name"), false)
+            .withChildrenVisibilityListener((config, value) -> value);
+    public static final @NotNull SeasonSettingNode SINGLE_SEASON_VALUE =
+        new SeasonSettingNode("minecraft:world_settings/single_season/value", new TranslatableText("world_settings.single_season.value.name"));
+    public static final @NotNull BooleanSettingNode STARTING_BIOME_ENABLED = (BooleanSettingNode)
+        new BooleanSettingNode("minecraft:world_settings/starting_biome/enabled", new TranslatableText("world_settings.starting_biome.enabled.name"), false)
+            .withChildrenVisibilityListener((config, value) -> value);
+    public static final @NotNull BiomeSettingNode STARTING_BIOME_VALUE =
+        new BiomeSettingNode("minecraft:world_settings/starting_biome/value", new TranslatableText("world_settings.starting_biome.value.name"));
+    public static final @NotNull BooleanSettingNode SINGLE_BIOME_ENABLED = (BooleanSettingNode)
+        new BooleanSettingNode("minecraft:world_settings/single_biome/enabled", new TranslatableText("world_settings.single_biome.enabled.name"), false)
+            .withChildrenVisibilityListener((config, value) -> value);
+    public static final @NotNull BiomeSettingNode SINGLE_BIOME_VALUE =
+        new BiomeSettingNode("minecraft:world_settings/single_biome/value", new TranslatableText("world_settings.single_biome.value.name"));
+
+    private static final @NotNull SettingNode ROOT_NODE;
+    static {
+        ROOT_NODE = new ContainerSettingNode(new ListSettingNodeChildrenProvider())
+            .withChild(WORLD_HEIGHT_BOTTOM)
+            .withChild(WORLD_HEIGHT_TOP)
+            .withChild(
+                SINGLE_SEASON_ENABLED
+                    .withChild(SINGLE_SEASON_VALUE)
+            )
+            .withChild(
+                STARTING_BIOME_ENABLED
+                    .withChild(STARTING_BIOME_VALUE)
+            )
+            .withChild(
+                SINGLE_BIOME_ENABLED
+                    .withChild(SINGLE_BIOME_VALUE)
+            );
+    }
+
+    public static @NotNull SettingNode getRootNode() {
+        return ROOT_NODE;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/impl/BiomeSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/impl/BiomeSettingNode.java
new file mode 100644
index 000000000..3d59d34e6
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/impl/BiomeSettingNode.java
@@ -0,0 +1,62 @@
+package net.minecraft.core.world.settings.impl;
+
+import com.mojang.nbt.tags.StringTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.core.data.registry.Registries;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.lang.text.TranslatableText;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import net.minecraft.core.world.settings.ListValueSettingNode;
+import net.minecraft.core.world.settings.ValueGenericSettingNode;
+import net.minecraft.core.world.type.WorldType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.zip.DataFormatException;
+
+public class BiomeSettingNode extends ValueGenericSettingNode<@NotNull Biome> implements ListValueSettingNode<@NotNull Biome> {
+    public BiomeSettingNode(final @NotNull String key, final @NotNull Text name) {
+        super(key, name, Biome.class);
+    }
+
+    @Override
+    public @NotNull Biome getDefaultValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.getValues(dimension, config).get(0);
+    }
+
+    @Override
+    public @NotNull List<@NotNull Biome> getValues(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        final @NotNull WorldType worldType = config.getWorldType(dimension);
+        return Arrays.asList(worldType.allBiomes());
+    }
+
+    @Override
+    public @NotNull Text getValueText(final @NotNull Biome value) {
+        return new TranslatableText(value.translationKey);
+    }
+
+    @Override
+    public @NotNull Tag<?> serializeValue(final @NotNull Biome value) {
+        return new StringTag(Objects.requireNonNull(Registries.BIOMES.getKey(value)));
+    }
+
+    @Override
+    public @NotNull Biome deserializeValue(final @NotNull Tag<?> tag) throws DataFormatException {
+        if (tag instanceof final @NotNull StringTag stringTag) {
+            final @Nullable Biome biome = Registries.BIOMES.getItem(stringTag.getValue());
+            if (biome != null) {
+                return biome;
+            } else {
+                throw new DataFormatException("Illegal biome ID in tag!");
+            }
+        } else {
+            throw new DataFormatException("Tag was wrong type!");
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/impl/BooleanSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/impl/BooleanSettingNode.java
new file mode 100644
index 000000000..05ae5d0d7
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/impl/BooleanSettingNode.java
@@ -0,0 +1,62 @@
+package net.minecraft.core.world.settings.impl;
+
+import com.mojang.nbt.tags.ByteTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.lang.text.TranslatableText;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import net.minecraft.core.world.settings.ValueGenericSettingNode;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.zip.DataFormatException;
+
+public class BooleanSettingNode extends ValueGenericSettingNode<@NotNull Boolean> {
+    private static final @NotNull TranslatableText ON = new TranslatableText("world_settings.values.on");
+    private static final @NotNull TranslatableText OFF = new TranslatableText("world_settings.values.off");
+
+    private final boolean defaultValue;
+
+    public BooleanSettingNode(final @NotNull String key, final @NotNull Text name, final boolean defaultValue) {
+        super(key, name, Boolean.class);
+
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public @NotNull Boolean getDefaultValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.defaultValue;
+    }
+
+    @Override
+    public boolean validateValue(final @NotNull Boolean value, final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return true;
+    }
+
+    @Override
+    public @NotNull Text getValueText(final @NotNull Boolean value) {
+        if (value) {
+            return ON;
+        } else {
+            return OFF;
+        }
+    }
+
+    @Override
+    public @NotNull Tag<?> serializeValue(final @NotNull Boolean value) {
+        if (value) {
+            return new ByteTag((byte) 1);
+        } else {
+            return new ByteTag((byte) 0);
+        }
+    }
+
+    @Override
+    public @NotNull Boolean deserializeValue(final @NotNull Tag<?> tag) throws DataFormatException {
+        if (tag instanceof final @NotNull ByteTag byteTag) {
+            return byteTag.getValue() != 0;
+        } else {
+            throw new DataFormatException("Tag was wrong type!");
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/impl/EnumSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/impl/EnumSettingNode.java
new file mode 100644
index 000000000..eda4c59e2
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/impl/EnumSettingNode.java
@@ -0,0 +1,61 @@
+package net.minecraft.core.world.settings.impl;
+
+import com.mojang.nbt.tags.StringTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.core.lang.text.IntoText;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import net.minecraft.core.world.settings.ListValueSettingNode;
+import net.minecraft.core.world.settings.ValueGenericSettingNode;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.zip.DataFormatException;
+
+public class EnumSettingNode<T extends Enum<T> & IntoText> extends ValueGenericSettingNode<T> implements ListValueSettingNode<T> {
+    final @NotNull T defaultValue;
+
+    public EnumSettingNode(final @NotNull String key, final @NotNull Text name, final @NotNull T defaultValue) {
+        super(key, name, defaultValue.getDeclaringClass());
+
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public @NotNull T getDefaultValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.defaultValue;
+    }
+
+    @Override
+    public @NotNull Text getValueText(final @NotNull T value) {
+        return value.intoText();
+    }
+
+    @Override
+    public @NotNull Tag<?> serializeValue(final @NotNull T value) {
+        return new StringTag(value.name());
+    }
+
+    @Override
+    public @NotNull T deserializeValue(final @NotNull Tag<?> tag) throws DataFormatException {
+        if (tag instanceof final @NotNull StringTag stringTag) {
+            final @NotNull String string = stringTag.getValue();
+
+            try {
+                return T.valueOf(this.getValueClass(), string);
+            } catch (final @NotNull IllegalArgumentException e) {
+                throw new DataFormatException("Illegal enum value in tag!");
+            }
+        } else {
+            throw new DataFormatException("Tag was wrong type!");
+        }
+    }
+
+    @Override
+    public @NotNull List<T> getValues(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return Arrays.asList(Objects.requireNonNull(this.getValueClass().getEnumConstants()));
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/impl/PercentageSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/impl/PercentageSettingNode.java
new file mode 100644
index 000000000..b6d188b6e
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/impl/PercentageSettingNode.java
@@ -0,0 +1,71 @@
+package net.minecraft.core.world.settings.impl;
+
+import com.mojang.nbt.tags.FloatTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.core.lang.text.LiteralText;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import net.minecraft.core.world.settings.RangeValueSettingNode;
+import net.minecraft.core.world.settings.ValueGenericSettingNode;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.zip.DataFormatException;
+
+public class PercentageSettingNode extends ValueGenericSettingNode<@NotNull Float> implements RangeValueSettingNode<@NotNull Float> {
+    private final float defaultValue;
+
+    public PercentageSettingNode(final @NotNull String key, final @NotNull Text name, final float defaultValue) {
+        super(key, name, Float.class);
+
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public @NotNull Float getMinimumValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return 0.0f;
+    }
+
+    @Override
+    public @NotNull Float getMaximumValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return 1.0f;
+    }
+
+    @Override
+    public @NotNull Float getDefaultValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.defaultValue;
+    }
+
+    @Override
+    public boolean validateValue(final @NotNull Float value, final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return value >= this.getMinimumValue(dimension, config) && value <= this.getMaximumValue(dimension, config);
+    }
+
+    @Override
+    public @NotNull Text getValueText(final @Nullable Float value) {
+        if (value == null) {
+            throw new IllegalArgumentException("Value cannot be null!");
+        }
+
+        return new LiteralText((int)(value * 100.0) + "%");
+    }
+
+    @Override
+    public @NotNull Tag<?> serializeValue(final @Nullable Float value) {
+        if (value == null) {
+            throw new IllegalArgumentException("Value cannot be null!");
+        }
+
+        return new FloatTag(value);
+    }
+
+    @Override
+    public @NotNull Float deserializeValue(final @NotNull Tag<?> tag) throws DataFormatException {
+        if (tag instanceof final @NotNull FloatTag floatTag) {
+            return floatTag.getValue();
+        } else {
+            throw new DataFormatException("Tag was wrong type!");
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/impl/RangeIntegerSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/impl/RangeIntegerSettingNode.java
new file mode 100644
index 000000000..dc1d04f28
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/impl/RangeIntegerSettingNode.java
@@ -0,0 +1,67 @@
+package net.minecraft.core.world.settings.impl;
+
+import com.mojang.nbt.tags.FloatTag;
+import com.mojang.nbt.tags.IntTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.core.lang.text.LiteralText;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import net.minecraft.core.world.settings.RangeValueSettingNode;
+import net.minecraft.core.world.settings.ValueGenericSettingNode;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.zip.DataFormatException;
+
+public class RangeIntegerSettingNode extends ValueGenericSettingNode<@NotNull Integer> implements RangeValueSettingNode<@NotNull Integer> {
+    private final int minValue;
+    private final int maxValue;
+    private final int defaultValue;
+
+    public RangeIntegerSettingNode(final @NotNull String key, final @NotNull Text name, final int minValue, final int maxValue, final int defaultValue) {
+        super(key, name, Integer.class);
+
+        this.minValue = minValue;
+        this.maxValue = maxValue;
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public @NotNull Integer getMinimumValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.minValue;
+    }
+
+    @Override
+    public @NotNull Integer getMaximumValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.maxValue;
+    }
+
+    @Override
+    public @NotNull Integer getDefaultValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.defaultValue;
+    }
+
+    @Override
+    public boolean validateValue(final @NotNull Integer value, final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return value >= this.getMinimumValue(dimension, config) && value <= this.getMaximumValue(dimension, config);
+    }
+
+    @Override
+    public @NotNull Text getValueText(final @NotNull Integer value) {
+        return new LiteralText("" + value);
+    }
+
+    @Override
+    public @NotNull Tag<?> serializeValue(final @NotNull Integer value) {
+        return new IntTag(value);
+    }
+
+    @Override
+    public @NotNull Integer deserializeValue(final @NotNull Tag<?> tag) throws DataFormatException {
+        if (tag instanceof final @NotNull IntTag intTag) {
+            return intTag.getValue();
+        } else {
+            throw new DataFormatException("Tag was wrong type!");
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/impl/SeasonSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/impl/SeasonSettingNode.java
index a0457deb2..b51b59ed2 100644
--- a/game/core/src/main/java/net/minecraft/core/world/settings/impl/SeasonSettingNode.java
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/impl/SeasonSettingNode.java
@@ -1,38 +1,75 @@
 package net.minecraft.core.world.settings.impl;
 
-import net.minecraft.core.lang.text.IntoText;
+import com.mojang.nbt.tags.StringTag;
+import com.mojang.nbt.tags.Tag;
 import net.minecraft.core.lang.text.Text;
 import net.minecraft.core.lang.text.TranslatableText;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.config.season.SeasonConfig;
+import net.minecraft.core.world.config.season.SeasonConfigCycle;
+import net.minecraft.core.world.config.season.SeasonConfigSingle;
+import net.minecraft.core.world.save.WorldConfigurationReader;
 import net.minecraft.core.world.season.Season;
-import net.minecraft.core.world.settings.ListValueGenericSettingNode;
+import net.minecraft.core.world.season.Seasons;
+import net.minecraft.core.world.settings.ListValueSettingNode;
+import net.minecraft.core.world.settings.ValueGenericSettingNode;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class SeasonSettingNode extends ListValueGenericSettingNode<SeasonSettingNode.SeasonEntry> {
-    public static class SeasonEntry implements IntoText {
-        private final @NotNull Text text;
+import java.util.List;
+import java.util.zip.DataFormatException;
 
-        public final @Nullable Season season;
+public class SeasonSettingNode extends ValueGenericSettingNode<@NotNull Season> implements ListValueSettingNode<@NotNull Season> {
+    public SeasonSettingNode(final @NotNull String key, final @NotNull Text name) {
+        super(key, name, Season.class);
+    }
 
-        private SeasonEntry() {
-            this.season = null;
-            this.text = new TranslatableText("world_settings.single_season.disabled");
+    @Override
+    public @NotNull List<@NotNull Season> getValues(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        final @NotNull SeasonConfig seasonConfig = config.getWorldType(dimension).getSeasonConfig();
+        if (seasonConfig instanceof final @NotNull SeasonConfigCycle cycle) {
+            return cycle.getSeasons();
+        } else if (seasonConfig instanceof final @NotNull SeasonConfigSingle single) {
+            return List.of(single.getSingleSeason());
+        } else {
+            throw new IllegalStateException("Illegal SeasonConfig!");
         }
+    }
 
-        public SeasonEntry(final @NotNull Season season) {
-            this.season = season;
-            this.text = new TranslatableText(season.getLanguageKey());
-        }
+    @Override
+    public @NotNull Season getDefaultValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        return this.getValues(dimension, config).get(0);
+    }
 
-        @Override
-        public @NotNull Text intoText() {
-            return this.text;
+    @Override
+    public @NotNull Text getValueText(final @Nullable Season value) {
+        if (value == null) {
+            return new TranslatableText("world_settings.single_season.values.disabled");
+        } else {
+            return new TranslatableText(value.getLanguageKey() + ".name");
         }
     }
 
-    public static final @NotNull SeasonEntry DISABLED = new SeasonEntry();
+    @Override
+    public @NotNull Tag<?> serializeValue(final @Nullable Season value) {
+        if (value == null) {
+            return new StringTag("");
+        } else {
+            return new StringTag(value.getId());
+        }
+    }
 
-    public SeasonSettingNode(final @NotNull String key, final @NotNull Text name, final @NotNull SeasonEntry defaultValue) {
-        super(key, name, defaultValue);
+    @Override
+    public @NotNull Season deserializeValue(final @NotNull Tag<?> tag) throws DataFormatException {
+        if (tag instanceof final @NotNull StringTag stringTag) {
+            final @Nullable Season season = Seasons.getSeason(stringTag.getValue());
+            if (season != null) {
+                return season;
+            } else {
+                throw new DataFormatException("Illegal season ID in tag!");
+            }
+        } else {
+            throw new DataFormatException("Tag was wrong type!");
+        }
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/impl/WorldHeightSettingNode.java b/game/core/src/main/java/net/minecraft/core/world/settings/impl/WorldHeightSettingNode.java
new file mode 100644
index 000000000..2000a92c9
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/settings/impl/WorldHeightSettingNode.java
@@ -0,0 +1,72 @@
+package net.minecraft.core.world.settings.impl;
+
+import net.minecraft.core.lang.text.LiteralText;
+import net.minecraft.core.lang.text.Text;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.WorldConfigurationReader;
+import net.minecraft.core.world.settings.WorldSettingNodes;
+import org.jetbrains.annotations.NotNull;
+
+public class WorldHeightSettingNode extends RangeIntegerSettingNode {
+    public static final int VALUE_SCALE = 16;
+    public static final int DEFAULT_MIN = 0;
+    public static final int DEFAULT_MAX = 16;
+
+    public enum ValueType {
+        BOTTOM,
+        TOP;
+    }
+
+    private final @NotNull ValueType valueType;
+
+    public WorldHeightSettingNode(final @NotNull String key, final @NotNull Text name, final int defaultValue, final @NotNull ValueType valueType) {
+        super(key, name, 0, 16, defaultValue);
+
+        this.valueType = valueType;
+    }
+
+    @Override
+    public @NotNull Integer getMinimumValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        final int bottomValue = config.getDimensionSettings(dimension).getNodeValueOr(WorldSettingNodes.WORLD_HEIGHT_BOTTOM, DEFAULT_MIN);
+
+        final int baseMin = super.getMinimumValue(dimension, config);
+
+        return switch (this.valueType) {
+            case BOTTOM -> baseMin;
+            case TOP -> bottomValue + 1;
+        };
+    }
+
+    @Override
+    public @NotNull Integer getMaximumValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        final int topValue = config.getDimensionSettings(dimension).getNodeValueOr(WorldSettingNodes.WORLD_HEIGHT_TOP, DEFAULT_MAX);
+
+        final int baseMax = super.getMaximumValue(dimension, config);
+
+        return switch (this.valueType) {
+            case BOTTOM -> topValue - 1;
+            case TOP -> baseMax;
+        };
+    }
+
+    @Override
+    public @NotNull Integer getDefaultValue(final @NotNull Dimension dimension, final @NotNull WorldConfigurationReader config) {
+        final int baseDefault = super.getDefaultValue(dimension, config);
+        final int baseMin = super.getMinimumValue(dimension, config);
+        final int baseMax = super.getMaximumValue(dimension, config);
+
+        final int bottomValue = config.getDimensionSettings(dimension).getNodeValueOr(WorldSettingNodes.WORLD_HEIGHT_BOTTOM, DEFAULT_MIN);
+        final int topValue = config.getDimensionSettings(dimension).getNodeValueOr(WorldSettingNodes.WORLD_HEIGHT_TOP, DEFAULT_MAX);
+
+        return switch (this.valueType) {
+            case BOTTOM -> MathHelper.clamp(baseDefault, baseMin, topValue - 1);
+            case TOP -> MathHelper.clamp(baseDefault, bottomValue + 1, baseMax);
+        };
+    }
+
+    @Override
+    public @NotNull Text getValueText(final @NotNull Integer value) {
+        return new LiteralText("" + (VALUE_SCALE * value));
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
index d45ea3c07..aa5cf8f09 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
@@ -11,6 +11,8 @@ import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.save.LevelData;
 import net.minecraft.core.world.season.Seasons;
+import net.minecraft.core.world.settings.WorldSettingNodes;
+import net.minecraft.core.world.settings.impl.WorldHeightSettingNode;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.Weathers;
 import net.minecraft.core.world.wind.WindProvider;
@@ -89,16 +91,16 @@ public abstract class WorldType {
         return seasonConfig;
     }
 
-    public int getMinY() {
-        return minY;
+    public int getMinY(final @NotNull World world) {
+        return world.getWorldSetting(WorldSettingNodes.WORLD_HEIGHT_BOTTOM) * WorldHeightSettingNode.VALUE_SCALE;
     }
 
     public int getMinPortalY() {
         return minPortalY;
     }
 
-    public int getMaxY() {
-        return maxY;
+    public int getMaxY(final @NotNull World world) {
+        return (world.getWorldSetting(WorldSettingNodes.WORLD_HEIGHT_TOP) * WorldHeightSettingNode.VALUE_SCALE) - 1;
     }
 
     public int getMaxPortalY() {
@@ -131,13 +133,13 @@ public abstract class WorldType {
 
     public void onWorldCreation(World world) { }
 
-    public final int getYRange() {
-        return getMaxY() - getMinY();
+    public final int getYRange(final @NotNull World world) {
+        return getMaxY(world) - getMinY(world);
     }
 
-    public final double getYPercentage(int y) {
-        int range = getYRange();
-        y -= getMinY();
+    public final double getYPercentage(final @NotNull World world, int y) {
+        int range = getYRange(world);
+        y -= getMinY(world);
         return (double)y / (double)range;
     }
 
@@ -150,6 +152,9 @@ public abstract class WorldType {
     public abstract boolean isValidSpawn(World world, int x, int y, int z);
 
     public void getInitialSpawnLocation(World world, @Nullable Biome startingBiome) {
+        final int minY = this.getMinY(world);
+        final int maxY = this.getMaxY(world);
+
         TilePos queryPos = new TilePos();
         TilePos spawnPos = new TilePos();
         if (startingBiome != null) {
@@ -195,7 +200,7 @@ public abstract class WorldType {
             }
             spawnPos.x += random.nextInt(64) - random.nextInt(64);
             spawnPos.z += random.nextInt(64) - random.nextInt(64);
-            for (spawnPos.y = getMaxY(); spawnPos.y >= getMinY(); spawnPos.y--) {
+            for (spawnPos.y = maxY; spawnPos.y >= minY; spawnPos.y--) {
                 Block<?> b = world.getBlockType(spawnPos.up(queryPos));
                 if (b.getCollisionAABB(world, queryPos) == null && !b.getMaterial().isLiquid() && isValidSpawn(world, spawnPos.x, spawnPos.y, spawnPos.z)) {
                     break spawnLoop;
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeDebug.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeDebug.java
index d2abd3115..1067b3471 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeDebug.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeDebug.java
@@ -26,7 +26,7 @@ public class WorldTypeDebug
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.OVERWORLD_PLAINS, 1.0, 1.0, 1.0);
+        return new BiomeProviderSingleBiome(world, Biomes.OVERWORLD_PLAINS, 1.0, 1.0, 1.0);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeEmpty.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeEmpty.java
index 514d28a5b..8e1eab9db 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeEmpty.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeEmpty.java
@@ -31,7 +31,7 @@ public class WorldTypeEmpty
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.OVERWORLD_PLAINS, 1.0, 1.0, 1.0);
+        return new BiomeProviderSingleBiome(world, Biomes.OVERWORLD_PLAINS, 1.0, 1.0, 1.0);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/drift/WorldTypeDrift.java b/game/core/src/main/java/net/minecraft/core/world/type/drift/WorldTypeDrift.java
index 72ff79c14..f9f47b6f6 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/drift/WorldTypeDrift.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/drift/WorldTypeDrift.java
@@ -54,7 +54,7 @@ public class WorldTypeDrift
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.DRIFT_DRIFT, 0.5, 0.0, 0.0);
+        return new BiomeProviderSingleBiome(world, Biomes.DRIFT_DRIFT, 0.5, 0.0, 0.0);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java b/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
index 2090ca074..3ef04360f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
@@ -44,7 +44,7 @@ public class WorldTypeNether
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderNether(world.getRandomSeed());
+        return new BiomeProviderNether(world);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeFlat.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeFlat.java
index 7fe2b1d83..dc417f8c7 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeFlat.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeFlat.java
@@ -18,7 +18,7 @@ public class WorldTypeFlat
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.OVERWORLD_PLAINS, 0.5, 0.0, 0.0);
+        return new BiomeProviderSingleBiome(world, Biomes.OVERWORLD_PLAINS, 0.5, 0.0, 0.0);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
index d05a103d0..f1d3328e7 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
@@ -14,8 +14,7 @@ import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.weather.Weather;
 import org.jetbrains.annotations.NotNull;
 
-public class WorldTypeOverworld
-        extends WorldType {
+public class WorldTypeOverworld extends WorldType {
     public WorldTypeOverworld(Properties properties) {
         super(properties);
     }
@@ -55,7 +54,7 @@ public class WorldTypeOverworld
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderOverworld(world.getRandomSeed(), this);
+        return new BiomeProviderOverworld(world);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldB173.java
index c15c2ebeb..e5e15bb5a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldB173.java
@@ -16,7 +16,7 @@ public class WorldTypeOverworldB173
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderB173(world.getRandomSeed());
+        return new BiomeProviderB173(world);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldClassic.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldClassic.java
index 1c75f2e40..6e530f165 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldClassic.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldClassic.java
@@ -18,7 +18,7 @@ public class WorldTypeOverworldClassic
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.OVERWORLD_RETRO, 1.0, 1.0, 1.0);
+        return new BiomeProviderSingleBiome(world, Biomes.OVERWORLD_RETRO, 1.0, 1.0, 1.0);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldFloating.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldFloating.java
index 2acf4fb1f..bade08577 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldFloating.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldFloating.java
@@ -17,7 +17,7 @@ public class WorldTypeOverworldFloating
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderOverworld(world.getRandomSeed(), this)
+        return new BiomeProviderOverworld(world)
                 .withTemperatureScales(0.00625, 0.00625, 0.25, 0.01)
                 .withHumidityScales(0.0125, 0.0125, 0.3, 0.01)
                 .withNoiseScales(8, 8, 0.025);
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldHell.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldHell.java
index 20f8898e5..7dd0349df 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldHell.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldHell.java
@@ -24,7 +24,7 @@ public class WorldTypeOverworldHell
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.OVERWORLD_HELL, 1.0, 1.0, 0.0);
+        return new BiomeProviderSingleBiome(world, Biomes.OVERWORLD_HELL, 1.0, 1.0, 0.0);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldIndev.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldIndev.java
index 8337b9fc9..5f02e681c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldIndev.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldIndev.java
@@ -29,6 +29,9 @@ public class WorldTypeOverworldIndev
 
     @Override
     public void getInitialSpawnLocation(World world, @Nullable Biome startingBiome) {
+        final int minY = world.getWorldType().getMinY(world);
+        final int maxY = world.getWorldType().getMaxY(world);
+
         int x;
         int y;
         int z;
@@ -37,7 +40,7 @@ public class WorldTypeOverworldIndev
         while (true) {
             x = random.nextInt(256);
             z = random.nextInt(256);
-            for (y = getMaxY(); y >= getMinY(); y--) {
+            for (y = maxY; y >= minY; y--) {
                 if (world.getBlockId(x, y + 1, z) == 0 && isValidSpawn(world, x, y, z)) {
                     break spawnLoop;
                 }
@@ -54,7 +57,7 @@ public class WorldTypeOverworldIndev
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.OVERWORLD_RETRO, 1.0, 1.0, 1.0);
+        return new BiomeProviderSingleBiome(world, Biomes.OVERWORLD_RETRO, 1.0, 1.0, 1.0);
     }
 
     @Override
@@ -64,6 +67,6 @@ public class WorldTypeOverworldIndev
 
     @Override
     public ChunkGenerator createChunkGenerator(World world) {
-        return new ChunkGeneratorIndev(world, 256, getMaxY() + 1, 256, IndevWorldType.ISLAND, IndevWorldTheme.NORMAL);
+        return new ChunkGeneratorIndev(world, 256, getMaxY(world) + 1, 256, IndevWorldType.ISLAND, IndevWorldTheme.NORMAL);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldRetro.java
index af2d80f60..ffe66fb0f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldRetro.java
@@ -17,7 +17,7 @@ public class WorldTypeOverworldRetro
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.OVERWORLD_RETRO, 1.0, 1.0, 1.0);
+        return new BiomeProviderSingleBiome(world, Biomes.OVERWORLD_RETRO, 1.0, 1.0, 1.0);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldSkyblock.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldSkyblock.java
index 509afb222..0b99fc98c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldSkyblock.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldSkyblock.java
@@ -18,7 +18,7 @@ public class WorldTypeOverworldSkyblock
 
     @Override
     public @NotNull BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.OVERWORLD_PLAINS, 1.0, 1.0, 1.0);
+        return new BiomeProviderSingleBiome(world, Biomes.OVERWORLD_PLAINS, 1.0, 1.0, 1.0);
     }
 
     @Override
diff --git a/game/core/src/main/resources/lang/en_US/gui.lang b/game/core/src/main/resources/lang/en_US/gui.lang
index 3edc9f344..481a324ef 100644
--- a/game/core/src/main/resources/lang/en_US/gui.lang
+++ b/game/core/src/main/resources/lang/en_US/gui.lang
@@ -100,6 +100,8 @@ gui.world_settings.label.title=World Settings
 gui.world_settings.button.done=Done
 gui.world_settings.page.game_rules.title=Game Rules
 gui.world_settings.page.world_settings.title=World Settings
+gui.world_settings.page.world_settings.category.overworld=Overworld
+gui.world_settings.page.world_settings.category.nether=Nether
 gui.world_settings.page.game_rules.button.on=ON
 gui.world_settings.page.game_rules.button.off=OFF
 gui.world_settings.page.mob_spawning.title=Mob Spawning
diff --git a/game/core/src/main/resources/lang/en_US/worldsettings.lang b/game/core/src/main/resources/lang/en_US/worldsettings.lang
new file mode 100644
index 000000000..393824780
--- /dev/null
+++ b/game/core/src/main/resources/lang/en_US/worldsettings.lang
@@ -0,0 +1,12 @@
+world_settings.values.on=ON
+world_settings.values.off=OFF
+
+world_settings.world_height.bottom.name=World Height at Bottom
+world_settings.world_height.ocean.name=Ocean Height
+world_settings.world_height.top.name=World Height at Top
+world_settings.single_season.enabled.name=Single Season
+world_settings.single_season.value.name=
+world_settings.starting_biome.enabled.name=Starting Biome
+world_settings.starting_biome.value.name=
+world_settings.single_biome.enabled.name=Single Biome
+world_settings.single_biome.value.name=
\ No newline at end of file
diff --git a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
index a49350ddf..df7242fef 100644
--- a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -59,6 +59,8 @@ import net.minecraft.core.player.gamemode.Gamemodes;
 import net.minecraft.core.util.pool.ObjectPool;
 import net.minecraft.core.util.helper.UUIDHelper;
 import net.minecraft.core.world.pos.TilePos;
+import net.minecraft.core.world.settings.WorldConfiguration;
+import net.minecraft.core.world.type.WorldTypeGroups;
 import net.minecraft.server.entity.player.PlayerServer;
 import net.minecraft.server.net.MulticastPublisher;
 import net.minecraft.server.net.command.ConsoleCommandSource;
@@ -536,7 +538,16 @@ public class MinecraftServer
             WorldServer worldServer;
             if (dimension.id == 0)
             {
-                worldServer = new WorldServer(this, levelStorage, worldDirName, seed, dimension);
+                final @NotNull WorldConfiguration worldConfiguration = new WorldConfiguration();
+                for (final @NotNull WorldTypeGroups.Group group : WorldTypeGroups.GROUPS) {
+                    if (group.get(dimension).equals(this.defaultWorldType)) {
+                        worldConfiguration.setWorldTypeGroup(group);
+                        break;
+                    }
+                }
+                worldConfiguration.setWorldName(worldDirName);
+                worldConfiguration.setNumericSeed(seed);
+                worldServer = new WorldServer(this, levelStorage, worldConfiguration, dimension);
             }
             else
             {
diff --git a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
index a25fbbe06..68bf64b70 100644
--- a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
+++ b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
@@ -27,6 +27,7 @@ import net.minecraft.core.world.chunk.provider.ChunkProvider;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.save.LevelStorage;
 import net.minecraft.core.world.saveddata.SavedDataStorage;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import net.minecraft.server.MinecraftServer;
 import net.minecraft.server.world.chunk.provider.ChunkProviderServer;
 import org.jetbrains.annotations.NotNull;
@@ -45,11 +46,10 @@ public class WorldServer extends World {
     public WorldServer(
         final @NotNull MinecraftServer server,
         final @NotNull LevelStorage levelStorage,
-        final @NotNull String name,
-        final long seed,
+        final @Nullable WorldConfiguration worldConfiguration,
         final @NotNull Dimension dimension
     ) {
-        super(levelStorage, name, seed, dimension, null);
+        super(levelStorage, worldConfiguration, dimension);
 
         entityIntHashMap = new Int2ObjectOpenHashMap<>();
         mcServer = server;
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/CompoundTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/CompoundTag.java
index 6eaae0cf6..bac09bd55 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/CompoundTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/CompoundTag.java
@@ -82,7 +82,7 @@ public class CompoundTag extends Tag<@NotNull Map<String, Tag<?>>>
         return getValue().containsKey(key);
     }
 
-    public Collection<Tag<?>> getValues()
+    public @NotNull Collection<@NotNull Tag<?>> getValues()
     {
         return getValue().values();
     }
diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAChunkProvider.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAChunkProvider.java
index 78fcbab91..f31b26326 100644
--- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAChunkProvider.java
+++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAChunkProvider.java
@@ -41,12 +41,15 @@ public class BTAChunkProvider implements ChunkProvider {
 
 
     public BTAChunkProvider(long seed) {
-        this.biomeProvider = new BiomeProviderOverworld(seed, WorldTypes.OVERWORLD_EXTENDED);
+//        this.biomeProvider = new BiomeProviderOverworld(seed, WorldTypes.OVERWORLD_EXTENDED);
+        // TODO: Fix
+        throw new IllegalArgumentException("This is currently broken!");
     }
 
     public BTAChunkProvider(File worldFolder, LevelData data) {
-        this.biomeProvider = new BiomeProviderOverworld(data.getRandomSeed(), WorldTypes.OVERWORLD_EXTENDED);
+//        this.biomeProvider = new BiomeProviderOverworld(data.getRandomSeed(), WorldTypes.OVERWORLD_EXTENDED);
         this.chunkLoader = new ChunkLoader(worldFolder, Dimension.OVERWORLD);
+        throw new IllegalArgumentException("This is currently broken!");
     }
     @Override
     public ViewerChunk getChunk(ChunkPos location) {
diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAWorld.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAWorld.java
index c12cff37d..97e631027 100644
--- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAWorld.java
+++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAWorld.java
@@ -1,5 +1,6 @@
 package org.useless.seedviewer.bta;
 
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.save.LevelData;
 import org.jetbrains.annotations.NotNull;
 import org.useless.seedviewer.bta.worldloader.LevelDataLoader;
diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/DummyWorld.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/DummyWorld.java
index 62c0f422b..0d485d500 100644
--- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/DummyWorld.java
+++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/DummyWorld.java
@@ -6,6 +6,7 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.chunk.provider.ChunkProvider;
 import net.minecraft.core.world.save.LevelStorage;
 import net.minecraft.core.world.save.LevelStorageDummy;
+import net.minecraft.core.world.settings.WorldConfiguration;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.useless.seedviewer.bta.worldloader.ChunkLoader;
@@ -16,10 +17,8 @@ import java.util.Objects;
 public class DummyWorld extends World {
     public static @Nullable ChunkLoader CHUNK_LOADER = null;
 
-    public DummyWorld(
-        final @NotNull Dimension dimension
-    ) {
-        super(new LevelStorageDummy(), "Dummy World", 0, dimension, null);
+    public DummyWorld(final @NotNull Dimension dimension) {
+        super(new LevelStorageDummy(), new WorldConfiguration(), dimension);
     }
 
     @Override
diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/worldloader/LevelDataLoader.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/worldloader/LevelDataLoader.java
index 3a7d15cff..881ebd5cc 100644
--- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/worldloader/LevelDataLoader.java
+++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/worldloader/LevelDataLoader.java
@@ -21,7 +21,7 @@ public class LevelDataLoader {
         Objects.requireNonNull(worldDir, "WorldDir must not be null!");
         CompoundTag tag = getLevelDataRaw(worldDir);
         if (tag == null) return null;
-        return LevelData.fromCompoundTag(tag);
+        return LevelData.deserialize(tag);
     }
 
     @Nullable
diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/data/ViewerWorld.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/data/ViewerWorld.java
index ff311b26f..01f1219d8 100644
--- a/util/seed-viewer/src/main/java/org/useless/seedviewer/data/ViewerWorld.java
+++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/data/ViewerWorld.java
@@ -1,5 +1,7 @@
 package org.useless.seedviewer.data;
 
+import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 import org.useless.seedviewer.gui.ChunkProvider;
 
 import java.io.File;
