diff --git a/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java b/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java
index da9d8804a..e989e6a4a 100644
--- a/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java
+++ b/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java
@@ -21,6 +21,7 @@ import net.minecraft.core.item.tool.ItemToolPickaxe;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.chunk.ChunkLoader;
 import net.minecraft.core.world.chunk.provider.ChunkProvider;
 import net.minecraft.core.world.weather.Weather;
@@ -147,10 +148,10 @@ public class DataDumper implements MinecraftAccessor {
                 .append(Registries.BIOMES.getNumericIdOfItem(biome)).append(",")
                 .append(biome.translationKey).append(",")
                 .append(String.format("0x%06X", biome.color)).append(",")
-                .append(Blocks.blocksList[biome.topBlock].getKey()).append(",")
-                .append(Blocks.blocksList[biome.fillerBlock].getKey()).append(",")
-                .append(biome.hasSurfaceSnow()).append(",")
-                .append(biome.hasSurfaceIce()).append(",");
+                .append(biome.getSurfaceProperties().getTopBlock().getKey()).append(",")
+                .append(biome.getSurfaceProperties().getFillerBlock().getKey()).append(",")
+                .append(biome.hasTag(BiomeTags.HAS_SURFACE_SNOW)).append(",")
+                .append(biome.hasTag(BiomeTags.HAS_SURFACE_ICE)).append(",");
 
         builder.append("\"");
 
diff --git a/game/client/src/main/java/net/minecraft/client/discord/RichPresenceHandlerThread.java b/game/client/src/main/java/net/minecraft/client/discord/RichPresenceHandlerThread.java
index 744f0ece3..a1643471c 100644
--- a/game/client/src/main/java/net/minecraft/client/discord/RichPresenceHandlerThread.java
+++ b/game/client/src/main/java/net/minecraft/client/discord/RichPresenceHandlerThread.java
@@ -56,7 +56,7 @@ public class RichPresenceHandlerThread extends Thread {
         biomeNamesMap.put(Biomes.OVERWORLD_MEADOW, "a meadow");
         biomeNamesMap.put(Biomes.NETHER_CRAG, "the crag");
         biomeNamesMap.put(Biomes.NETHER_CRYSTAL_FOREST, "a crystal forest");
-        biomeNamesMap.put(Biomes.NETHER_CRYSTAL_FIELD, "a crystal field");
+        biomeNamesMap.put(Biomes.NETHER_CRYSTAL_PLAINS, "a crystal field");
         biomeNamesMap.put(Biomes.NETHER_SULFUR_POOLS, "the sulfur pools");
         biomeNamesMap.put(Biomes.NETHER_VOLCANIC_ISLANDS, "a volcanic island");
         biomeNamesMap.put(Biomes.NETHER_OLD_WORLD, "the crag (cold)");
diff --git a/game/client/src/main/java/net/minecraft/client/render/FogManager.java b/game/client/src/main/java/net/minecraft/client/render/FogManager.java
index 8940c6dfa..f179204db 100644
--- a/game/client/src/main/java/net/minecraft/client/render/FogManager.java
+++ b/game/client/src/main/java/net/minecraft/client/render/FogManager.java
@@ -6,6 +6,7 @@ import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.world.WorldClient;
 import net.minecraft.core.block.material.Materials;
 import net.minecraft.core.world.pos.TilePos;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.joml.Vector3fc;
 import org.joml.Vector4f;
@@ -99,7 +100,7 @@ public class FogManager {
                     dest.fogStart = 0.0F;
                     dest.fogEnd = fogDistance * 0.8F;
                 }
-                if (this.mc.currentWorld.dimension == Dimension.NETHER) {
+                if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.NETHER)) {
                     dest.fogStart = 0.0F;
                 }
             }
@@ -134,7 +135,7 @@ public class FogManager {
             this.fogBlue = out[2];
         }
         if (CameraUtil.isUnderLiquid(this.mc.activeCamera, world, Materials.WATER, partialTick)) {
-            if(this.mc.currentWorld != null && this.mc.currentWorld.dimension == Dimension.NETHER) {
+            if(this.mc.currentWorld != null && this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.NETHER)) {
                 this.fogRed = 0.2F;
                 this.fogGreen = 0.02F;
                 this.fogBlue = 0.02F;
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 4832cf391..cb2e8cf61 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
@@ -3,10 +3,9 @@ package net.minecraft.client.render;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.pos.TilePos;
-import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.season.Seasons;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.Weathers;
 import org.jetbrains.annotations.NotNull;
@@ -93,13 +92,13 @@ public class PostProcessingManager {
         this.lastHumidity = humidity;
 
         // Perform base temperature change
-        if (this.mc.currentWorld.dimension == Dimension.OVERWORLD) {
+        if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.OVERWORLD)) {
             this.lastTemperature = temperature;
             final double tt = (temperature * 2) - 1.0; // Ranges from -1.0 to 1.0
             this.current.saturation += (float) (0.25 * tt * surfaceness);
             this.current.contrast += (float) (-0.1 * tt * surfaceness);
         }
-        if (this.mc.currentWorld.dimension == Dimension.NETHER) {
+        if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.HOT)) {
             this.lastTemperature = temperature;
             if (temperature < 0.5) {
                 final double tt = temperature * 2; // Ranges from 0.0 to 1.0
@@ -153,9 +152,9 @@ public class PostProcessingManager {
         }
 
         // Perform dimension effects
-        if (this.mc.currentWorld.dimension == Dimension.NETHER || this.mc.currentWorld.getWorldType() == WorldTypes.OVERWORLD_HELL) {
+        if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.HOT)) {
             float scale = 1.0f;
-            if (this.mc.currentWorld.dimension == Dimension.NETHER && temperature < 0.5) {
+            if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.NETHER) && temperature < 0.5) {
                 scale = (float) temperature * 2.0f;
             }
             this.current.rMod += 1.2f * scale;
@@ -168,7 +167,7 @@ public class PostProcessingManager {
         }
 
         // Perform heatwave effects
-        if (this.mc.currentWorld.dimension == Dimension.OVERWORLD && (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_SUMMER || this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_FALL)) {
+        if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.OVERWORLD) && (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_SUMMER || this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_FALL)) {
             if (temperature >= 0.85 && humidity <= 0.15) {
                 final double tPercentage = (temperature - 0.85) / 0.15;
                 final double hPercentage = 1 - (humidity / 0.15);
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 b7562be1d..6e3a48221 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
@@ -790,14 +790,8 @@ public class RenderGlobal
             timeScalar *= cutoff;
             timeScalar *= rainbowTimeScalar;
 
-            Weather[] blocked = this.world.getBlockBiome(new TilePos(this.mc.thePlayer)).blockedWeathers;
-            boolean isWeatherBlocked = false;
-            for (Weather w : blocked) {
-                if (w.equals(this.world.getWeatherManager().getLastWeather())) {
-                    isWeatherBlocked = true;
-                    break;
-                }
-            }
+            List<Weather> blocked = this.world.getBlockBiome(new TilePos(this.mc.thePlayer)).blockedWeathers;
+            boolean isWeatherBlocked = blocked.contains(this.world.getWeatherManager().getLastWeather());
 
             double targetRainbowBrightness;
             if (isWeatherBlocked) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
index 76522382f..59dd489e1 100644
--- a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
@@ -17,6 +17,7 @@ import net.minecraft.core.entity.animal.MobPig;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.weather.IPrecipitation;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.joml.Matrix4f;
 import org.joml.Vector3d;
 import org.joml.Vector3dc;
@@ -69,7 +70,7 @@ public class WorldRenderer {
     public float farPlaneDistance;
     public ItemRenderer itemRenderer;
     public FogManager fogManager;
-    private int rendererUpdateCount;
+    private int tick;
     private Entity pointedEntity;
     private final MouseFilter mouseFilterXAxis;
     private final MouseFilter mouseFilterYAxis;
@@ -107,7 +108,7 @@ public class WorldRenderer {
 
         this.fogManager.updateBrightness();
 
-        this.rendererUpdateCount++;
+        this.tick++;
         this.itemRenderer.updateEquippedItem();
         addRainParticles();
         this.lightmapHelper.tick();
@@ -330,7 +331,7 @@ public class WorldRenderer {
         if (portalIntensity > 0.0F) {
             float f3 = 5F / (portalIntensity * portalIntensity + 5F) - portalIntensity * 0.04F;
             f3 *= f3;
-            float rotation = org.joml.Math.toRadians(((float) this.rendererUpdateCount + partialTick) * 20F);
+            float rotation = org.joml.Math.toRadians(((float) this.tick + partialTick) * 20F);
             matrix.rotate(rotation, 0.0F, 0.7071f, 0.7071f);
             matrix.scale(1.0F / f3, 1.0F, 1.0F);
             matrix.rotate(-rotation, 0.0F, 0.7071f, 0.7071f);
@@ -715,7 +716,7 @@ public class WorldRenderer {
         GLRenderer.setDepthMask(true);
         GLRenderer.enableState(State.CULL_FACE);
         GLRenderer.disableState(State.BLEND);
-        renderRainSnow(partialTicks);
+        renderPrecipitation(partialTicks);
         if (GameSettings.CLOUDS.value) {
             Debug.change("clouds");
             GLRenderer.pushFrame();
@@ -739,255 +740,205 @@ public class WorldRenderer {
 
     private void addRainParticles() {
         if (GameSettings.PARTICLES_QUALITY.value == ParticlesQuality.NONE) return;
-        Weather weather = this.mc.currentWorld.getCurrentWeather();
-        if (!(weather instanceof IPrecipitation precipitation) || !precipitation.spawnRainParticles()) return;
 
-        float f = this.mc.currentWorld.getWeatherManager().getWeatherIntensity() * this.mc.currentWorld.getWeatherManager().getWeatherPower();
+        final @Nullable World world = this.mc.currentWorld;
+        if (world == null) {
+            return;
+        }
+
+        final @Nullable Weather weather = world.getCurrentWeather();
+        if (!(weather instanceof IPrecipitation precipitation) || !precipitation.spawnRainParticles()) {
+            return;
+        }
 
+        float rainLevel = world.getWeatherManager().getWeatherIntensity() * world.getWeatherManager().getWeatherPower();
         if (GameSettings.PARTICLES_QUALITY.value == ParticlesQuality.REDUCED) {
-            f /= 2.0F;
+            rainLevel /= 2.0F;
         }
-        if (f == 0.0F) {
+        if (rainLevel == 0.0F) {
             return;
         }
-        this.random.setSeed((long) this.rendererUpdateCount * 0x12a7ce5fL);
-        World world = this.mc.currentWorld;
+
+        this.random.setSeed((long) this.tick * 0x12a7ce5fL);
         int cameraX = MathHelper.floor(this.mc.activeCamera.getX());
         int cameraY = MathHelper.floor(this.mc.activeCamera.getY());
         int cameraZ = MathHelper.floor(this.mc.activeCamera.getZ());
-        byte byte0 = 10;
-        double d = 0.0D;
-        double d1 = 0.0D;
-        double d2 = 0.0D;
-        int l = 0;
-        blockedWeather:
-        for (int i1 = 0; i1 < (int) (100F * f * f); i1++) {
-            int randX = (cameraX + this.random.nextInt(byte0)) - this.random.nextInt(byte0);
-            int randZ = (cameraZ + this.random.nextInt(byte0)) - this.random.nextInt(byte0);
-            int y = world.findTopSolidBlock(randX, randZ);
-            int i2 = world.getBlockId(randX, y - 1, randZ);
-
-            Biome biome = world.getBlockBiome(randX, y, randZ);
-            for (int q = 0; q < biome.blockedWeathers.length; q++) {
-                if (biome.blockedWeathers[q] == weather) continue blockedWeather;
+
+        final byte weatherDiameter = 10;
+
+        double rainParticlePositionX = 0.0D;
+        double rainParticlePositionY = 0.0D;
+        double rainParticlePositionZ = 0.0D;
+
+        int spawnedParticles = 0;
+        for (int ii = 0; ii < (int) (100F * rainLevel * rainLevel); ii++) {
+            int x = (cameraX + this.random.nextInt(weatherDiameter)) - this.random.nextInt(weatherDiameter);
+            int z = (cameraZ + this.random.nextInt(weatherDiameter)) - this.random.nextInt(weatherDiameter);
+            int heightmapPosition = world.findTopSolidBlock(x, z);
+            int blockId = world.getBlockId(x, heightmapPosition - 1, z);
+
+            final @NotNull Biome biome = world.getBlockBiome(x, heightmapPosition, z);
+            if (biome.blockedWeathers.contains(weather)) {
+                continue;
             }
 
-            if (y > cameraY + byte0 || y < cameraY - byte0) {
+            if (heightmapPosition > cameraY + weatherDiameter || heightmapPosition < cameraY - weatherDiameter) {
                 continue;
             }
-            float f1 = this.random.nextFloat();
-            float f2 = this.random.nextFloat();
-            if (i2 <= 0) {
+            final float blockX = this.random.nextFloat();
+            final float blockZ = this.random.nextFloat();
+
+            if (blockId == Blocks.AIR.id()) {
                 continue;
             }
-            if (Blocks.blocksList[i2].getMaterial() == Materials.LAVA) {
-                this.mc.particleEngine.add(new ParticleSmoke(world, (float) randX + f1, (double) ((float) y + 0.1F) - Blocks.blocksList[i2].getBounds().minY(), (float) randZ + f2, 0.0D, 0.0D, 0.0D, 1.0f, 0));
+
+            if (Blocks.blocksList[blockId].getMaterial() == Materials.LAVA) {
+                this.mc.particleEngine.add(new ParticleSmoke(world, x + blockX, (heightmapPosition + 0.1F) - Blocks.blocksList[blockId].getBounds().minY(), z + blockZ, 0.0D, 0.0D, 0.0D, 1.0f, 0));
                 continue;
             }
-            if (this.random.nextInt(++l) == 0) {
-                d = (float) randX + f1;
-                d1 = (double) ((float) y + 0.1F) - Blocks.blocksList[i2].getBounds().minY();
-                d2 = (float) randZ + f2;
+
+            if (this.random.nextInt(++spawnedParticles) == 0) {
+                rainParticlePositionX = x + blockX;
+                rainParticlePositionY = (heightmapPosition + 0.1F) - Blocks.blocksList[blockId].getBounds().minY();
+                rainParticlePositionZ = z + blockZ;
             }
-            this.mc.particleEngine.add(new ParticleWaterDrop(world, (float) randX + f1, (double) ((float) y + 0.1F) - Blocks.blocksList[i2].getBounds().minY(), (float) randZ + f2));
+            this.mc.particleEngine.add(new ParticleWaterDrop(world, x + blockX, (heightmapPosition + 0.1F) - Blocks.blocksList[blockId].getBounds().minY(), z + blockZ));
         }
 
-        if (l > 0 && this.random.nextInt(3) < this.rainSoundCounter++) {
+        if (spawnedParticles > 0 && this.random.nextInt(3) < this.rainSoundCounter++) {
             this.rainSoundCounter = 0;
-            if (d1 > this.mc.activeCamera.getY() + 1.0D && world.getHeightValue(MathHelper.floor(this.mc.activeCamera.getX()), MathHelper.floor(this.mc.activeCamera.getZ())) > MathHelper.floor(this.mc.activeCamera.getY())) {
-                this.mc.currentWorld.playSoundEffect(null, SoundCategory.WEATHER_SOUNDS, d, d1, d2, "ambient.weather.rain", 0.1F * this.mc.currentWorld.getWeatherManager().getWeatherIntensity() * this.mc.currentWorld.getWeatherManager().getWeatherPower() * 0.5f, 0.5F);
+
+            float volume;
+            float pitch;
+            if (rainParticlePositionY > this.mc.activeCamera.getY() + 1.0D && world.getHeightValue(MathHelper.floor(this.mc.activeCamera.getX()), MathHelper.floor(this.mc.activeCamera.getZ())) > MathHelper.floor(this.mc.activeCamera.getY())) {
+                volume = 0.1f;
+                pitch = 0.5f;
             } else {
-                this.mc.currentWorld.playSoundEffect(null, SoundCategory.WEATHER_SOUNDS, d, d1, d2, "ambient.weather.rain", 0.2F * this.mc.currentWorld.getWeatherManager().getWeatherIntensity() * this.mc.currentWorld.getWeatherManager().getWeatherPower() * 0.5f, 1.0F);
+                volume = 0.2f;
+                pitch = 1.0f;
             }
+
+            this.mc.currentWorld.playSoundEffect(
+                null,
+                SoundCategory.WEATHER_SOUNDS,
+                rainParticlePositionX, rainParticlePositionY, rainParticlePositionZ,
+                "ambient.weather.rain",
+                volume * this.mc.currentWorld.getWeatherManager().getWeatherIntensity() * this.mc.currentWorld.getWeatherManager().getWeatherPower() * 0.5f,
+                pitch
+            );
         }
     }
 
-    protected void renderRainSnow(float partialTick) {
-        Weather weather = this.mc.currentWorld.getCurrentWeather();
-        if (!(weather instanceof @NotNull IPrecipitation precipitation)) return;
+    protected void renderPrecipitation(final float partialTick) {
+        final @Nullable World world = this.mc.currentWorld;
+        if (world == null) {
+            return;
+        }
+
+        final @Nullable Weather weather = world.getCurrentWeather();
+        if (!(weather instanceof @NotNull IPrecipitation precipitation)) {
+            return;
+        }
+
+        final int cameraBlockX = MathHelper.floor(this.mc.activeCamera.getX());
+        final int cameraBlockY = MathHelper.floor(this.mc.activeCamera.getY());
+        final int cameraBlockZ = MathHelper.floor(this.mc.activeCamera.getZ());
+
+        final @NotNull TessellatorGeneral t = GLRenderer.getTessellator();
 
-        World world = this.mc.currentWorld;
-        int posX = MathHelper.floor(this.mc.activeCamera.getX());
-        int posY = MathHelper.floor(this.mc.activeCamera.getY());
-        int posZ = MathHelper.floor(this.mc.activeCamera.getZ());
-        TessellatorGeneral tessellator = GLRenderer.getTessellator();
         GLRenderer.pushFrame();
         GLRenderer.setShader(Shaders.WORLD);
         GLRenderer.setLightmapCoord2i(15, 15);
         GLRenderer.disableState(State.CULL_FACE);
-//        glNormal3f(0.0F, 1.0F, 0.0F);
         GLRenderer.enableState(State.BLEND);
         GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA);
-//        glAlphaFunc(516, 0.01F);
 
         this.mc.textureManager.loadTexture(precipitation.getPrecipitationTexturePath(world.getWeatherManager().getWeatherPower(), world.getWeatherManager().getWeatherIntensity())).bind();
 
-        double nextPosX = this.mc.activeCamera.getX(partialTick);
-        double nextPosY = this.mc.activeCamera.getY(partialTick);
-        double nextPosZ = this.mc.activeCamera.getZ(partialTick);
-        int floorPosY = MathHelper.floor(nextPosY);
-        int radiusEffect = 10;
-
-        TilePos queryPos = new TilePos();
-
-        if (precipitation.getPrecipitationType() == IPrecipitation.Type.SNOW_LIKE) {
-            tessellator.startDrawingQuads();
-            for (int x = posX - radiusEffect; x <= posX + radiusEffect; x++) {
-                blockedWeather:
-                for (int z = posZ - radiusEffect; z <= posZ + radiusEffect; z++) {
-                    int y = world.findTopSolidBlock(x, z);
-                    Biome biomegenbase = world.getBlockBiome(x, y, z);
-                    for (int q = 0; q < biomegenbase.blockedWeathers.length; q++) {
-                        if (biomegenbase.blockedWeathers[q] == weather) {
-                            continue blockedWeather;
-                        }
-                    }
-                    if (y < 0) {
-                        y = 0;
-                    }
-                    int i3 = y;
-                    if (i3 < floorPosY) {
-                        i3 = floorPosY;
-                    }
-                    int k3 = posY - radiusEffect;
-                    int i4 = posY + radiusEffect;
-                    if (k3 < y) {
-                        k3 = y;
-                    }
-                    if (i4 < y) {
-                        i4 = y;
-                    }
-                    float f3 = 1.0F;
-                    if (k3 != i4) {
-                        this.random.setSeed((long) x * x * 3121 /*GL_RGBA_MODE*/ + x * 0x2b24abbL + (long) z * z * 0x66397 + z * 13761L);
-                        float f5 = (float) this.rendererUpdateCount + partialTick;
-                        float f6 = ((float) (this.rendererUpdateCount & 0x1ff) + partialTick) / 512F;
-                        float f7 = this.random.nextFloat() + f5 * 0.01F * (float) this.random.nextGaussian();
-                        float f8 = this.random.nextFloat() + f5 * (float) this.random.nextGaussian() * 0.001F;
-                        double d5 = (double) ((float) x + 0.5F) - this.mc.activeCamera.getX();
-                        double d6 = (double) ((float) z + 0.5F) - this.mc.activeCamera.getZ();
-                        float f11 = MathHelper.sqrt(d5 * d5 + d6 * d6) / (float) radiusEffect;
-                        float brightness;
-                        if (this.mc.fullbright) {
-                            brightness = 1.0f;
-                        } else {
-                            brightness = world.getLightBrightness(queryPos.set(x, i3, z));
-                        }
-                        tessellator.setColor4f(brightness, brightness, brightness, ((1.0F - f11 * f11) * 0.3F + 0.5F) * world.getWeatherManager().getWeatherIntensity() * world.getWeatherManager().getWeatherPower());
-                        tessellator.setTranslation(-nextPosX, -nextPosY, -nextPosZ);
-                        tessellator.addVertexWithUV(x, k3, (double) z + 0.5D, 0.0F * f3 + f7, ((float) k3 * f3) / 4F + f6 * f3 + f8);
-                        tessellator.addVertexWithUV(x + 1, k3, (double) z + 0.5D, f3 + f7, ((float) k3 * f3) / 4F + f6 * f3 + f8);
-                        tessellator.addVertexWithUV(x + 1, i4, (double) z + 0.5D, f3 + f7, ((float) i4 * f3) / 4F + f6 * f3 + f8);
-                        tessellator.addVertexWithUV(x, i4, (double) z + 0.5D, 0.0F * f3 + f7, ((float) i4 * f3) / 4F + f6 * f3 + f8);
-
-                        tessellator.addVertexWithUV((double) x + 0.5D, k3, z, 0.0F * f3 + f7, ((float) k3 * f3) / 4F + f6 * f3 + f8);
-                        tessellator.addVertexWithUV((double) x + 0.5D, k3, z + 1, f3 + f7, ((float) k3 * f3) / 4F + f6 * f3 + f8);
-                        tessellator.addVertexWithUV((double) x + 0.5D, i4, z + 1, f3 + f7, ((float) i4 * f3) / 4F + f6 * f3 + f8);
-                        tessellator.addVertexWithUV((double) x + 0.5D, i4, z, 0.0F * f3 + f7, ((float) i4 * f3) / 4F + f6 * f3 + f8);
-                        tessellator.setTranslation(0.0D, 0.0D, 0.0D);
-                    }
-                }
-            }
-            tessellator.draw();
-        } else if (precipitation.getPrecipitationType() == IPrecipitation.Type.RAIN_LIKE) {
-            tessellator.startDrawingQuads();
-            for (int x = posX - radiusEffect; x <= posX + radiusEffect; x++) {
-                blockedWeather:
-                for (int z = posZ - radiusEffect; z <= posZ + radiusEffect; z++) {
-                    int y = world.findTopSolidBlock(x, z);
-                    Biome biome = world.getBlockBiome(x, y, z);
-                    for (int q = 0; q < biome.blockedWeathers.length; q++) {
-                        if (biome.blockedWeathers[q] == weather) {
-                            continue blockedWeather;
-                        }
-                    }
-                    int j3 = posY - radiusEffect;
-                    int l3 = posY + radiusEffect;
-                    if (j3 < y) {
-                        j3 = y;
-                    }
-                    if (l3 < y) {
-                        l3 = y;
-                    }
-                    float f2 = 1.0F;
-                    if (j3 != l3) {
-                        this.random.setSeed((long) x * x * 3121 + x * 0x2b24abbL + (long) z * z * 0x66397 + z * 13761L);
-                        float f4 = (((float) (this.rendererUpdateCount + x * x * 3121 + x * 0x2b24abb + z * z * 0x66397 + z * 13761 & 0x1f) + partialTick) / 32F) * (3F + this.random.nextFloat());
-                        double d3 = (double) ((float) x + 0.5F) - this.mc.activeCamera.getX();
-                        double d4 = (double) ((float) z + 0.5F) - this.mc.activeCamera.getZ();
-                        float f9 = MathHelper.sqrt(d3 * d3 + d4 * d4) / (float) radiusEffect;
-
-                        float brightness;
-                        if (this.mc.fullbright) {
-                            brightness = 1.0f;
-                        } else {
-                            brightness = world.getLightBrightness(queryPos.set(x, world.getHeightBlocks(), z)) * 0.85F + 0.15F;
-                        }
-                        tessellator.setTranslation(-nextPosX, -nextPosY, -nextPosZ);
-                        tessellator.setColor4f(brightness, brightness, brightness, ((1.0F - f9 * f9) * 0.5F + 0.5F) * (world.getWeatherManager().getWeatherIntensity() - 0.1f) * world.getWeatherManager().getWeatherPower());
-                        tessellator.addVertexWithUV(x, j3, (double) z + 0.5D, 0.0F * f2, ((float) j3 * f2) / 4F + f4 * f2);
-                        tessellator.addVertexWithUV(x + 1, j3, (double) z + 0.5D, f2, ((float) j3 * f2) / 4F + f4 * f2);
-                        tessellator.addVertexWithUV(x + 1, l3, (double) z + 0.5D, f2, ((float) l3 * f2) / 4F + f4 * f2);
-                        tessellator.addVertexWithUV(x, l3, (double) z + 0.5D, 0.0F * f2, ((float) l3 * f2) / 4F + f4 * f2);
-
-                        tessellator.addVertexWithUV((double) x + 0.5D, j3, z, 0.0F * f2, ((float) j3 * f2) / 4F + f4 * f2);
-                        tessellator.addVertexWithUV((double) x + 0.5D, j3, z + 1, f2, ((float) j3 * f2) / 4F + f4 * f2);
-                        tessellator.addVertexWithUV((double) x + 0.5D, l3, z + 1, f2, ((float) l3 * f2) / 4F + f4 * f2);
-                        tessellator.addVertexWithUV((double) x + 0.5D, l3, z, 0.0F * f2, ((float) l3 * f2) / 4F + f4 * f2);
-                        tessellator.setTranslation(0.0D, 0.0D, 0.0D);
-                    }
+        final double lerpedX = this.mc.activeCamera.getX(partialTick);
+        final double lerpedY = this.mc.activeCamera.getY(partialTick);
+        final double lerpedZ = this.mc.activeCamera.getZ(partialTick);
+
+        final int radius = 10;
+
+        final @NotNull TilePos queryPos = new TilePos();
+
+        t.startDrawingQuads();
+
+        for (int x = cameraBlockX - radius; x <= cameraBlockX + radius; x++) {
+            for (int z = cameraBlockZ - radius; z <= cameraBlockZ + radius; z++) {
+                final int terrainHeight = Math.max(world.findTopSolidBlock(x, z), 0);
+                queryPos.set(x, terrainHeight, z);
+
+                final @NotNull Biome biome = world.getBlockBiome(queryPos);
+                if (biome.blockedWeathers.contains(weather)) {
+                    continue;
                 }
-            }
-            tessellator.draw();
-        } else if (precipitation.getPrecipitationType() == IPrecipitation.Type.INVERTED_RAIN_LIKE) {
-            tessellator.startDrawingQuads();
-            for (int x = posX - radiusEffect; x <= posX + radiusEffect; x++) {
-                blockedWeather:
-                for (int z = posZ - radiusEffect; z <= posZ + radiusEffect; z++) {
-                    int topSolidY = world.findTopSolidBlock(x, z);
-                    Biome biome = world.getBlockBiome(x, topSolidY, z);
-                    for (int i = 0; i < biome.blockedWeathers.length; i++) {
-                        if (biome.blockedWeathers[i] == weather) {
-                            continue blockedWeather;
-                        }
-                    }
-                    int j3 = posY - radiusEffect;
-                    int l3 = posY + radiusEffect;
-                    if (j3 < topSolidY) {
-                        j3 = topSolidY;
-                    }
-                    if (l3 < topSolidY) {
-                        l3 = topSolidY;
+
+                int y0 = Math.max(cameraBlockY - radius, terrainHeight);
+                int y1 = Math.max(cameraBlockY + radius, terrainHeight);
+
+                if (y0 != y1) {
+                    final long seed = x * x * 3121L + x * 45238971L + z * z * 418711L + z * 13761L;
+                    this.random.setSeed(seed);
+
+                    final double relativeX = (x + 0.5) - this.mc.activeCamera.getX(partialTick);
+                    final double relativeZ = (z + 0.5) - this.mc.activeCamera.getZ(partialTick);
+                    final float distanceSq = MathHelper.sqrt(relativeX * relativeX + relativeZ * relativeZ) / radius;
+
+                    float br;
+                    if (this.mc.fullbright) {
+                        br = 1.0f;
+                    } else {
+                        br = world.getLightBrightness(queryPos);
                     }
-                    float f2 = 1.0F;
-                    if (j3 != l3) {
-                        this.random.setSeed((long) x * x * 3121 + x * 0x2b24abbL + (long) z * z * 0x66397 + z * 13761L);
-                        float vOffset = (((float) (this.rendererUpdateCount + x * x * 3121 /*GL_RGBA_MODE*/ + x * 0x2b24abb + z * z * 0x66397 + z * 13761 & 0x1f) + partialTick) / 32F) * (3F + this.random.nextFloat());
-                        double d3 = (double) ((float) x + 0.5F) - this.mc.activeCamera.getX();
-                        double d4 = (double) ((float) z + 0.5F) - this.mc.activeCamera.getZ();
-                        float f9 = MathHelper.sqrt(d3 * d3 + d4 * d4) / (float) radiusEffect;
-                        float brightness;
-                        if (this.mc.fullbright) {
-                            brightness = 1.0f;
-                        } else {
-                            brightness = world.getLightBrightness(queryPos.set(x, world.getHeightBlocks(), z)) * 0.85F + 0.15F;
+
+                    float u, v, vOffset;
+
+                    if (precipitation.getPrecipitationType() == IPrecipitation.Type.SNOW_LIKE) {
+                        final float time = this.tick + partialTick;
+
+                        vOffset = ((this.tick & 0x1ff) + partialTick) / 512F;
+                        u = this.random.nextFloat() + time * 0.01F * (float) this.random.nextGaussian();
+                        v = this.random.nextFloat() + time * (float) this.random.nextGaussian() * 0.001F;
+
+                        t.setColor4f(br, br, br, ((1.0F - distanceSq * distanceSq) * 0.3F + 0.5F) * world.getWeatherManager().getWeatherIntensity() * world.getWeatherManager().getWeatherPower());
+                    } else if (precipitation.getPrecipitationType() == IPrecipitation.Type.RAIN_LIKE || precipitation.getPrecipitationType() == IPrecipitation.Type.INVERTED_RAIN_LIKE) {
+                        final float blockPosRainSpeed = 3.0F + this.random.nextFloat();
+
+                        vOffset = ((this.tick + seed & 0x1f) + partialTick) / 32F * blockPosRainSpeed;
+                        u = 0.0f;
+                        v = 0.0f;
+
+                        br *= 0.85f + 0.15f;
+
+                        t.setColor4f(br, br, br, ((1.0F - distanceSq * distanceSq) * 0.5F + 0.5F) * (world.getWeatherManager().getWeatherIntensity() - 0.1f) * world.getWeatherManager().getWeatherPower());
+
+                        if (precipitation.getPrecipitationType() == IPrecipitation.Type.INVERTED_RAIN_LIKE) {
+                            vOffset = -vOffset;
                         }
-                        tessellator.setColor4f(brightness, brightness, brightness, ((1.0F - f9 * f9) * 0.5F + 0.5F) * (world.getWeatherManager().getWeatherIntensity() - 0.1f) * world.getWeatherManager().getWeatherPower());
-                        tessellator.setTranslation(-nextPosX, -nextPosY, -nextPosZ);
-                        tessellator.addVertexWithUV(x, j3, (double) z + 0.5D, 0.0F * f2, ((float) j3 * f2) / 4F - vOffset * f2);
-                        tessellator.addVertexWithUV(x + 1, j3, (double) z + 0.5D, f2, ((float) j3 * f2) / 4F - vOffset * f2);
-                        tessellator.addVertexWithUV(x + 1, l3, (double) z + 0.5D, f2, ((float) l3 * f2) / 4F - vOffset * f2);
-                        tessellator.addVertexWithUV(x, l3, (double) z + 0.5D, 0.0F * f2, ((float) l3 * f2) / 4F - vOffset * f2);
-                        tessellator.addVertexWithUV((double) x + 0.5D, j3, z, 0.0F * f2, ((float) j3 * f2) / 4F - vOffset * f2);
-                        tessellator.addVertexWithUV((double) x + 0.5D, j3, z + 1, f2, ((float) j3 * f2) / 4F - vOffset * f2);
-                        tessellator.addVertexWithUV((double) x + 0.5D, l3, z + 1, f2, ((float) l3 * f2) / 4F - vOffset * f2);
-                        tessellator.addVertexWithUV((double) x + 0.5D, l3, z, 0.0F * f2, ((float) l3 * f2) / 4F - vOffset * f2);
-                        tessellator.setTranslation(0.0D, 0.0D, 0.0D);
+                    } else {
+                        throw new IllegalStateException("Illegal weather type!");
                     }
+
+                    t.setTranslation(-lerpedX, -lerpedY, -lerpedZ);
+
+                    t.addVertexWithUV(x + 0.0, y0 + 0.0, z + 0.5, 0.0 + u, y0 / 4.0 + vOffset + v);
+                    t.addVertexWithUV(x + 1.0, y0 + 0.0, z + 0.5, 1.0 + u, y0 / 4.0 + vOffset + v);
+                    t.addVertexWithUV(x + 1.0, y1 + 0.0, z + 0.5, 1.0 + u, y1 / 4.0 + vOffset + v);
+                    t.addVertexWithUV(x + 0.0, y1 + 0.0, z + 0.5, 0.0 + u, y1 / 4.0 + vOffset + v);
+
+                    t.addVertexWithUV(x + 0.5, y0 + 0.0, z + 0.0, 0.0 + u, y0 / 4.0 + vOffset + v);
+                    t.addVertexWithUV(x + 0.5, y0 + 0.0, z + 1.0, 1.0 + u, y0 / 4.0 + vOffset + v);
+                    t.addVertexWithUV(x + 0.5, y1 + 0.0, z + 1.0, 1.0 + u, y1 / 4.0 + vOffset + v);
+                    t.addVertexWithUV(x + 0.5, y1 + 0.0, z + 0.0, 0.0 + u, y1 / 4.0 + vOffset + v);
+
+                    t.setTranslation(0.0, 0.0, 0.0);
                 }
             }
-            tessellator.draw();
         }
+
+        t.draw();
         GLRenderer.popFrame();
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWater.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWater.java
index 350195a42..30818842f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWater.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWater.java
@@ -5,6 +5,7 @@ import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.colorizer.Colorizer;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 
 public class BlockColorWater extends BlockColorCustom {
@@ -17,7 +18,7 @@ public class BlockColorWater extends BlockColorCustom {
 	
 	@Override
 	public int getFallbackColor(int meta, int tintIndex) {
-		if(!GameSettings.BIOME_WATER.value || (this.mc.currentWorld != null && this.mc.currentWorld.isRetro())) {
+		if(!GameSettings.BIOME_WATER.value || (this.mc.currentWorld != null && this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.RETRO))) {
 			return 0xFFFFFFFF;
 		}
 		return super.getFallbackColor(meta, tintIndex);
@@ -25,10 +26,9 @@ public class BlockColorWater extends BlockColorCustom {
 	
 	@Override
 	public int getWorldColor(@NotNull WorldSource source, @NotNull TilePosc tilePos, int tintIndex) {
-		if(!GameSettings.BIOME_WATER.value || source.isRetro()) {
+		if(!GameSettings.BIOME_WATER.value || source.getWorldType().hasTag(WorldTypeTags.RETRO)) {
 			return 0xFFFFFFFF;
 		}
 		return super.getWorldColor(source, tilePos, tintIndex);
 	}
-
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModel.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModel.java
index 1ae54ebbe..266ea7636 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModel.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModel.java
@@ -9,6 +9,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.useless.dragonfly.DisplayPos;
@@ -41,6 +42,6 @@ public abstract class BlockModel<T extends BlockLogic> {
     }
 
     public boolean isRetro() {
-        return Minecraft.getMinecraft().currentWorld != null && Minecraft.getMinecraft().currentWorld.isRetro();
+        return Minecraft.getMinecraft().currentWorld != null && Minecraft.getMinecraft().currentWorld.getWorldType().hasTag(WorldTypeTags.RETRO);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCalendar.java b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCalendar.java
index d700b8fcd..4dea57881 100644
--- a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCalendar.java
+++ b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCalendar.java
@@ -3,6 +3,7 @@ package net.minecraft.client.render.dynamictexture;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.world.season.SeasonManagerCycle;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 
 public class DynamicTextureCalendar extends DynamicTextureAbstractClock {
 
@@ -15,7 +16,7 @@ public class DynamicTextureCalendar extends DynamicTextureAbstractClock {
 		double d = 0.0;
 		if (mc.currentWorld != null && mc.thePlayer != null)
 		{
-			if (mc.currentWorld.getSeasonManager() instanceof SeasonManagerCycle)
+			if (mc.currentWorld.getSeasonManager() instanceof SeasonManagerCycle && !mc.currentWorld.getWorldType().hasTag(WorldTypeTags.BREAKS_TIMEPIECES))
 			{
 				SeasonManagerCycle cycleManager = (SeasonManagerCycle) mc.currentWorld.getSeasonManager();
 				float f = cycleManager.getYearProgress() - 0.25f;
diff --git a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureClock.java b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureClock.java
index 90b8e3f2d..0daf8646d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureClock.java
+++ b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureClock.java
@@ -3,6 +3,7 @@ package net.minecraft.client.render.dynamictexture;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 
 public class DynamicTextureClock extends DynamicTextureAbstractClock{
 
@@ -16,7 +17,7 @@ public class DynamicTextureClock extends DynamicTextureAbstractClock{
 		if(mc.currentWorld != null && mc.thePlayer != null) {
 			float f = mc.currentWorld.getCelestialAngle(1.0f);
 			d = -f * Math.PI * 2;
-			if(mc.currentWorld.dimension == Dimension.NETHER) {
+			if(mc.currentWorld.getWorldType().hasTag(WorldTypeTags.BREAKS_TIMEPIECES)) {
 				d = Math.random() * Math.PI * 2;
 			}
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCompass.java b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCompass.java
index 8342a41c7..9fcc0fcd9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCompass.java
+++ b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCompass.java
@@ -9,6 +9,7 @@ import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.pos.TilePos;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 
 public class DynamicTextureCompass extends DynamicTexture {
 	
@@ -71,7 +72,7 @@ public class DynamicTextureCompass extends DynamicTexture {
 			double dx = (double)spawnPoint.x - this.mc.thePlayer.x;
 			double dz = (double)spawnPoint.z - this.mc.thePlayer.z;
 			angle = (double)(this.mc.thePlayer.yRot - 90.0F) * PI / 180.0D - Math.atan2(dz, dx);
-			if(this.mc.currentWorld.dimension == Dimension.NETHER) {
+			if(this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.BREAKS_COMPASS)) {
 				angle = Math.random() * PI * 2;
 			}
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureWaterFlow.java b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureWaterFlow.java
index 037cce9b5..b1ad7dc4d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureWaterFlow.java
+++ b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureWaterFlow.java
@@ -4,7 +4,7 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 
 public class DynamicTextureWaterFlow extends DynamicTexture {
@@ -69,14 +69,7 @@ public class DynamicTextureWaterFlow extends DynamicTexture {
 
 		for (int i = 0; i < this.targetTexture.getArea(); ++i) {
 			float pow = this.current[pmod(i - this.ticks * this.targetTexture.width, this.targetTexture.getArea())];
-			if (pow > 1.0F) {
-				pow = 1.0F;
-			}
-
-			if (pow < 0.0F) {
-				pow = 0.0F;
-			}
-
+			pow = MathHelper.clamp(pow, 0.0f, 1.0f);
 			float pp = pow * pow;
 
 			int r = (int) (32.0F + pp * 32.0F);
@@ -84,11 +77,15 @@ public class DynamicTextureWaterFlow extends DynamicTexture {
 			int b = 255;
 			int a = (int) (146.0F + pp * 50.0F);
 
-			if (this.mc.currentWorld != null && this.mc.currentWorld.dimension == Dimension.NETHER) {
-				r = 255;
-				g = (int) (110.0F + pp * 64.0F);
-				b = (int) (32.0F + pp * 32.0F);
+			if (this.mc.currentWorld != null && this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.NETHER)) {
 				a = (int) (225.0F + pp * 50.0F);
+
+				if (!GameSettings.BIOME_WATER.value) {
+					final float br = 0.3F;
+					r = (int) (255.0F * br);
+					g = (int) ((50.0F + pp * 64.0F) * br);
+					b = (int) ((32.0F + pp * 32.0F) * br);
+				}
 			}
 
 			r = MathHelper.clamp(r, 0, 255);
@@ -96,7 +93,7 @@ public class DynamicTextureWaterFlow extends DynamicTexture {
 			b = MathHelper.clamp(b, 0, 255);
 			a = MathHelper.clamp(a, 0, 255);
 
-			if (GameSettings.BIOME_WATER.value && !(this.mc.currentWorld != null && this.mc.currentWorld.isRetro())) {
+			if (GameSettings.BIOME_WATER.value && !(this.mc.currentWorld != null && this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.RETRO))) {
 				r = g = b = (r + g + b) / 3;
 			}
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureWaterStill.java b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureWaterStill.java
index 20f951f0f..4afa26708 100644
--- a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureWaterStill.java
+++ b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureWaterStill.java
@@ -5,6 +5,7 @@ import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -96,11 +97,15 @@ public class DynamicTextureWaterStill extends DynamicTexture {
 			int b = 255;
 			int a = (int) (146.0F + pp * 50.0F);
 
-			if (this.mc.currentWorld != null && this.mc.currentWorld.dimension == Dimension.NETHER) {
-				r = 255;
-				g = (int) (110.0F + pp * 64.0F);
-				b = (int) (32.0F + pp * 32.0F);
+			if (this.mc.currentWorld != null && this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.NETHER)) {
 				a = (int) (225.0F + pp * 50.0F);
+
+				if (!GameSettings.BIOME_WATER.value) {
+					final float br = 0.3F;
+					r = (int) (255.0F * br);
+					g = (int) ((50.0F + pp * 64.0F) * br);
+					b = (int) ((32.0F + pp * 32.0F) * br);
+				}
 			}
 
 			r = MathHelper.clamp(r, 0, 255);
@@ -108,7 +113,7 @@ public class DynamicTextureWaterStill extends DynamicTexture {
 			b = MathHelper.clamp(b, 0, 255);
 			a = MathHelper.clamp(a, 0, 255);
 
-			if (GameSettings.BIOME_WATER.value && !(this.mc.currentWorld != null && this.mc.currentWorld.isRetro())) {
+			if (GameSettings.BIOME_WATER.value && !(this.mc.currentWorld != null && this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.RETRO))) {
 				r = g = b = (r + g + b) / 3;
 			}
 
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 bfe1b2801..0d935ae3a 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
@@ -37,7 +37,6 @@ import org.joml.Vector3fc;
 
 public class WorldClient extends World {
     private final @NotNull Minecraft mc;
-    private int lightningFlicker;
 
     public WorldClient(
         final @NotNull Minecraft mc,
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/cobbled_basalt_mossy.png b/game/client/src/main/resources/assets/minecraft/textures/block/cobbled_basalt_mossy.png
index 3c9d02479..fe4b8de57 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/cobbled_basalt_mossy.png and b/game/client/src/main/resources/assets/minecraft/textures/block/cobbled_basalt_mossy.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/ore/nethercoal/basalt.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/ore/nethercoal/basalt.emiss.png
new file mode 100644
index 000000000..522d504c0
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/ore/nethercoal/basalt.emiss.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/ore/nethercoal/basalt.png b/game/client/src/main/resources/assets/minecraft/textures/block/ore/nethercoal/basalt.png
new file mode 100644
index 000000000..6b28a2f0e
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/ore/nethercoal/basalt.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/colormap/water/nether.png b/game/client/src/main/resources/assets/minecraft/textures/colormap/water/nether.png
index 9033cac9e..9e48e7ec9 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/colormap/water/nether.png and b/game/client/src/main/resources/assets/minecraft/textures/colormap/water/nether.png differ
diff --git a/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java b/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java
index 3dc8201c5..f0209e5ad 100644
--- a/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java
+++ b/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java
@@ -137,10 +137,6 @@ public abstract class Achievements
         new Achievement(NamespaceID.fromPool("minecraft", "sleep_nether"), "sleepNether", Items.BED, ENTER_NETHER)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
-//    public static Achievement ENTER_WARRENS =
-//        new Achievement(NamespaceID.getPermanentNamespaceID("minecraft", "enter_warrens"), "enterWarrens", Blocks.BEDROCK, ENTER_NETHER)
-//            .setType(Achievement.TYPE_NORMAL)
-//            .registerAchievement();
     public static Achievement MOST_WANTED =
         new Achievement(NamespaceID.fromPool("minecraft", "most_wanted"), "mostWanted", Items.TOOL_SWORD_GOLD, ENTER_NETHER)
             .setType(Achievement.TYPE_NORMAL)
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
index 4571d9d7b..2dffdb031 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
@@ -7,9 +7,13 @@ import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -44,6 +48,10 @@ public class BlockLogicIce extends BlockLogicTransparent {
     @Override
 	public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick)
     {
+        if (isRandomTick && rand.nextInt(8) == 0 && world.getWorldType().hasTag(WorldTypeTags.HOT)) {
+            world.setBlockTypeNotify(tilePos, Blocks.FLUID_WATER_STILL);
+        }
+
         if(world.getSavedLightValue(LightLayer.Block, tilePos) > 11 - this.block.lightBlock())
         {
             world.setBlockTypeNotify(tilePos, Blocks.FLUID_WATER_STILL);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
index 61f712082..c4d25e101 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
@@ -10,6 +10,7 @@ import net.minecraft.core.item.Items;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
@@ -85,7 +86,7 @@ public class BlockLogicLayerSnow extends BlockLogicLayerBase {
             dropWithCause(world, EnumDropCause.WORLD, tilePos, world.getBlockData(tilePos), null, null);
             world.setBlockTypeNotify(tilePos, Blocks.AIR);
         }
-        if (!world.getBlockBiome(tilePos).hasSurfaceSnow() && world.getSeasonManager().getCurrentSeason() != null && world.getSeasonManager().getCurrentSeason().letWeatherCleanUpSnow) {
+        if (!world.getBlockBiome(tilePos).hasTag(BiomeTags.HAS_SURFACE_SNOW) && world.getSeasonManager().getCurrentSeason() != null && world.getSeasonManager().getCurrentSeason().letWeatherCleanUpSnow) {
             dropWithCause(world, EnumDropCause.WORLD, tilePos, world.getBlockData(tilePos), null, null);
             world.setBlockTypeNotify(tilePos, Blocks.AIR);
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMud.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMud.java
index 2adfb8081..4a1a2e60f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMud.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMud.java
@@ -11,6 +11,7 @@ import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -146,7 +147,7 @@ public class BlockLogicMud extends BlockLogic {
 
         // dry out mud
         if (!this.isHardened) {
-            if (isLavaNearby(world, tilePos) || world.dimension == Dimension.NETHER) {
+            if (isLavaNearby(world, tilePos) || world.getWorldType().hasTag(WorldTypeTags.HOT)) {
                 world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, tilePos.x() + 0.5D, tilePos.y() + 0.5D, tilePos.z() + 0.5D, "random.fizz", 0.5F, 2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F);
                 for (int l = 0; l < 8; l++) {
                     world.spawnParticle("largesmoke", (double) tilePos.x() + Math.random(), (double) tilePos.y() + Math.random(), (double) tilePos.z() + Math.random(), 0.0D, 0.0D, 0.0D, 0);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPumice.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPumice.java
index c1cbb98a1..b3eab3a36 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPumice.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPumice.java
@@ -8,6 +8,7 @@ import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -24,7 +25,7 @@ public class BlockLogicPumice extends BlockLogic {
     public void onPlacedByWorld(@NotNull World world, @NotNull TilePosc tilePos) {
         super.onPlacedByWorld(world, tilePos);
         byte radius = 2;
-        if (this.isWet && (inWater(world, tilePos) || world.dimension.id == Dimension.DRIFT.id)) {
+        if (this.isWet && (inWater(world, tilePos) || world.getWorldType().hasTag(WorldTypeTags.COLD))) {
             world.setBlockTypeNotify(tilePos, Blocks.PUMICE_DRY);
             world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, tilePos.x() + 0.5D, tilePos.y() + 0.5D, tilePos.z() + 0.5D, "random.fizz", 0.5F, 2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F);
             for (int l = 0; l < 8; l++) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrop.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrop.java
index 5535bbe5d..5b7d27d88 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrop.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrop.java
@@ -11,6 +11,7 @@ import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.joml.primitives.AABBd;
@@ -118,7 +119,7 @@ public class BlockLogicRubyglassCrop extends BlockLogic {
 
     private float getGrowthRate (final @NotNull World world, final @NotNull TilePosc tilePos) {
         float growthRate = 0F;
-        if(world.dimension == Dimension.NETHER) {
+        if(world.getWorldType().hasTag(WorldTypeTags.HOT)) {
             growthRate = 5F;
         }
         else if(isLavaNearby(world, tilePos)) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSponge.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSponge.java
index 4880f4825..e839161c1 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSponge.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSponge.java
@@ -9,6 +9,7 @@ import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -24,7 +25,7 @@ public class BlockLogicSponge extends BlockLogic {
     @Override
     public void onPlacedByWorld(@NotNull World world, @NotNull TilePosc tilePos) {
         super.onPlacedByWorld(world, tilePos);
-        if ((world.dimension == Dimension.NETHER || inHot(world, tilePos)) && this.isWet) {
+        if ((world.getWorldType().hasTag(WorldTypeTags.HOT) || inHot(world, tilePos)) && this.isWet) {
             world.setBlockTypeNotify(tilePos, Blocks.SPONGE_DRY);
             world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, tilePos.x() + 0.5D, tilePos.y() + 0.5D, tilePos.z() + 0.5D, "random.fizz", 0.5F, 2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F);
             for (int l = 0; l < 8; l++) {
@@ -39,7 +40,6 @@ public class BlockLogicSponge extends BlockLogic {
                     for (queryPos.z = tilePos.z() - radius; queryPos.z <= tilePos.z() + radius; queryPos.z++) {
                         if (world.getBlockType(queryPos).hasTag(BlockTags.IS_WATER)) {
                             world.setBlockTypeNotify(queryPos, Blocks.AIR);
-
                         }
                     }
                 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/FluidLava.java b/game/core/src/main/java/net/minecraft/core/block/FluidLava.java
index 47d0f217d..c37bb89a0 100644
--- a/game/core/src/main/java/net/minecraft/core/block/FluidLava.java
+++ b/game/core/src/main/java/net/minecraft/core/block/FluidLava.java
@@ -6,6 +6,7 @@ import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -41,7 +42,7 @@ public class FluidLava
         if (encountered == Materials.WATER) {
             final int data = world.getBlockData(tilePos) & 0x0F;
 
-            if (world.dimension == Dimension.NETHER) {
+            if (world.getWorldType().hasTag(WorldTypeTags.NETHER)) {
                 if (data == 0) {
                     world.setBlockTypeNotify(tilePos, Blocks.MAGMA);
                 } else {
@@ -106,7 +107,7 @@ public class FluidLava
 
     @Override
     public byte getFlowDecayMod(final @NotNull BlockLogicFluid logicFluid, final @NotNull World world, final @NotNull TilePosc tilePos) {
-        if (world.dimension == Dimension.NETHER) {
+        if (world.getWorldType().hasTag(WorldTypeTags.NETHER)) {
             return 1;
         } else {
             return 2;
diff --git a/game/core/src/main/java/net/minecraft/core/block/FluidWater.java b/game/core/src/main/java/net/minecraft/core/block/FluidWater.java
index dc72e0456..e9484a1fa 100644
--- a/game/core/src/main/java/net/minecraft/core/block/FluidWater.java
+++ b/game/core/src/main/java/net/minecraft/core/block/FluidWater.java
@@ -8,6 +8,7 @@ import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -29,7 +30,7 @@ public class FluidWater
                 world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (float) tilePos.x() + 0.5F, (float) tilePos.y() + 0.5F, (float) tilePos.z() + 0.5F, "liquid.water", rand.nextFloat() * 0.25F + 0.75F, rand.nextFloat() * 1.0F + 0.5F);
             }
         }
-        if (world.dimension == Dimension.NETHER && isTop && data == 0 && rand.nextInt(4) == 0) {
+        if (world.getWorldType().hasTag(WorldTypeTags.NETHER) && isTop && data == 0 && rand.nextInt(4) == 0) {
             world.spawnParticle("smoke", tilePos.x() + Math.random(), tilePos.y() + (14f / 16f), tilePos.z() + Math.random(), 0.0D, 0.0D, 0.0D, 1);
         }
 
@@ -46,7 +47,7 @@ public class FluidWater
         if (encountered == Materials.LAVA) {
             final int data = world.getBlockData(tilePos) & 0x0F;
             if (data == 0) {
-                if (world.dimension == Dimension.NETHER) {
+                if (world.getWorldType().hasTag(WorldTypeTags.NETHER)) {
                     world.setBlockTypeNotify(tilePos, Blocks.NETHERRACK);
                 } else {
                     world.setBlockTypeNotify(tilePos, Blocks.COBBLE_LIMESTONE);
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Entity.java b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
index 09103a1ed..0276d2e48 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Entity.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
@@ -31,6 +31,7 @@ import net.minecraft.core.world.World;
 import net.minecraft.core.world.data.SynchedEntityData;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.joml.Vector3dc;
@@ -340,7 +341,7 @@ public abstract class Entity
     }
 
     public void waterHurt() {
-        if (this.world.dimension == Dimension.NETHER && !(this.vehicle instanceof EntityBoat)) {
+        if (this.world.getWorldType().hasTag(WorldTypeTags.HOT) && !(this.vehicle instanceof EntityBoat)) {
             hurt(null, 1, DamageType.FIRE);
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java
index d38f53965..34ef4b625 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java
@@ -443,7 +443,7 @@ public class MobFireflyCluster extends MobFlying
             Biomes.NETHER_SULFUR_POOLS,
             Biomes.NETHER_VOLCANIC_ISLANDS,
             Biomes.NETHER_CRYSTAL_FOREST,
-            Biomes.NETHER_CRYSTAL_FIELD,
+            Biomes.NETHER_CRYSTAL_PLAINS,
             Biomes.NETHER_OLD_WORLD
         },
             new float[]{1f, 0.25f, 0.25f}));
diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
index 7169b1449..16f6e6112 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -57,6 +57,7 @@ import net.minecraft.core.world.chunk.ChunkCoordinates;
 import net.minecraft.core.world.chunk.provider.ChunkProvider;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import net.minecraft.core.world.weather.Weathers;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -248,13 +249,8 @@ public abstract class Player
 
     @Override
     public void tick() {
-        if (this.world.dimension == Dimension.NETHER) {
+        if (this.world.getDimension() == Dimension.NETHER) {
             addStat(Achievements.ENTER_NETHER, 1);
-            /*if (y >=128) {
-                addStat(Achievements.ENTER_NETHER, 1);
-            }  else {
-                addStat(Achievements.ENTER_WARRENS, 1);
-            }*/
         }
 
         this.xdO = this.xd;
@@ -1353,7 +1349,7 @@ public abstract class Player
             int j = java.lang.Math.round(MathHelper.sqrt(d * d + d2 * d2) * 100F);
             if (j > 0) {
                 addStat(StatList.distanceSwumStat, j);
-                if (this.dimension == Dimension.NETHER.id) {
+                if (this.world.getDimension() == Dimension.NETHER) {
                     addStat(Achievements.SWIM_NETHER, 1);
                 }
             }
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
index 0d632252a..ed98f02db 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
@@ -10,7 +10,10 @@ import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
@@ -47,7 +50,7 @@ public class ItemBucket extends Item {
         }
 
         Block<?> block = world.getBlockType(rayCastPos);
-        if (block != null && !block.hasTag(BlockTags.PLACE_OVERWRITES) && !block.hasTag(BlockTags.BROKEN_BY_FLUIDS)) {
+        if (!block.hasTag(BlockTags.PLACE_OVERWRITES) && !block.hasTag(BlockTags.BROKEN_BY_FLUIDS)) {
             Side side = hitTile.side;
             rayCastPos.x += side.getOffsetX();
             rayCastPos.y += side.getOffsetY();
@@ -62,9 +65,10 @@ public class ItemBucket extends Item {
             if (this.blockToPlace == Blocks.FLUID_WATER_FLOWING) {
                 world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, rayCastPos.x + 0.5F, rayCastPos.y + 0.5F, rayCastPos.z + 0.5F, "liquid.splash", 0.5f, 1.0f);
             }
-            player.swingItem();
-            world.getBlockType(rayCastPos).dropWithCause(world, EnumDropCause.WORLD, rayCastPos, world.getBlockData(rayCastPos), null, null);
             world.setBlockTypeNotify(rayCastPos, this.blockToPlace);
+            world.getBlockType(rayCastPos).dropWithCause(world, EnumDropCause.WORLD, rayCastPos, world.getBlockData(rayCastPos), null, null);
+
+            player.swingItem();
             if (player.getGamemode().hasBlockConsumption()) {
                 return new ItemStack(Items.BUCKET);
             }
@@ -83,6 +87,8 @@ public class ItemBucket extends Item {
         Block<?> b = world.getBlockType(posAhead);
         if (b.hasTag(BlockTags.PLACE_OVERWRITES) || b.hasTag(BlockTags.BROKEN_BY_FLUIDS)) {
             world.setBlockTypeNotify(posAhead, this.blockToPlace);
+            world.getBlockType(posAhead).dropWithCause(world, EnumDropCause.WORLD, posAhead, world.getBlockData(posAhead), null, null);
+
             selfStack.itemID = Items.BUCKET.id;
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemDye.java b/game/core/src/main/java/net/minecraft/core/item/ItemDye.java
index 79e60efb6..6a748984f 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemDye.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemDye.java
@@ -20,6 +20,7 @@ import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.type.WorldTypes;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -63,7 +64,7 @@ public class ItemDye extends Item {
                 if (!world.isClientSide) {
                     if (world.getBlockType(blockPos.up(queryPos)).lightBlock() <= 2) {
                         @NotNull Block<?> grass = Blocks.GRASS;
-                        if (world.getDimensionData().getWorldType().isRetro()) {
+                        if (world.getDimensionData().getWorldType().hasTag(WorldTypeTags.RETRO)) {
                             grass = Blocks.GRASS_RETRO;
                         }
                         world.setBlockTypeNotify(blockPos, grass);
diff --git a/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java b/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
index 4b8e0a4b8..ad07a83ce 100644
--- a/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
+++ b/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
@@ -11,6 +11,7 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.season.SeasonManager;
+import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.weather.WeatherManager;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -29,6 +30,16 @@ public class BlocksContainer implements MutableWorldSource {
         this.world = world;
     }
 
+    @Override
+    public @NotNull Dimension getDimension() {
+        return this.world.getDimension();
+    }
+
+    @Override
+    public @NotNull WorldType getWorldType() {
+        return this.world.getWorldType();
+    }
+
     @Override
     public int getHeightBlocks() {
         return this.world.getHeightBlocks();
@@ -224,11 +235,6 @@ public class BlocksContainer implements MutableWorldSource {
         return this.world.getSavedLightIndex(tilePos);
     }
 
-    @Override
-    public boolean isRetro() {
-        return this.world.isRetro();
-    }
-
     public static class BlockEntry {
         public @NotNull Block<?> block;
         public int data;
diff --git a/game/core/src/main/java/net/minecraft/core/world/MutableWorldSource.java b/game/core/src/main/java/net/minecraft/core/world/MutableWorldSource.java
index 6d65e1c58..f19263be2 100644
--- a/game/core/src/main/java/net/minecraft/core/world/MutableWorldSource.java
+++ b/game/core/src/main/java/net/minecraft/core/world/MutableWorldSource.java
@@ -15,51 +15,51 @@ public interface MutableWorldSource
 
     boolean setBlockType(final @NotNull TilePosc tilePos, final @NotNull Block<?> block);
 
+    boolean setBlockData(final @NotNull TilePosc tilePos, final int data);
+
+    boolean setBlockTypeData(final @NotNull TilePosc tilePos, final @NotNull Block<?> block, final int data);
+
+    void setLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePosc tilePos, final int value);
+
+    void setTileEntity(final @NotNull TilePosc tilePos, final @NotNull TileEntity tileEntity);
+
+    void removeTileEntity(final @NotNull TilePosc tilePos);
+
+    default void replaceTileEntity(final @NotNull TilePosc tilePos, final @NotNull TileEntity tileEntity) {
+        this.removeTileEntity(tilePos);
+        this.setTileEntity(tilePos, tileEntity);
+    }
+
     @Deprecated
     default boolean setBlock(final int x, final int y, final int z, final int id) {
         return this.setBlockType(new TilePos(x, y, z), Objects.requireNonNull(Blocks.getBlock(id)));
     }
 
-    boolean setBlockData(final @NotNull TilePosc tilePos, final int data);
-
     @Deprecated
     default boolean setBlockMetadata(final int x, final int y, final int z, final int data) {
         return this.setBlockData(new TilePos(x, y, z), data);
     }
 
-    boolean setBlockTypeData(final @NotNull TilePosc tilePos, final @NotNull Block<?> block, final int data);
-
     @Deprecated
     default boolean setBlockAndMetadata(final int x, final int y, final int z, final int id, final int data) {
         return this.setBlockTypeData(new TilePos(x, y, z), Objects.requireNonNull(Blocks.getBlock(id)), data);
     }
 
-    void setLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePosc tilePos, final int value);
-
     @Deprecated
     default void setLightValue(final @NotNull LightLayer lightLayer, final int x, final int y, final int z, final int value) {
         this.setLightValue(lightLayer, new TilePos(x, y, z), value);
     }
 
-    void setTileEntity(final @NotNull TilePosc tilePos, final @NotNull TileEntity tileEntity);
-
     @Deprecated
     default void setTileEntity(final int x, final int y, final int z, final @NotNull TileEntity tileEntity) {
         this.setTileEntity(new TilePos(x, y, z), tileEntity);
     }
 
-    void removeTileEntity(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default void removeBlockTileEntity(final int x, final int y, final int z) {
         this.removeTileEntity(new TilePos(x, y, z));
     }
 
-    default void replaceTileEntity(final @NotNull TilePosc tilePos, final @NotNull TileEntity tileEntity) {
-        this.removeTileEntity(tilePos);
-        this.setTileEntity(tilePos, tileEntity);
-    }
-
     @Deprecated
     default void replaceBlockTileEntity(final int x, final int y, final int z, final @NotNull TileEntity tileEntity) {
         this.replaceTileEntity(new TilePos(x, y, z), tileEntity);
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 63af916b6..c93a4b9e0 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
@@ -259,6 +259,13 @@ public abstract class World implements MutableWorldSource {
         return this.dimensionData.getDimensionSettings().getNodeValueOr(node, or);
     }
 
+    @Override
+    public @NotNull Dimension getDimension() {
+        return this.dimension;
+    }
+
+
+
     public abstract void setLightningFlicker(final int flicker);
 
     public <T> T getGameRuleValue(final GameRule<T> gameRule) {
@@ -895,11 +902,6 @@ public abstract class World implements MutableWorldSource {
         }
     }
 
-    @Override
-    public boolean isRetro() {
-        return this.getWorldType().isRetro();
-    }
-
     @Override
     public void setLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePosc tilePos, final int value) {
         if (tilePos.inBounds(this) && this.isBlockLoaded(tilePos)) {
@@ -2795,6 +2797,7 @@ public abstract class World implements MutableWorldSource {
         this.playBlockEvent(player, new TilePos(x, y, z), id, data);
     }
 
+    @Override
     public @NotNull WorldType getWorldType() {
         return this.dimensionData.getWorldType();
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/WorldSource.java b/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
index fc1ca427e..109828112 100644
--- a/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
+++ b/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
@@ -9,6 +9,7 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.season.SeasonManager;
+import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.weather.WeatherManager;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -16,129 +17,131 @@ import org.jetbrains.annotations.Nullable;
 public interface WorldSource {
     int getHeightBlocks();
 
+    @NotNull Block<?> getBlockType(final @NotNull TilePosc tilePos);
+
+    @Nullable TileEntity getTileEntity(final @NotNull TilePosc tilePos);
+
+    default <T> @Nullable T getBlockLogic(final @NotNull TilePosc tilePos, final @NotNull Class<T> logicClass) {
+        final @NotNull Block<?> block = this.getBlockType(tilePos);
+        final @NotNull BlockLogic logic = block.getLogic();
+        if (logicClass.isAssignableFrom(logic.getClass())) {
+            return logicClass.cast(logic);
+        }
+
+        return null;
+    }
+
+    float getBrightness(final @NotNull TilePosc tilePos, final int lightEmission);
+
+    byte getLightIndex(final @NotNull TilePosc tilePos, final int lightEmission);
+
+    float getLightBrightness(final @NotNull TilePosc tilePos);
+
+    int getBlockData(final @NotNull TilePosc tilePos);
+
     @Deprecated
     default int getBlockId(final int x, final int y, final int z) {
         return this.getBlockType(new TilePos(x, y, z)).id();
     }
 
-    @NotNull Block<?> getBlockType(final @NotNull TilePosc tilePos);
+    @NotNull Material getBlockMaterial(final @NotNull TilePosc tilePos);
+
+    boolean isBlockOpaqueCube(final @NotNull TilePosc tilePos);
+
+    boolean isBlockNormalCube(final @NotNull TilePosc tilePos);
+
+    double getBlockTemperature(final @NotNull TilePosc tilePos);
+
+    double getBlockHumidity(final @NotNull TilePosc tilePos);
+
+    double getBlockVariety(final @NotNull TilePosc tilePos);
+
+    @NotNull SeasonManager getSeasonManager();
+
+    @NotNull WeatherManager getWeatherManager();
+
+    @NotNull Biome getBlockBiome(final @NotNull TilePosc tilePos);
+
+    int getSavedLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePosc tilePos);
+
+    byte getSavedLightIndex(@NotNull TilePosc tilePos);
+
+    @NotNull Dimension getDimension();
+
+    @NotNull WorldType getWorldType();
 
     @Deprecated
     default @NotNull Block<?> getBlock(final int x, final int y, final int z) {
         return this.getBlockType(new TilePos(x, y, z));
     }
 
-    @Nullable TileEntity getTileEntity(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default @Nullable TileEntity getTileEntity(final int x, final int y, final int z) {
         return this.getTileEntity(new TilePos(x, y, z));
     }
 
-    default <T> @Nullable T getBlockLogic(final @NotNull TilePosc tilePos, final @NotNull Class<T> logicClass) {
-        final @NotNull Block<?> block = this.getBlockType(tilePos);
-        final @NotNull BlockLogic logic = block.getLogic();
-        if (logicClass.isAssignableFrom(logic.getClass())) {
-            return logicClass.cast(logic);
-        }
-
-        return null;
-    }
-
     @Deprecated
     default <T> @Nullable T getBlockLogic(final int x, final int y, final int z, final @NotNull Class<T> logicClass) {
         return this.getBlockLogic(new TilePos(x, y, z), logicClass);
     }
 
-    float getBrightness(final @NotNull TilePosc tilePos, final int lightEmission);
-
     @Deprecated
     default float getBrightness(final int x, final int y, final int z, final int lightEmission) {
         return this.getBrightness(new TilePos(x, y, z), lightEmission);
     }
 
-    byte getLightIndex(final @NotNull TilePosc tilePos, final int lightEmission);
-
     @Deprecated
     default byte getLightmapCoord(final int x, final int y, final int z, final int lightEmission) {
         return this.getLightIndex(new TilePos(x, y, z), lightEmission);
     }
 
-    float getLightBrightness(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default float getLightBrightness(final int x, final int y, final int z) {
         return this.getLightBrightness(new TilePos(x, y, z));
     }
 
-    int getBlockData(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default int getBlockMetadata(final int x, final int y, final int z) {
         return this.getBlockData(new TilePos(x, y, z));
     }
 
-    @NotNull Material getBlockMaterial(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default @NotNull Material getBlockMaterial(final int x, final int y, final int z) {
         return this.getBlockMaterial(new TilePos(x, y, z));
     }
 
-    boolean isBlockOpaqueCube(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default boolean isBlockOpaqueCube(final int x, final int y, final int z) {
         return this.isBlockOpaqueCube(new TilePos(x, y, z));
     }
 
-    boolean isBlockNormalCube(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default boolean isBlockNormalCube(final int x, final int y, final int z) {
         return this.isBlockNormalCube(new TilePos(x, y, z));
     }
 
-    double getBlockTemperature(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default double getBlockTemperature(final int x, final int z) {
         return this.getBlockTemperature(new TilePos(x, 0, z));
     }
 
-    double getBlockHumidity(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default double getBlockHumidity(final int x, final int z) {
         return this.getBlockHumidity(new TilePos(x, 0, z));
     }
 
-    double getBlockVariety(final @NotNull TilePosc tilePos);
-
     @Deprecated
     default double getBlockVariety(final int x, final int z) {
         return this.getBlockVariety(new TilePos(x, 0, z));
     }
 
-    @NotNull SeasonManager getSeasonManager();
-
-    @NotNull WeatherManager getWeatherManager();
-
-    @NotNull Biome getBlockBiome(final @NotNull TilePosc tilePos);
-
     @Deprecated
-    default @Nullable Biome getBlockBiome(final int x, final int y, final int z) {
+    default @NotNull Biome getBlockBiome(final int x, final int y, final int z) {
         return this.getBlockBiome(new TilePos(x, y, z));
     }
 
-    int getSavedLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePosc tilePos);
-
-    byte getSavedLightIndex(@NotNull TilePosc tilePos);
-
     @Deprecated
     default int getSavedLightValue(final @NotNull LightLayer layer, final int x, final int y, final int z) {
         return this.getSavedLightValue(layer, new TilePos(x, y, z));
     }
-
-    boolean isRetro();
 }
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 8f3503e9d..28ade554b 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
@@ -1,6 +1,8 @@
 package net.minecraft.core.world.biome;
 
 import net.minecraft.core.block.Blocks;
+import net.minecraft.core.data.tag.ITaggable;
+import net.minecraft.core.data.tag.Tag;
 import net.minecraft.core.entity.SpawnListEntry;
 import net.minecraft.core.entity.animal.MobButterfly;
 import net.minecraft.core.entity.animal.MobChicken;
@@ -27,140 +29,131 @@ import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.weather.Weather;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.Range;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 
 public class Biome
-{
-	public final String translationKey;
+    implements ITaggable<Biome> {
+
+    public final @NotNull String translationKey;
     public int color = 0xFF00FF;
-    public short topBlock;
-    public short fillerBlock;
-    public Weather[] blockedWeathers = new Weather[0];
-    protected @NotNull List<@NotNull SpawnListEntry> spawnableMonsterList = new ArrayList<>();
-    protected @NotNull List<@NotNull SpawnListEntry> spawnableCreatureList = new ArrayList<>();
-    protected @NotNull List<@NotNull SpawnListEntry> spawnableWaterCreatureList = new ArrayList<>();
-    protected @NotNull List<@NotNull SpawnListEntry> spawnableAmbientCreatureList = new ArrayList<>();
-    private boolean hasSurfaceSnow = false;
-    private boolean hasSurfaceIce = false;
+    public final @NotNull List<@NotNull Weather> blockedWeathers = new ArrayList<>();
+    protected final @NotNull List<@NotNull SpawnListEntry> spawnableMonsterList = new ArrayList<>();
+    protected final @NotNull List<@NotNull SpawnListEntry> spawnableCreatureList = new ArrayList<>();
+    protected final @NotNull List<@NotNull SpawnListEntry> spawnableWaterCreatureList = new ArrayList<>();
+    protected final @NotNull List<@NotNull SpawnListEntry> spawnableAmbientCreatureList = new ArrayList<>();
     public float defaultTemperature = 0.5f;
     public float defaultHumidity = 0.5f;
     public float defaultVariety = 0.5f;
-    
-    public Biome(String key)
-    {
-    	this.translationKey = "biome." + key;
-        this.topBlock = (short) Blocks.GRASS.id();
-        this.fillerBlock = (short)Blocks.DIRT.id();
-        this.spawnableMonsterList.add(new SpawnListEntry(MobSpider.class, 10));
-        this.spawnableMonsterList.add(new SpawnListEntry(MobZombie.class, 10));
-        this.spawnableMonsterList.add(new SpawnListEntry(MobZombieArmored.class, 2));
-        this.spawnableMonsterList.add(new SpawnListEntry(MobSkeleton.class, 10));
-        this.spawnableMonsterList.add(new SpawnListEntry(MobCreeper.class, 10));
-        this.spawnableMonsterList.add(new SpawnListEntry(MobSlime.class, 10));
-        this.spawnableMonsterList.add(new SpawnListEntry(MobSnowman.class, 2));
-        this.spawnableCreatureList.add(new SpawnListEntry(MobSheep.class, 102));
-        this.spawnableCreatureList.add(new SpawnListEntry(MobPig.class, 102));
-        this.spawnableCreatureList.add(new SpawnListEntry(MobChicken.class, 102));
-        this.spawnableCreatureList.add(new SpawnListEntry(MobCow.class, 102));
-        this.spawnableCreatureList.add(new SpawnListEntry(MobDeer.class, 10));
-        this.spawnableWaterCreatureList.add(new SpawnListEntry(MobSquid.class, 10));
-        this.spawnableAmbientCreatureList.add(new SpawnListEntry(MobFireflyCluster.class, 10));
-        this.spawnableAmbientCreatureList.add(new SpawnListEntry(MobButterfly.class, 65));
+    private @NotNull SurfaceProperties surfaceProperties;
+
+    public Biome(final @NotNull String key) {
+        this.translationKey = "biome." + key;
+        this.surfaceProperties = new SurfaceProperties.Builder().build();
+        Biome.initSpawnables(
+            this.spawnableMonsterList,
+            this.spawnableCreatureList,
+            this.spawnableWaterCreatureList,
+            this.spawnableAmbientCreatureList
+        );
+    }
+
+    static void initSpawnables(
+        final @NotNull List<@NotNull SpawnListEntry> monsters,
+        final @NotNull List<@NotNull SpawnListEntry> creatures,
+        final @NotNull List<@NotNull SpawnListEntry> waterCreatures,
+        final @NotNull List<@NotNull SpawnListEntry> ambientCreatures
+    ) {
+        monsters.add(new SpawnListEntry(MobSpider.class, 10));
+        monsters.add(new SpawnListEntry(MobZombie.class, 10));
+        monsters.add(new SpawnListEntry(MobZombieArmored.class, 2));
+        monsters.add(new SpawnListEntry(MobSkeleton.class, 10));
+        monsters.add(new SpawnListEntry(MobCreeper.class, 10));
+        monsters.add(new SpawnListEntry(MobSlime.class, 10));
+        monsters.add(new SpawnListEntry(MobSnowman.class, 2));
+        creatures.add(new SpawnListEntry(MobSheep.class, 102));
+        creatures.add(new SpawnListEntry(MobPig.class, 102));
+        creatures.add(new SpawnListEntry(MobChicken.class, 102));
+        creatures.add(new SpawnListEntry(MobCow.class, 102));
+        creatures.add(new SpawnListEntry(MobDeer.class, 10));
+        waterCreatures.add(new SpawnListEntry(MobSquid.class, 10));
+        ambientCreatures.add(new SpawnListEntry(MobFireflyCluster.class, 10));
+        ambientCreatures.add(new SpawnListEntry(MobButterfly.class, 65));
     }
 
-    public @NotNull Biome setDefaults(final float temperature, final float humidity, final float variety) {
+    public @NotNull Biome withPlacementDefaults(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)
-        {
-            return new WorldFeatureTreeFancy(Blocks.LEAVES_OAK.id(), Blocks.LOG_OAK.id());
-        } else
-        {
-            return new WorldFeatureTree(Blocks.LEAVES_OAK.id(), Blocks.LOG_OAK.id(), 4);
+    @SafeVarargs
+    public final @NotNull Biome withTags(final @NotNull Tag<Biome>... tags) {
+        for (final @NotNull Tag<Biome> tag : tags) {
+            tag.tag(this);
         }
+
+        return this;
     }
 
-    public Biome setColor(int color)
-    {
+    public @NotNull Biome withDebugColor(final int color) {
         this.color = color;
         return this;
     }
 
-    public int getSkyColor(float temperature)
-    {
+    public @NotNull Biome withBlockedWeathers(final @NotNull Weather... blocked) {
+        this.blockedWeathers.clear();
+        this.blockedWeathers.addAll(Arrays.asList(blocked));
+        return this;
+    }
+
+    public @NotNull Biome withSurfaceProperties(final @NotNull SurfaceProperties surfaceProperties) {
+        this.surfaceProperties = surfaceProperties;
+        return this;
+    }
+
+    public @NotNull SurfaceProperties getSurfaceProperties() {
+        return this.surfaceProperties;
+    }
+
+    public @NotNull WorldFeature getTreeFeature(final @NotNull Random random) {
+        if (random.nextInt(10) == 0) {
+            return new WorldFeatureTreeFancy(Blocks.LEAVES_OAK.id(), Blocks.LOG_OAK.id());
+        } else {
+            return new WorldFeatureTree(Blocks.LEAVES_OAK.id(), Blocks.LOG_OAK.id(), 4);
+        }
+    }
+
+    public int getSkyColor(float temperature) {
         temperature /= 3F;
-        if(temperature < -1F)
-        {
+        if (temperature < -1F) {
             temperature = -1F;
         }
-        if(temperature > 1.0F)
-        {
+        if (temperature > 1.0F) {
             temperature = 1.0F;
         }
+        // todo: remove AWT dependency
         return java.awt.Color.getHSBColor(0.6222222F - temperature * 0.125F, 0.5F + temperature * 0.1F, 1.0F).getRGB();
     }
 
-    public @NotNull List<@NotNull SpawnListEntry> getSpawnableList(final @NotNull MobCategory creatureType)
-    {
-        return switch (creatureType) {
+    public @NotNull List<@NotNull SpawnListEntry> getSpawnableList(final @NotNull MobCategory category) {
+        return switch (category) {
             case MONSTER -> this.spawnableMonsterList;
             case CREATURE -> this.spawnableCreatureList;
             case WATER_CREATURE -> this.spawnableWaterCreatureList;
             case AMBIENT -> this.spawnableAmbientCreatureList;
         };
     }
-    
-    public boolean hasSurfaceSnow()
-    {
-    	return this.hasSurfaceSnow;
-    }
-
-    public boolean hasSurfaceIce() {
-        return this.hasSurfaceIce;
-    }
-
-    public Biome setSurfaceSnow()
-    {
-        this.hasSurfaceSnow = true;
-    	return this;
-    }
-
-    public Biome setSurfaceIce() {
-        this.hasSurfaceIce = true;
-        return this;
-    }
-
-    public Biome setBlockedWeathers(Weather... blocked)
-    {
-    	this.blockedWeathers = blocked;
-    	return this;
-    }
 
-    public Biome setTopBlock(int id)
-    {
-        this.topBlock = (short)id;
-        return this;
-    }
-
-    public Biome setFillerBlock(int id)
-    {
-        this.fillerBlock = (short)id;
-        return this;
-    }
-
-    public static @Nullable TilePosc getBiomeCoords(@NotNull Biome biome, @NotNull World world) {
-        int[] xPattern = new int[]{0, 1, 0, -1};
-        int[] zPattern = new int[]{1, 0, -1, 0};
-        TilePosc sourcePos = new TilePos();
+    public static @Nullable TilePosc getBiomeCoords(final @NotNull Biome biome, final @NotNull World world) {
+        final int[] xPattern = new int[]{0, 1, 0, -1};
+        final int[] zPattern = new int[]{1, 0, -1, 0};
+        final @NotNull TilePosc sourcePos = new TilePos();
         int runLength = 2;
         int chunkX = (int) (sourcePos.x() / 16.0);
         int chunkZ = (int) (sourcePos.z() / 16.0);
@@ -187,4 +180,13 @@ public class Biome
             return null;
         }
     }
+
+    public boolean hasTag(final @NotNull Tag<Biome> tag) {
+        return tag.appliesTo(this);
+    }
+
+    @Override
+    public boolean isIn(final @NotNull Tag<Biome> tag) {
+        return tag.appliesTo(this);
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/BiomeTags.java b/game/core/src/main/java/net/minecraft/core/world/biome/BiomeTags.java
new file mode 100644
index 000000000..d54ebafec
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/BiomeTags.java
@@ -0,0 +1,50 @@
+package net.minecraft.core.world.biome;
+
+import net.minecraft.core.data.tag.Tag;
+import org.jetbrains.annotations.NotNull;
+
+public final class BiomeTags {
+    private BiomeTags() throws IllegalAccessException {
+        throw new IllegalAccessException("Attempted instantiation of helper class!");
+    }
+
+    /**
+     * Defines whether the biome has a coating of surface snow.
+     */
+    public static final @NotNull Tag<Biome> HAS_SURFACE_SNOW = Tag.of("has_surface_snow");
+
+    /**
+     * Defines whether the biome has a coating of surface ash.
+     */
+    public static final @NotNull Tag<Biome> HAS_SURFACE_ASH = Tag.of("has_surface_ash");
+
+    /**
+     * Defines whether surface water freezes in this biome.
+     */
+    public static final @NotNull Tag<Biome> HAS_SURFACE_ICE = Tag.of("has_surface_ice");
+
+    /**
+     * Defines whether sulfur pools generate on the surface of this biome.
+     */
+    public static final @NotNull Tag<Biome> HAS_SULFUR_POOLS = Tag.of("has_sulfur_pools");
+
+    /**
+     * Defines whether this biome has crystal veins.
+     */
+    public static final @NotNull Tag<Biome> HAS_CRYSTAL_VEINS = Tag.of("has_crystal_veins");
+
+    /**
+     * Defines whether this biome has surface water, e.g. swamps.
+     */
+    public static final @NotNull Tag<Biome> HAS_SURFACE_WATER = Tag.of("has_surface_water");
+
+    /**
+     * Defines whether this biome spawns with a muddy surface.
+     */
+    public static final @NotNull Tag<Biome> HAS_SURFACE_MUD = Tag.of("has_surface_mud");
+
+    /**
+     * Defines whether snow constantly layers up in this biome regardless of season.
+     */
+    public static final @NotNull Tag<Biome> DEEPER_SNOW = Tag.of("deeper_snow");
+}
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 81198680a..14060036b 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
@@ -7,59 +7,370 @@ import net.minecraft.core.world.biome.overworld.*;
 import net.minecraft.core.world.biome.drift.BiomeDrift;
 import net.minecraft.core.world.biome.overworld.legacy.*;
 import net.minecraft.core.world.weather.Weathers;
+import org.jetbrains.annotations.NotNull;
 
-public class Biomes
-{
+public class Biomes {
+    public static final @NotNull Biome OVERWORLD_RAINFOREST = register(
+        "minecraft:overworld.rainforest",
+        new BiomeRainforest("overworld.rainforest")
+            .withDebugColor(0x1C_F1_00)
+            .withBlockedWeathers(Weathers.OVERWORLD_SNOW)
+            .withPlacementDefaults(0.975f, 0.925f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_SWAMPLAND = register(
+        "minecraft:overworld.swampland",
+        new BiomeSwamp("overworld.swampland")
+            .withDebugColor(0x00_FF_78)
+            .withPlacementDefaults(0.85f, 0.925f, 0.5f)
+            .withTags(BiomeTags.HAS_SURFACE_WATER, BiomeTags.HAS_SURFACE_MUD)
+    );
+    public static final @NotNull Biome OVERWORLD_SEASONAL_FOREST = register(
+        "minecraft:overworld.seasonal_forest",
+        new BiomeSeasonalForest("overworld.seasonal_forest")
+            .withDebugColor(0x64_CE_15)
+            .withPlacementDefaults(0.675f, 0.75f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_FOREST = register(
+        "minecraft:overworld.forest",
+        new BiomeForest("overworld.forest")
+            .withDebugColor(0x26_A6_15)
+            .withPlacementDefaults(0.875f, 0.675f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_GRASSLANDS = register(
+        "minecraft:overworld.grasslands",
+        new Biome("overworld.grasslands")
+            .withDebugColor(0xF0_F0_48)
+            .withBlockedWeathers(Weathers.OVERWORLD_SNOW)
+            .withPlacementDefaults(0.75f, 0.025f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_OUTBACK = register(
+        "minecraft:overworld.outback",
+        new BiomeOutback("overworld.outback")
+            .withDebugColor(0xD9_5E_20)
+            .withBlockedWeathers(Weathers.OVERWORLD_SNOW)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.DIRT_SCORCHED)
+                    .withFillerBlock(Blocks.DIRT_SCORCHED)
+                    .build()
+            )
+            .withPlacementDefaults(0.825f, 0.1f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_SHRUBLAND = register(
+        "minecraft:overworld.shrubland",
+        new BiomeShrubland("overworld.shrubland")
+            .withDebugColor(0xBA_BA_38)
+            .withPlacementDefaults(0.675f, 0.175f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_TAIGA = register(
+        "minecraft:overworld.taiga",
+        new BiomeTaiga("overworld.taiga")
+            .withDebugColor(0x8A_BC_FF)
+            .withPlacementDefaults(0.15f, 0.55f, 0.5f)
+            .withTags(BiomeTags.HAS_SURFACE_SNOW, BiomeTags.HAS_SURFACE_ICE)
+    );
+    public static final @NotNull Biome OVERWORLD_BOREAL_FOREST = register(
+        "minecraft:overworld.boreal_forest",
+        new BiomeBorealForest("overworld.boreal_forest")
+            .withDebugColor(0x14_85_64)
+            .withPlacementDefaults(0.4f, 0.525f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_DESERT = register(
+        "minecraft:overworld.desert",
+        new BiomeDesert("overworld.desert")
+            .withDebugColor(0xED_E2_6F)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.SAND)
+                    .withFillerBlock(Blocks.SAND)
+                    .build()
+            )
+            .withPlacementDefaults(0.925f, 0.05f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_PLAINS = register(
+        "minecraft:overworld.plains",
+        new BiomePlains("overworld.plains")
+            .withDebugColor(0xA3_C6_49)
+            .withPlacementDefaults(0.875f, 0.25f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_GLACIER = register(
+        "minecraft:overworld.glacier",
+        new Biome("overworld.glacier")
+            .withDebugColor(0xCB_F6_FF)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.BLOCK_SNOW)
+                    .withFillerBlock(Blocks.BLOCK_SNOW)
+                    .build()
+            )
+            .withPlacementDefaults(0.15f, 0.005f, 0.5f)
+            .withTags(BiomeTags.HAS_SURFACE_SNOW, BiomeTags.DEEPER_SNOW)
+    );
+    public static final @NotNull Biome OVERWORLD_TUNDRA = register(
+        "minecraft:overworld.tundra",
+        new Biome("overworld.tundra")
+            .withDebugColor(0x57_E0_FF)
+            .withPlacementDefaults(0.15f, 0.055f, 0.5f)
+            .withTags(BiomeTags.HAS_SURFACE_SNOW, BiomeTags.HAS_SURFACE_ICE)
+    );
+    public static final @NotNull Biome OVERWORLD_MEADOW = register(
+        "minecraft:overworld.meadow",
+        new BiomeBorealForest("overworld.meadow")
+            .withDebugColor(0x8C_8C_22)
+            .withPlacementDefaults(0.4f, 0.025f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_BIRCH_FOREST = register(
+        "minecraft:overworld.birch_forest",
+        new BiomeBirchForest("overworld.birch_forest")
+            .withDebugColor(0x4B_CB_5E)
+            .withPlacementDefaults(0.675f, 0.4f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_RETRO = register(
+        "minecraft:overworld.retro",
+        new BiomeRetro("overworld.retro")
+            .withDebugColor(0x76_B1_4A)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.GRASS_RETRO)
+                    .build()
+            )
+    );
+    public static final @NotNull Biome OVERWORLD_HELL = register(
+        "minecraft:overworld.hell",
+        new Biome("overworld.hell")
+            .withDebugColor(0xD9_62_23)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.DIRT_SCORCHED)
+                    .withFillerBlock(Blocks.DIRT_SCORCHED)
+                    .build()
+            )
+    );
+    public static final @NotNull Biome OVERWORLD_SWAMPLAND_MUDDY = register(
+        "minecraft:overworld.swampland.muddy",
+        new BiomeSwamp("overworld.swampland.muddy")
+            .withDebugColor(0x52_27_00)
+            .withPlacementDefaults(0.85f, 0.925f, 0.5f)
+            .withTags(BiomeTags.HAS_SURFACE_MUD)
+    );
+    public static final @NotNull Biome OVERWORLD_OUTBACK_GRASSY = register(
+        "minecraft:overworld.outback.grassy",
+        new BiomeOutback("overworld.outback.grassy")
+            .withDebugColor(0xF0_90_37)
+            .withBlockedWeathers(Weathers.OVERWORLD_SNOW)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.GRASS_SCORCHED)
+                    .withFillerBlock(Blocks.DIRT_SCORCHED)
+                    .build()
+            )
+            .withPlacementDefaults(0.825f, 0.1f, 1.0f)
+    );
+    public static final @NotNull Biome OVERWORLD_CAATINGA = register(
+        "minecraft:overworld.caatinga",
+        new BiomeCaatinga("overworld.caatinga")
+            .withDebugColor(0xDE_CD_A6)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.MUD_BAKED)
+                    .withFillerBlock(Blocks.MUD_BAKED)
+                    .build()
+            )
+            .withBlockedWeathers(Weathers.OVERWORLD_SNOW)
+            .withPlacementDefaults(0.95f, 0.015f, 0.5f)
+            .withTags(BiomeTags.HAS_SURFACE_MUD)
+    );
+    public static final @NotNull Biome OVERWORLD_CAATINGA_PLAINS = register(
+        "minecraft:overworld.caatinga.plains",
+        new Biome("overworld.caatinga.plains")
+            .withDebugColor(0xA1_94_77)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.MUD_BAKED)
+                    .withFillerBlock(Blocks.MUD_BAKED)
+                    .build()
+            )
+            .withBlockedWeathers(Weathers.OVERWORLD_SNOW)
+            .withPlacementDefaults(0.95f, 0.015f, 0.0f)
+            .withTags(BiomeTags.HAS_SURFACE_MUD)
+    );
 
-    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).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 @NotNull Biome NETHER_CRAG = register(
+        "minecraft:nether.crag",
+        new BiomeNether("nether.crag")
+            .withDebugColor(0x63_3E_3D)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.COBBLE_NETHERRACK)
+                    .withFillerBlock(Blocks.COBBLE_NETHERRACK)
+                    .build()
+            )
+    );
+    public static final @NotNull Biome NETHER_VOLCANIC_ISLANDS = register(
+        "minecraft:nether.volcanic_islands",
+        new BiomeVolcanoIslands("nether.volcanic_islands")
+            .withDebugColor(0xFF_A3_33)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.BRIMSAND)
+                    .withFillerBlock(Blocks.BRIMSAND)
+                    .build()
+            )
+    );
+    public static final @NotNull Biome NETHER_SULFUR_POOLS = register(
+        "minecraft:nether.sulfur_pools",
+        new BiomeSulfurPools("nether.sulfur_pools")
+            .withDebugColor(0xA3_99_40)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.BRIMSAND)
+                    .withFillerBlock(Blocks.BRIMSAND)
+                    .build()
+            )
+            .withTags(BiomeTags.HAS_SULFUR_POOLS)
+    );
+    public static final @NotNull Biome NETHER_CRYSTAL_PLAINS = register(
+        "minecraft:nether.crystal_plains",
+        new BiomeCrystalForest("nether.crystal_plains")
+            .withDebugColor(0xAA_00_00)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.COBBLE_NETHERRACK)
+                    .withFillerBlock(Blocks.COBBLE_NETHERRACK)
+                    .build()
+            )
+            .withTags(BiomeTags.HAS_CRYSTAL_VEINS)
+    );
+    public static final @NotNull Biome NETHER_CRYSTAL_FOREST = register(
+        "minecraft:nether.crystal_forest",
+        new BiomeCrystalForest("nether.crystal_forest")
+            .withDebugColor(0xDD_00_00)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.COBBLE_NETHERRACK)
+                    .withFillerBlock(Blocks.COBBLE_NETHERRACK)
+                    .build()
+            )
+            .withTags(BiomeTags.HAS_CRYSTAL_VEINS)
+    );
+    public static final @NotNull Biome NETHER_OLD_WORLD = register(
+        "minecraft:nether.old_world",
+        new BiomeNether("nether.old_world")
+            .withDebugColor(0x63_64_80)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.COBBLE_NETHERRACK)
+                    .withFillerBlock(Blocks.COBBLE_NETHERRACK)
+                    .build()
+            )
+            .withTags(BiomeTags.HAS_SURFACE_ASH)
+    );
+    public static final @NotNull Biome NETHER_SHELF = register(
+        "minecraft:nether.shelf",
+        new BiomeNether("nether.shelf")
+            .withDebugColor(0x96_8A_6F)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.COBBLE_NETHERRACK)
+                    .withFillerBlock(Blocks.COBBLE_NETHERRACK)
+                    .build()
+            )
+    );
 
-    public static final Biome NETHER_CRAG = register("minecraft:nether.crag", new BiomeNether("nether.crag").setColor(0x633e3d).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(0xffa333).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.BRIMSAND.id()).setFillerBlock(Blocks.BRIMSAND.id()));
-    public static final Biome NETHER_SULFUR_POOLS = register("minecraft:nether.sulfur_pools", new BiomeSulfurPools("nether.sulfur_pools").setColor(0xa39940).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.BRIMSAND.id()).setFillerBlock(Blocks.BRIMSAND.id()));
-    public static final Biome NETHER_CRYSTAL_FIELD = register("minecraft:nether.crystal_field", new BiomeCrystalForest("nether.crystal_field").setColor(0xAA0000).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_CRYSTAL_FOREST = register("minecraft:nether.crystal_forest", new BiomeCrystalForest("nether.crystal_forest").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_OLD_WORLD = register("minecraft:nether.old_world", new BiomeNether("nether.old_world").setColor(0x636480).setSurfaceSnow().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_SHELF = register("minecraft:nether.shelf", new BiomeNether("nether.shelf").setColor(0x968a6f).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 @NotNull Biome DRIFT_DRIFT = register(
+        "minecraft:drift.drift",
+        new BiomeDrift("drift.drift")
+            .withDebugColor(0x80_80_FF)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG)
+            .withPlacementDefaults(0.5f, 0.0f, 0.0f)
+    );
 
-    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 final @NotNull Biome OVERWORLD_LEGACY_RAINFOREST = register(
+        "minecraft:overworld.legacy.rainforest",
+        new BiomeRainforestLegacy("overworld.legacy.rainforest")
+            .withDebugColor(0xD9_E0_23)
+            .withBlockedWeathers(Weathers.OVERWORLD_SNOW)
+            .withPlacementDefaults(0.985f, 0.95f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_SWAMPLAND = register(
+        "minecraft:overworld.legacy.swampland",
+        new BiomeSwampLegacy("overworld.legacy.swampland")
+            .withDebugColor(0x07_F9_B2)
+            .withPlacementDefaults(0.75f, 0.4f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_SEASONAL_FOREST = register(
+        "minecraft:overworld.legacy.seasonal_forest",
+        new Biome("overworld.legacy.seasonal_forest")
+            .withDebugColor(0x9B_E0_23)
+            .withPlacementDefaults(0.985f, 0.675f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_FOREST = register(
+        "minecraft:overworld.legacy.forest",
+        new BiomeForestLegacy("overworld.legacy.forest")
+            .withDebugColor(0x05_66_21)
+            .withPlacementDefaults(0.735f, 0.425f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_SAVANNA = register(
+        "minecraft:overworld.legacy.savanna",
+        new BiomeDesertLegacy("overworld.legacy.savanna")
+            .withDebugColor(0xD9_E0_23)
+            .withBlockedWeathers(Weathers.OVERWORLD_SNOW)
+            .withPlacementDefaults(0.725f, 0.1f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_SHRUBLAND = register(
+        "minecraft:overworld.legacy.shrubland",
+        new Biome("overworld.legacy.shrubland")
+            .withDebugColor(0xA1_AD_20)
+            .withPlacementDefaults(0.735f, 0.275f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_TAIGA = register(
+        "minecraft:overworld.legacy.taiga",
+        new BiomeTaigaLegacy("overworld.legacy.taiga")
+            .withDebugColor(0x2E_B1_53)
+            .withPlacementDefaults(0.3f, 0.35f, 0.5f)
+            .withTags(BiomeTags.HAS_SURFACE_SNOW, BiomeTags.HAS_SURFACE_ICE)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_DESERT = register(
+        "minecraft:overworld.legacy.desert",
+        new BiomeDesertLegacy("overworld.legacy.desert")
+            .withDebugColor(0xFA_94_18)
+            .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM)
+            .withSurfaceProperties(
+                new SurfaceProperties.Builder()
+                    .withTopBlock(Blocks.SAND)
+                    .withFillerBlock(Blocks.SAND)
+                    .build()
+            )
+            .withPlacementDefaults(0.975f, 0.1f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_PLAINS = register(
+        "minecraft:overworld.legacy.plains",
+        new BiomeDesertLegacy("overworld.legacy.plains")
+            .withDebugColor(0xFF_D9_10)
+            .withPlacementDefaults(0.985f, 0.325f, 0.5f)
+    );
+    public static final @NotNull Biome OVERWORLD_LEGACY_TUNDRA = register(
+        "minecraft:overworld.legacy.tundra",
+        new Biome("overworld.legacy.tundra")
+            .withDebugColor(0x57_EB_F9)
+            .withPlacementDefaults(0.05f, 0.5f, 0.5f)
+            .withTags(BiomeTags.HAS_SURFACE_SNOW, BiomeTags.HAS_SURFACE_ICE)
+    );
 
-    public static Biome register(String key, Biome biome)
-    {
+    public static @NotNull Biome register(final @NotNull String key, final @NotNull Biome biome) {
         Registries.BIOMES.register(key, biome);
-
         return biome;
     }
 
-    public static void init() { }
+    public static void init() {
+    }
 
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/SurfaceProperties.java b/game/core/src/main/java/net/minecraft/core/world/biome/SurfaceProperties.java
new file mode 100644
index 000000000..89673a124
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/SurfaceProperties.java
@@ -0,0 +1,56 @@
+package net.minecraft.core.world.biome;
+
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.Blocks;
+import org.jetbrains.annotations.NotNull;
+
+public final class SurfaceProperties {
+    private final @NotNull Block<?> topBlock;
+    private final @NotNull Block<?> fillerBlock;
+
+    private SurfaceProperties(
+        final @NotNull Block<?> topBlock,
+        final @NotNull Block<?> fillerBlock
+    ) {
+        this.topBlock = topBlock;
+        this.fillerBlock = fillerBlock;
+    }
+
+    public @NotNull Block<?> getTopBlock() {
+        return this.topBlock;
+    }
+
+    public @NotNull Block<?> getFillerBlock() {
+        return this.fillerBlock;
+    }
+
+    public static final class Builder {
+        private @NotNull Block<?> topBlock = Blocks.GRASS;
+        private @NotNull Block<?> fillerBlock = Blocks.DIRT;
+
+        public @NotNull Block<?> getTopBlock() {
+            return this.topBlock;
+        }
+
+        public @NotNull Builder withTopBlock(final @NotNull Block<?> block) {
+            this.topBlock = block;
+            return this;
+        }
+
+        public @NotNull Block<?> getFillerBlock() {
+            return this.fillerBlock;
+        }
+
+        public @NotNull Builder withFillerBlock(final @NotNull Block<?> block) {
+            this.fillerBlock = block;
+            return this;
+        }
+
+        public @NotNull SurfaceProperties build() {
+            return new SurfaceProperties(
+                this.topBlock,
+                this.fillerBlock
+            );
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeBirchForest.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeBirchForest.java
index 13acfed9c..899bf0c01 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeBirchForest.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeBirchForest.java
@@ -4,9 +4,10 @@ import net.minecraft.core.entity.animal.MobWolf;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.SpawnListEntry;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeTall;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -20,7 +21,7 @@ public class BiomeBirchForest extends Biome
     }
 
     @Override
-	public WorldFeature getRandomWorldGenForTrees(Random random)
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
 
         if(random.nextInt(10) == 0)
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeBorealForest.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeBorealForest.java
index a26de87fb..ac4abe021 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeBorealForest.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeBorealForest.java
@@ -4,8 +4,9 @@ import net.minecraft.core.entity.animal.MobWolf;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.SpawnListEntry;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeTaigaBushy;
 import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeTaigaBushy;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -19,7 +20,7 @@ public class BiomeBorealForest extends Biome
     }
 
     @Override
-	public WorldFeature getRandomWorldGenForTrees(Random random)
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         return new WorldFeatureTreeTaigaBushy(Blocks.LEAVES_PINE.id(), Blocks.LOG_PINE.id());
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeCaatinga.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeCaatinga.java
index 793dba71d..4757f4502 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeCaatinga.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeCaatinga.java
@@ -6,8 +6,9 @@ package net.minecraft.core.world.biome.overworld;
 
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.generate.feature.tree.*;
 import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.world.generate.feature.tree.*;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -19,7 +20,7 @@ public class BiomeCaatinga extends Biome
     }
 
     @Override
-    public WorldFeature getRandomWorldGenForTrees(Random random)
+    public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         if(random.nextInt(3) != 0)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeDesert.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeDesert.java
index 63df9e873..66bdeea7d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeDesert.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeDesert.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreePalm;
+import org.jetbrains.annotations.NotNull;
 
 public class BiomeDesert extends Biome
 {
@@ -15,7 +16,7 @@ public class BiomeDesert extends Biome
         super(key);
     }
     @Override
-    public WorldFeature getRandomWorldGenForTrees(Random random) {
+    public @NotNull WorldFeature getTreeFeature(@NotNull Random random) {
 
         return new WorldFeatureTreePalm(Blocks.LOG_PALM, Blocks.LEAVES_PALM, random.nextInt(10) == 0, false, true);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeForest.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeForest.java
index 458603e3e..9517a9aa0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeForest.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeForest.java
@@ -4,9 +4,10 @@ import net.minecraft.core.entity.animal.MobWolf;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.SpawnListEntry;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
-import net.minecraft.core.world.generate.feature.WorldFeature;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -20,7 +21,7 @@ public class BiomeForest extends Biome
     }
 
     @Override
-	public WorldFeature getRandomWorldGenForTrees(Random random)
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         if(random.nextInt(5) == 0)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeOutback.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeOutback.java
index 956cc2e29..751da21e0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeOutback.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeOutback.java
@@ -4,8 +4,9 @@ import net.minecraft.core.entity.monster.MobSpider;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.SpawnListEntry;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeEucalyptus;
 import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeEucalyptus;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -22,7 +23,7 @@ public class BiomeOutback extends Biome
     }
 
     @Override
-	public WorldFeature getRandomWorldGenForTrees(Random random)
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         return new WorldFeatureTreeEucalyptus(Blocks.LEAVES_EUCALYPTUS.id(), Blocks.LOG_EUCALYPTUS.id());
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomePlains.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomePlains.java
index 5bcc35fee..90767bf7b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomePlains.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomePlains.java
@@ -4,6 +4,7 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeEucalyptus;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -14,7 +15,7 @@ public class BiomePlains extends Biome
     }
 
     @Override
-    public WorldFeature getRandomWorldGenForTrees(Random random)
+    public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         return new WorldFeatureTreeEucalyptus(Blocks.LEAVES_EUCALYPTUS.id(), Blocks.LOG_EUCALYPTUS.id());
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeRainforest.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeRainforest.java
index 10944c5c0..d26cb3c72 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeRainforest.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeRainforest.java
@@ -10,6 +10,7 @@ import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancyRainf
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreePalm;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeShrub;
 import net.minecraft.core.world.generate.feature.tree.spooner.WorldFeatureSpoonerTreeRound;
+import org.jetbrains.annotations.NotNull;
 
 public class BiomeRainforest extends Biome
 {
@@ -20,7 +21,7 @@ public class BiomeRainforest extends Biome
     }
 
 	@Override
-	public WorldFeature getRandomWorldGenForTrees(Random random) {
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random) {
 		if(random.nextInt(1000) == 0) {
 			int treeHeight = 30 + random.nextInt(30);
 			return new WorldFeatureSpoonerTreeRound(treeHeight, Blocks.LOG_OAK.id(), 0, Blocks.LEAVES_OAK.id(), 0);
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeRetro.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeRetro.java
index 16284c0e2..0ce25763c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeRetro.java
@@ -8,6 +8,7 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -34,7 +35,7 @@ public class BiomeRetro
     }
 
     @Override
-    public WorldFeature getRandomWorldGenForTrees(Random random)
+    public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         WorldFeature feature = new WorldFeatureTree(Blocks.LEAVES_OAK.id(), Blocks.LOG_OAK.id(), 4);
         if (random.nextInt(10) == 0)
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeSeasonalForest.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeSeasonalForest.java
index a7dedb093..312a1d063 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeSeasonalForest.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeSeasonalForest.java
@@ -4,10 +4,11 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.SpawnListEntry;
 import net.minecraft.core.entity.animal.MobWolf;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeCherry;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
-import net.minecraft.core.world.generate.feature.WorldFeature;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -20,7 +21,7 @@ public class BiomeSeasonalForest extends Biome
         spawnableCreatureList.add(new SpawnListEntry(MobWolf.class, 25));
     }
     @Override
-	public WorldFeature getRandomWorldGenForTrees(Random random)
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         if(random.nextInt(3) == 0)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeShrubland.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeShrubland.java
index 8ed06dd22..8d7972525 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeShrubland.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeShrubland.java
@@ -2,8 +2,9 @@ package net.minecraft.core.world.biome.overworld;
 
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeShrub;
 import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeShrub;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -14,7 +15,7 @@ public class BiomeShrubland extends Biome
 	}
 
 	@Override
-	public WorldFeature getRandomWorldGenForTrees(Random random)
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         return new WorldFeatureTreeShrub(Blocks.LEAVES_SHRUB.id(), Blocks.LOG_OAK.id());
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeSwamp.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeSwamp.java
index 783b8737d..bcaab071d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeSwamp.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeSwamp.java
@@ -2,8 +2,9 @@ package net.minecraft.core.world.biome.overworld;
 
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeShapeSwamp;
 import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeShapeSwamp;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -14,7 +15,7 @@ public class BiomeSwamp extends Biome
 	}
 
 	@Override
-	public WorldFeature getRandomWorldGenForTrees(Random random)
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         return new WorldFeatureTreeShapeSwamp(Blocks.LEAVES_OAK.id(), Blocks.LOG_OAK_MOSSY.id(), 6);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeTaiga.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeTaiga.java
index b27ab4794..8466fb697 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeTaiga.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/BiomeTaiga.java
@@ -4,9 +4,10 @@ import net.minecraft.core.entity.animal.MobWolf;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.SpawnListEntry;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeTaigaBushy;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeTaigaTall;
-import net.minecraft.core.world.generate.feature.WorldFeature;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -20,7 +21,7 @@ public class BiomeTaiga extends Biome
     }
 
     @Override
-	public WorldFeature getRandomWorldGenForTrees(Random random)
+	public @NotNull WorldFeature getTreeFeature(@NotNull Random random)
     {
         if(random.nextInt(3) == 0)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeForestLegacy.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeForestLegacy.java
index 66d2bd8cc..d5a6c55a2 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeForestLegacy.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeForestLegacy.java
@@ -7,6 +7,7 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -19,7 +20,7 @@ public class BiomeForestLegacy
     }
 
     @Override
-    public WorldFeature getRandomWorldGenForTrees(final Random random) {
+    public @NotNull WorldFeature getTreeFeature(final @NotNull Random random) {
         if (random.nextInt(5) == 0) {
             return new WorldFeatureTree(Blocks.LEAVES_BIRCH.id(), Blocks.LOG_BIRCH.id(), 5);
         } else {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeRainforestLegacy.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeRainforestLegacy.java
index 3faa48598..6fe406ccf 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeRainforestLegacy.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeRainforestLegacy.java
@@ -5,6 +5,7 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -16,7 +17,7 @@ public class BiomeRainforestLegacy
     }
 
     @Override
-    public WorldFeature getRandomWorldGenForTrees(final Random random) {
+    public @NotNull WorldFeature getTreeFeature(final @NotNull Random random) {
         return (random.nextInt(3) == 0) ? new WorldFeatureTreeFancy(Blocks.LEAVES_OAK.id(), Blocks.LOG_OAK.id()) : new WorldFeatureTree(Blocks.LEAVES_OAK.id(), Blocks.LOG_OAK.id(), 4);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeTaigaLegacy.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeTaigaLegacy.java
index 48842c748..8dac43f80 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeTaigaLegacy.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeTaigaLegacy.java
@@ -5,6 +5,7 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.generate.feature.WorldFeature;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeTaigaBushy;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeTaigaTall;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -16,7 +17,7 @@ public class BiomeTaigaLegacy
     }
 
     @Override
-    public WorldFeature getRandomWorldGenForTrees(final Random random) {
+    public @NotNull WorldFeature getTreeFeature(final @NotNull Random random) {
         if(random.nextInt(3) == 0)
         {
             return new WorldFeatureTreeTaigaTall(Blocks.LEAVES_PINE.id(), Blocks.LOG_PINE.id());
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 f2c6f85bc..c33818514 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
@@ -16,7 +16,7 @@ public final class BiomeProviderNether
 {
     public static final Biome[] BIOMES_ORDER = {
             Biomes.NETHER_OLD_WORLD,
-            Biomes.NETHER_CRYSTAL_FIELD,
+            Biomes.NETHER_CRYSTAL_PLAINS,
             Biomes.NETHER_CRYSTAL_FOREST,
             Biomes.NETHER_SHELF,
             Biomes.NETHER_CRAG,
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
index f09a4fa87..29cb19e20 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.LightIndexHelper;
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.biome.Biome;
@@ -15,6 +16,7 @@ import net.minecraft.core.world.pos.ChunkTilePos;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.season.SeasonManager;
+import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.weather.WeatherManager;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -253,7 +255,12 @@ public class ChunkCache
     }
 
     @Override
-    public boolean isRetro() {
-        return this.world.isRetro();
+    public @NotNull Dimension getDimension() {
+        return this.world.getDimension();
+    }
+
+    @Override
+    public @NotNull WorldType getWorldType() {
+        return this.world.getWorldType();
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/CavesLargeFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/CavesLargeFeature.java
index 8595a5bbe..107a88dc5 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/CavesLargeFeature.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/CavesLargeFeature.java
@@ -174,8 +174,8 @@ public class CavesLargeFeature extends LargeFeature {
 
                                     if (replaceTopBlock) {
                                         Biome biome = world.getBlockBiome(x, yIndex - 1, z);
-                                        int topBlockId = biome.topBlock;
-                                        int fillBlockId = biome.fillerBlock;
+                                        int topBlockId = biome.getSurfaceProperties().getTopBlock().id();
+                                        int fillBlockId = biome.getSurfaceProperties().getFillerBlock().id();
                                         int id = result.getBlock(x, yIndex - 1, z);
                                         if (id == fillBlockId) {
                                             result.setBlock(x, yIndex - 1, z, topBlockId);
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java
index 28b8e7d3b..06cabca62 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java
@@ -166,8 +166,8 @@ public class RetroCavesLargeFeature extends LargeFeature {
 
                                         if (replaceTopBlock) {
                                             Biome biome = world.getBlockBiome(x, yIndex - 1, z);
-                                            int topBlockId = biome.topBlock;
-                                            int fillBlockId = biome.fillerBlock;
+                                            int topBlockId = biome.getSurfaceProperties().getTopBlock().id();
+                                            int fillBlockId = biome.getSurfaceProperties().getFillerBlock().id();
                                             int id = result.getBlock(x, yIndex - 1, z);
                                             if (id == fillBlockId) {
                                                 result.setBlock(x, yIndex - 1, z, topBlockId);
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 727182ed3..0d102f7c5 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
@@ -2,6 +2,7 @@ package net.minecraft.core.world.generate.chunk.classic;
 
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.CavesLargeFeature;
 import net.minecraft.core.world.generate.chunk.ChunkGenerator;
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 a55416817..e8a0637c9 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
@@ -3,6 +3,7 @@ package net.minecraft.core.world.generate.chunk.perlin.nether;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.*;
@@ -29,7 +30,7 @@ public class ChunkDecoratorNether
         );
         this.register("minecraft:decoration/nether/default/rubyglass_crystal_ceiling",
                 new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(true))
-                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_FIELD })
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS})
                         .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
                         .withPlacementMethod(((feature, world, chunk, random) -> {
                             int x = chunk.pos.x * 16;
@@ -44,7 +45,7 @@ public class ChunkDecoratorNether
 
         this.register("minecraft:decoration/nether/default/rubyglass_crystal_floor",
                 new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(false, 25, 50))
-                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_FIELD })
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS})
                         .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
                         .withPlacementMethod(((feature, world, chunk, random) -> {
                             int x = chunk.pos.x * 16;
@@ -59,21 +60,21 @@ public class ChunkDecoratorNether
 
         this.register("minecraft:decoration/nether/default/rubyglass_crystal_floor_2",
                 new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(false,  20, 30))
-                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_FIELD })
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS})
                         .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
                         .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))
         );
 
         this.register("minecraft:decoration/nether/default/rubyglass_sprout_patch",
                 new ChunkDecorationBuilder(new WorldFeatureRubyglassSproutPatch())
-                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_FIELD })
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS})
                         .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean)
                         .withPlacementMethod(new PlacementMethod.TriesPerChunk(20))
         );
 
         this.register("minecraft:decoration/nether/default/nether_water_spring",
                 new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_WATER_FLOWING.id()))
-                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_FIELD, Biomes.NETHER_OLD_WORLD })
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_OLD_WORLD })
                         .withPositionSelector(PositionSelectors.HeightRangeBiasedTop)
                         .withPlacementMethod(new PlacementMethod.TriesPerChunk(30))
         );
@@ -94,7 +95,7 @@ public class ChunkDecoratorNether
 
         this.register("minecraft:decoration/nether/default/pillar_netherrack",
                 new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.NETHERRACK.id(), false))
-                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FIELD, Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRAG, Biomes.NETHER_SHELF })
+                        .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRAG, Biomes.NETHER_SHELF })
                         .withPositionSelector(PositionSelectors.UpperHeightRangeUniform)
                         .withPlacementMethod(new PlacementMethod.ChanceToPlace(4))
         );
@@ -225,7 +226,7 @@ public class ChunkDecoratorNether
                 dy++;
                 Biome localBiome = world.getBlockBiome(dx, dy, dz);
 
-                if (localBiome != null && localBiome.hasSurfaceSnow() && (dy > 0 && dy < world.getHeightBlocks())) {
+                if (localBiome != null && localBiome.hasTag(BiomeTags.HAS_SURFACE_ASH) && (dy > 0 && dy < world.getHeightBlocks())) {
                     if (world.isAirBlock(dx, dy, dz) && world.getBlockMaterial(dx, dy - 1, dz).blocksMotion()) {
                         world.setBlock(dx, dy, dz, Blocks.LAYER_ASH.id());
                     }
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 887ae1c37..88b496b5d 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
@@ -3,6 +3,7 @@ package net.minecraft.core.world.generate.chunk.perlin.nether;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult;
@@ -64,8 +65,8 @@ public class SurfaceGeneratorNether
                     int block = result.getBlock(x, y, z);
 
                     if ((biome != lastBiome || topBlock == -1 || fillerBlock == -1) && block == 0) {
-                        topBlock = biome.topBlock;
-                        fillerBlock = biome.fillerBlock;
+                        topBlock = (short) biome.getSurfaceProperties().getTopBlock().id();
+                        fillerBlock = (short) biome.getSurfaceProperties().getFillerBlock().id();
                     }
                     lastBiome = biome;
 
@@ -87,12 +88,12 @@ public class SurfaceGeneratorNether
                             topBlock = 0;
                             fillerBlock = (short) Blocks.NETHERRACK.id();
                         } else {
-                            boolean biomeGeneratesSulfur = biome == Biomes.NETHER_SULFUR_POOLS;
+                            boolean biomeGeneratesSulfur = biome.hasTag(BiomeTags.HAS_SULFUR_POOLS);
 
                             if (y >= minY + oceanY - 4 && y <= minY + oceanY + 1) {
                                 // Generate coastlines
-                                topBlock = biome.topBlock;
-                                fillerBlock = biome.fillerBlock;
+                                topBlock = (short) biome.getSurfaceProperties().getTopBlock().id();
+                                fillerBlock = (short) biome.getSurfaceProperties().getFillerBlock().id();
                                 if (generateGravelBeach) {
                                     topBlock = (short) Blocks.GRAVEL.id();
                                     fillerBlock = (short) Blocks.GRAVEL.id();
@@ -133,7 +134,7 @@ public class SurfaceGeneratorNether
 
                     if(currentLayerDepth == 0)
                     {
-                        if(biome == Biomes.NETHER_SULFUR_POOLS && fillerBlock == Blocks.BRIMSAND.id()) {
+                        if(biome.hasTag(BiomeTags.HAS_SULFUR_POOLS) && fillerBlock == Blocks.BRIMSAND.id()) {
                             currentLayerDepth = rand.nextInt(4) + 2;
                             fillerBlock = (short)Blocks.BRIMSAND.id();
                         }
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 28ffa3202..8fa73ae04 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
@@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.chunk.ChunkSection;
@@ -42,7 +43,7 @@ public class TerrainGeneratorNether
         this.fluidLookup.put(Biomes.NETHER_CRAG, Blocks.FLUID_LAVA_STILL.id());
         this.fluidLookup.put(Biomes.NETHER_SHELF, Blocks.COBBLE_NETHERRACK.id());
         this.fluidLookup.put(Biomes.NETHER_CRYSTAL_FOREST, Blocks.FLUID_WATER_STILL.id());
-        this.fluidLookup.put(Biomes.NETHER_CRYSTAL_FIELD, Blocks.FLUID_WATER_STILL.id());
+        this.fluidLookup.put(Biomes.NETHER_CRYSTAL_PLAINS, Blocks.FLUID_WATER_STILL.id());
         this.fluidLookup.put(Biomes.NETHER_OLD_WORLD, Blocks.FLUID_WATER_STILL.id());
 
         this.minY = world.getWorldType().getMinY(world);
@@ -72,7 +73,7 @@ public class TerrainGeneratorNether
         } else if (y <= quarterHeight + this.rand.nextInt(5)) {
             return Blocks.BEDROCK.id();
         } else if (density > 0.0) {
-            if (this.lastBiome == Biomes.NETHER_CRYSTAL_FOREST || this.lastBiome == Biomes.NETHER_CRYSTAL_FIELD) {
+            if (this.lastBiome != null && this.lastBiome.hasTag(BiomeTags.HAS_CRYSTAL_VEINS)) {
                 int sizeY = Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y;
                 // YZX ordering
                 final double d = ((this.cache[(x * Chunk.CHUNK_SIZE_Z * sizeY) + (z * sizeY) + y]));
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 5029744b0..d7c7a0ae3 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
@@ -12,15 +12,16 @@ import net.minecraft.core.block.BlockLogicSand;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.material.Materials;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.noise.FractalNoise2D;
 import net.minecraft.core.world.noise.ImprovedPerlinNoise;
-import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.overworld.BiomeOutback;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkDecorator;
 import net.minecraft.core.world.generate.feature.*;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
@@ -66,7 +67,7 @@ public class ChunkDecoratorOverworld
         Random swampRand = new Random((long) chunkX * l1 + (long) chunkZ * l2 ^ this.world.getRandomSeed());
 
         // Water pass for swamps
-        if (biome == Biomes.OVERWORLD_SWAMPLAND) {
+        if (biome.hasTag(BiomeTags.HAS_SURFACE_WATER)) {
             for (int dx = 0; dx < 16; dx++) {
                 for (int dz = 0; dz < 16; dz++) {
                     int topBlock = this.world.getHeightValue(x + dx, z + dz);
@@ -102,7 +103,7 @@ public class ChunkDecoratorOverworld
             lakeChance = 0;
         if (lakeChance != 0 && rand.nextInt(lakeChance) == 0) {
             int fluid = Blocks.FLUID_WATER_STILL.id();
-            if (biome.hasSurfaceIce()) {
+            if (biome.hasTag(BiomeTags.HAS_SURFACE_ICE)) {
                 fluid = Blocks.ICE.id();
             }
             int i1 = x + rand.nextInt(16) + 8;
@@ -301,7 +302,7 @@ public class ChunkDecoratorOverworld
             for (int i11 = 0; i11 < treeDensity; i11++) {
                 int l13 = x + rand.nextInt(16) + 8;
                 int j14 = z + rand.nextInt(16) + 8;
-                WorldFeature feature = biome.getRandomWorldGenForTrees(rand);
+                WorldFeature feature = biome.getTreeFeature(rand);
                 feature.init(1.0D, 1.0D, 1.0D);
                 feature.place(this.world, rand, l13, this.world.getHeightValue(l13, j14), j14);
             }
@@ -604,12 +605,16 @@ public class ChunkDecoratorOverworld
                 int dy = this.world.getHeightValue(dx, dz);
                 Biome localBiome = this.world.getBlockBiome(dx, dy, dz);
 
-                if ((localBiome.hasSurfaceSnow() || this.world.getWorldType() == WorldTypes.OVERWORLD_WINTER) && dy > 0 && dy < this.world.getHeightBlocks()) {
+                if ((localBiome.hasTag(BiomeTags.HAS_SURFACE_SNOW) || this.world.getWorldType().hasTag(WorldTypeTags.ENDLESS_SNOW)) &&
+                    dy > 0 && dy < this.world.getHeightBlocks())
+                {
                     if (this.world.isAirBlock(dx, dy, dz) && this.world.getBlockMaterial(dx, dy - 1, dz).blocksMotion()) {
                         this.world.setBlockWithNotify(dx, dy, dz, Blocks.LAYER_SNOW.id());
                     }
                 }
-                if ((localBiome.hasSurfaceIce() || this.world.getWorldType() == WorldTypes.OVERWORLD_WINTER) && (this.world.getBlockId(dx, oceanY - 1, dz) == Blocks.FLUID_WATER_STILL.id() || this.world.getBlockId(dx, oceanY - 1, dz) == Blocks.FLUID_WATER_FLOWING.id())) {
+                if ((localBiome.hasTag(BiomeTags.HAS_SURFACE_ICE) || this.world.getWorldType().hasTag(WorldTypeTags.ENDLESS_SNOW)) &&
+                    (this.world.getBlockId(dx, oceanY - 1, dz) == Blocks.FLUID_WATER_STILL.id() || this.world.getBlockId(dx, oceanY - 1, dz) == Blocks.FLUID_WATER_FLOWING.id())
+                ) {
                     this.world.setBlockWithNotify(dx, oceanY - 1, dz, Blocks.ICE.id());
                 }
 
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 07ecdc60e..6b6f8429b 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
@@ -5,6 +5,7 @@ import java.util.Random;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult;
@@ -118,8 +119,8 @@ public class SurfaceGeneratorOverworld
 
                     if ((biome != lastBiome || topBlock == -1 || fillerBlock == -1) && block == 0)
                     {
-                        topBlock = biome.topBlock;
-                        fillerBlock = biome.fillerBlock;
+                        topBlock = (short) biome.getSurfaceProperties().getTopBlock().id();
+                        fillerBlock = (short) biome.getSurfaceProperties().getFillerBlock().id();
                     }
                     lastBiome = biome;
 
@@ -147,17 +148,13 @@ public class SurfaceGeneratorOverworld
                         }
                         else {
                             //todo: biome tags
-                            boolean biomeGeneratesMud = biome ==
-                                    Biomes.OVERWORLD_CAATINGA_PLAINS ||
-                                    biome == Biomes.OVERWORLD_CAATINGA ||
-                                    biome == Biomes.OVERWORLD_SWAMPLAND ||
-                                    biome == Biomes.OVERWORLD_SWAMPLAND_MUDDY;
+                            boolean biomeGeneratesMud = biome.hasTag(BiomeTags.HAS_SURFACE_MUD);
 
                             if(y >= minY + oceanY - 4 && y <= minY + oceanY + 1)
                             {
                                 // generate coastlines
-                                topBlock = biome.topBlock;
-                                fillerBlock = biome.fillerBlock;
+                                topBlock = (short) biome.getSurfaceProperties().getTopBlock().id();
+                                fillerBlock = (short) biome.getSurfaceProperties().getFillerBlock().id();
                                 if(biomeGeneratesMud)
                                 {
                                     topBlock = (short) Blocks.MUD.id();
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 6c92100ee..8838e954b 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
@@ -2,6 +2,7 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld;
 
 import net.minecraft.core.block.Blocks;
 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.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
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 9878ff5b1..3b09b9038 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
@@ -4,6 +4,7 @@ import net.minecraft.core.block.BlockLogicSand;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkDecorator;
@@ -168,9 +169,9 @@ public class ChunkDecoratorOverworldB173
         for (int i = 0; i < numTrees; i++) {
             final int fx = wx + rand.nextInt(16) + 8;
             final int fz = wz + rand.nextInt(16) + 8;
-            final @NotNull WorldFeature feature = biome.getRandomWorldGenForTrees(rand);
+            final @NotNull WorldFeature feature = biome.getTreeFeature(rand);
             feature.init(1.0, 1.0, 1.0);
-            biome.getRandomWorldGenForTrees(rand).place(this.world, rand, fx, this.world.getHeightValue(fx, fz), fz);
+            biome.getTreeFeature(rand).place(this.world, rand, fx, this.world.getHeightValue(fx, fz), fz);
         }
 
         int numYellowFlowers = 0;
@@ -302,12 +303,12 @@ public class ChunkDecoratorOverworldB173
                 int yy = this.world.getHeightValue(xx, zz);
                 final Biome localBiome = this.world.getBlockBiome(xx, yy, zz);
 
-                if (localBiome.hasSurfaceSnow() && yy > 0 && yy < this.world.getHeightBlocks()) {
+                if (localBiome.hasTag(BiomeTags.HAS_SURFACE_SNOW) && yy > 0 && yy < this.world.getHeightBlocks()) {
                     if (this.world.isAirBlock(xx, yy, zz) && this.world.getBlockMaterial(xx, yy - 1, zz).blocksMotion()) {
                         this.world.setBlockWithNotify(xx, yy, zz, Blocks.LAYER_SNOW.id());
                     }
                 }
-                if (localBiome.hasSurfaceIce() && (this.world.getBlockId(xx, oceanY - 1, zz) == Blocks.FLUID_WATER_STILL.id() || this.world.getBlockId(xx, oceanY - 1, zz) == Blocks.FLUID_WATER_FLOWING.id())) {
+                if (localBiome.hasTag(BiomeTags.HAS_SURFACE_ICE) && (this.world.getBlockId(xx, oceanY - 1, zz) == Blocks.FLUID_WATER_STILL.id() || this.world.getBlockId(xx, oceanY - 1, zz) == Blocks.FLUID_WATER_FLOWING.id())) {
                     this.world.setBlockWithNotify(xx, oceanY - 1, zz, Blocks.ICE.id());
                 }
             }
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 af0ab3fdf..e9d4aa976 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
@@ -2,6 +2,8 @@ package net.minecraft.core.world.type;
 
 import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
+import net.minecraft.core.data.tag.ITaggable;
+import net.minecraft.core.data.tag.Tag;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.provider.BiomeProvider;
@@ -20,9 +22,14 @@ import net.minecraft.core.world.wind.WindProviderGeneric;
 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.Random;
 
-public abstract class WorldType {
+public abstract class WorldType
+    implements ITaggable<WorldType>
+{
     private final String languageKey;
     private final Weather defaultWeather;
     private final WindProvider windProvider;
@@ -38,7 +45,6 @@ public abstract class WorldType {
     private final int fillerBlockId;
     private final int dayNightCycleTicks;
     private final boolean mayRespawn;
-    private final boolean isRetro;
 
     public WorldType(Properties properties) {
         this.languageKey = properties.languageKey;
@@ -64,7 +70,10 @@ public abstract class WorldType {
         this.fillerBlockId = properties.fillerBlock == null ? 0 : properties.fillerBlock.id();
         this.dayNightCycleTicks = properties.dayNightCycleTicks;
         this.mayRespawn = properties.mayRespawn;
-        this.isRetro = properties.isRetro;
+
+        for (final @NotNull Tag<WorldType> tag : properties.tags) {
+            tag.tag(this);
+        }
     }
 
     public String getLanguageKey() {
@@ -127,10 +136,6 @@ public abstract class WorldType {
         return mayRespawn;
     }
 
-    public boolean isRetro() {
-        return isRetro;
-    }
-
     public void onWorldCreation(World world) { }
 
     public final int getYRange(final @NotNull World world) {
@@ -286,6 +291,15 @@ public abstract class WorldType {
 
     public abstract int getSkyDarken(World world, long tick, float partialTick);
 
+    public boolean hasTag(final @NotNull Tag<WorldType> tag) {
+        return tag.appliesTo(this);
+    }
+
+    @Override
+    public boolean isIn(Tag<WorldType> tag) {
+        return tag.appliesTo(this);
+    }
+
     public static class Properties {
         private final String languageKey;
         private Weather defaultWeather = null;
@@ -302,7 +316,7 @@ public abstract class WorldType {
         private @Nullable Block<?> fillerBlock = null;
         private int dayNightCycleTicks = Global.DAY_LENGTH_TICKS;
         private boolean mayRespawn = false;
-        private boolean isRetro = false;
+        private final @NotNull List<Tag<WorldType>> tags = new ArrayList<>();
 
         private Properties(String languageKey) {
             this.languageKey = languageKey;
@@ -393,8 +407,9 @@ public abstract class WorldType {
             return this;
         }
 
-        public @NotNull Properties setRetro() {
-            this.isRetro = true;
+        @SafeVarargs
+        public final @NotNull Properties withTags(final @NotNull Tag<WorldType>... tags) {
+            this.tags.addAll(Arrays.asList(tags));
             return this;
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
index 7f41111a6..026509a68 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
@@ -8,199 +8,216 @@ import net.minecraft.core.world.type.nether.WorldTypeNether;
 import net.minecraft.core.world.type.nether.WorldTypeNetherSkyblock;
 import net.minecraft.core.world.type.overworld.*;
 import net.minecraft.core.world.type.drift.WorldTypeDrift;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import net.minecraft.core.world.weather.Weathers;
 import org.jetbrains.annotations.NotNull;
 
 public abstract class WorldTypes {
     public static final @NotNull WorldType OVERWORLD_EXTENDED = register(
-            "minecraft:overworld.extended",
-            new WorldTypeOverworld(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.extended")
-            )
+        "minecraft:overworld.extended",
+        new WorldTypeOverworld(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.extended")
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_DEFAULT = register(
-            "minecraft:overworld.default",
-            new WorldTypeOverworld(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.default")
-                            .bounds(0, 127, 64)
-                            .portalBounds(0, 255)
-            )
+        "minecraft:overworld.default",
+        new WorldTypeOverworld(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.default")
+                .bounds(0, 127, 64)
+                .portalBounds(0, 255)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType NETHER_DEFAULT = register(
-            "minecraft:nether.default",
-            new WorldTypeNether(
-                    WorldTypeNether.defaultProperties("worldType.nether.default")
-                        .portalBounds(63, 255)
-            )
+        "minecraft:nether.default",
+        new WorldTypeNether(
+            WorldTypeNether.defaultProperties("worldType.nether.default")
+                .portalBounds(63, 255)
+                .withTags(WorldTypeTags.NETHER, WorldTypeTags.HOT, WorldTypeTags.BREAKS_COMPASS, WorldTypeTags.BREAKS_TIMEPIECES)
+        )
     );
     public static final @NotNull WorldType NETHER_SKYBLOCK = register(
-            "minecraft:nether.skyblock",
-            new WorldTypeNetherSkyblock(
-                    WorldTypeNether.defaultProperties("worldType.nether.skyblock")
-                        .bounds(0, 127, 0)
-            )
+        "minecraft:nether.skyblock",
+        new WorldTypeNetherSkyblock(
+            WorldTypeNether.defaultProperties("worldType.nether.skyblock")
+                .bounds(0, 127, 0)
+                .withTags(WorldTypeTags.NETHER, WorldTypeTags.HOT, WorldTypeTags.BREAKS_COMPASS, WorldTypeTags.BREAKS_TIMEPIECES)
+        )
     );
     public static final @NotNull WorldType DRIFT_DEFAULT = register(
-            "minecraft:drift.default",
-            new WorldTypeDrift(
-                    WorldTypeDrift.defaultProperties("worldType.drift.default")
-            )
+        "minecraft:drift.default",
+        new WorldTypeDrift(
+            WorldTypeDrift.defaultProperties("worldType.drift.default")
+                .withTags(WorldTypeTags.DRIFT, WorldTypeTags.COLD, WorldTypeTags.BREAKS_COMPASS, WorldTypeTags.BREAKS_TIMEPIECES)
+        )
     );
     public static final @NotNull WorldType FLAT = register(
-            "minecraft:flat",
-            new WorldTypeFlat(
-                    WorldType.Properties.of("worldType.flat")
-                            .brightnessRamp(WorldTypeOverworld.createLightRamp())
-                            .fillerBlock(Blocks.STONE)
-                            .allowRespawn()
-                            .bounds(0, 31, 0)
-                            .portalBounds(0, 255)
-                            .seasonConfig(SeasonConfig.builder()
-                                    .withSingleSeason(Seasons.OVERWORLD_SUMMER)
-                                    .build()
-                            )
-            )
+        "minecraft:flat",
+        new WorldTypeFlat(
+            WorldType.Properties.of("worldType.flat")
+                .brightnessRamp(WorldTypeOverworld.createLightRamp())
+                .fillerBlock(Blocks.STONE)
+                .allowRespawn()
+                .bounds(0, 31, 0)
+                .portalBounds(0, 255)
+                .seasonConfig(SeasonConfig.builder()
+                    .withSingleSeason(Seasons.OVERWORLD_SUMMER)
+                    .build()
+                )
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_FLOATING = register(
-            "minecraft:overworld.floating",
-            new WorldTypeOverworldFloating(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.floating")
-                            .bounds(0, 255, 0)
-                            .oceanBlock(null)
-            )
+        "minecraft:overworld.floating",
+        new WorldTypeOverworldFloating(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.floating")
+                .bounds(0, 255, 0)
+                .oceanBlock(null)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_AMPLIFIED = register(
-            "minecraft:overworld.amplified",
-            new WorldTypeOverworld(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.amplified")
-                            .bounds(0, 255, 64)
-            )
+        "minecraft:overworld.amplified",
+        new WorldTypeOverworld(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.amplified")
+                .bounds(0, 255, 64)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_RETRO = register(
-            "minecraft:overworld.retro",
-            new WorldTypeOverworldRetro(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.retro")
-                            .seasonConfig(null)
-                            .bounds(0, 127, 64)
-                            .portalBounds(0, 255)
-                            .setRetro()
-            )
+        "minecraft:overworld.retro",
+        new WorldTypeOverworldRetro(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.retro")
+                .seasonConfig(null)
+                .bounds(0, 127, 64)
+                .portalBounds(0, 255)
+                .withTags(WorldTypeTags.OVERWORLD, WorldTypeTags.RETRO)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_ISLANDS = register(
-            "minecraft:overworld.islands",
-            new WorldTypeOverworld(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.islands")
-                            .bounds(0, 255, 160)
-            )
+        "minecraft:overworld.islands",
+        new WorldTypeOverworld(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.islands")
+                .bounds(0, 255, 160)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_WINTER = register(
-            "minecraft:overworld.winter",
-            new WorldTypeOverworld(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.winter")
-                            .seasonConfig(SeasonConfig.builder()
-                                    .withSingleSeason(Seasons.OVERWORLD_WINTER_ENDLESS)
-                                    .build()
-                            )
-                            .bounds(0, 127, 64)
-                            .portalBounds(0, 255)
-            )
+        "minecraft:overworld.winter",
+        new WorldTypeOverworld(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.winter")
+                .seasonConfig(SeasonConfig.builder()
+                    .withSingleSeason(Seasons.OVERWORLD_WINTER_ENDLESS)
+                    .build()
+                )
+                .bounds(0, 127, 64)
+                .portalBounds(0, 255)
+                .withTags(WorldTypeTags.OVERWORLD, WorldTypeTags.ENDLESS_SNOW, WorldTypeTags.COLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_HELL = register(
-            "minecraft:overworld.hell",
-            new WorldTypeOverworldHell(
-                    WorldType.Properties.of("worldType.overworld.hell")
-                            .brightnessRamp(WorldTypeOverworld.createLightRamp())
-                            .seasonConfig(SeasonConfig.builder()
-                                    .withSingleSeason(Seasons.OVERWORLD_HELL)
-                                    .build()
-                            )
-                            .oceanBlock(Blocks.FLUID_LAVA_STILL)
-                            .fillerBlock(Blocks.STONE)
-                            .allowRespawn()
-                            .bounds(0, 127, 64)
-                            .portalBounds(0, 255)
-                            .defaultWeather(Weathers.OVERWORLD_HELL_CLEAR)
-            )
+        "minecraft:overworld.hell",
+        new WorldTypeOverworldHell(
+            WorldType.Properties.of("worldType.overworld.hell")
+                .brightnessRamp(WorldTypeOverworld.createLightRamp())
+                .seasonConfig(SeasonConfig.builder()
+                    .withSingleSeason(Seasons.OVERWORLD_HELL)
+                    .build()
+                )
+                .oceanBlock(Blocks.FLUID_LAVA_STILL)
+                .fillerBlock(Blocks.STONE)
+                .allowRespawn()
+                .bounds(0, 127, 64)
+                .portalBounds(0, 255)
+                .defaultWeather(Weathers.OVERWORLD_HELL_CLEAR)
+                .withTags(WorldTypeTags.OVERWORLD, WorldTypeTags.HOT)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_WOODS = register(
-            "minecraft:overworld.woods",
-            new WorldTypeOverworldWoods(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.woods")
-                            .defaultWeather(Weathers.OVERWORLD_WOODS_CLEAR)
-            )
+        "minecraft:overworld.woods",
+        new WorldTypeOverworldWoods(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.woods")
+                .defaultWeather(Weathers.OVERWORLD_WOODS_CLEAR)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_PARADISE = register(
-            "minecraft:overworld.paradise",
-            new WorldTypeOverworldParadise(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.paradise")
-                            .seasonConfig(SeasonConfig.builder()
-                                    .withSingleSeason(Seasons.OVERWORLD_SPRING)
-                                    .build()
-                            )
-                            .bounds(0, 127, 64)
-                            .portalBounds(0, 255)
-            )
+        "minecraft:overworld.paradise",
+        new WorldTypeOverworldParadise(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.paradise")
+                .seasonConfig(SeasonConfig.builder()
+                    .withSingleSeason(Seasons.OVERWORLD_SPRING)
+                    .build()
+                )
+                .bounds(0, 127, 64)
+                .portalBounds(0, 255)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_INLAND = register(
-            "minecraft:overworld.inland",
-            new WorldTypeOverworldInland(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.inland")
-                            .bounds(0, 255, 0)
-                            .oceanBlock(null)
-            )
+        "minecraft:overworld.inland",
+        new WorldTypeOverworldInland(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.inland")
+                .bounds(0, 255, 0)
+                .oceanBlock(null)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_CLASSIC = register(
-            "minecraft:overworld.classic",
-            new WorldTypeOverworldClassic(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.classic")
-                            .seasonConfig(null)
-                            .bounds(0, 127, 64)
-                            .portalBounds(0, 255)
-                            .setRetro()
-            )
+        "minecraft:overworld.classic",
+        new WorldTypeOverworldClassic(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.classic")
+                .seasonConfig(null)
+                .bounds(0, 127, 64)
+                .portalBounds(0, 255)
+                .withTags(WorldTypeTags.OVERWORLD, WorldTypeTags.RETRO)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_INDEV = register(
-            "minecraft:overworld.indev",
-            new WorldTypeOverworldIndev(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.indev")
-                            .seasonConfig(null)
-                            .bounds(0, 127, 64)
-                            .portalBounds(0, 255)
-                            .setRetro()
-            )
+        "minecraft:overworld.indev",
+        new WorldTypeOverworldIndev(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.indev")
+                .seasonConfig(null)
+                .bounds(0, 127, 64)
+                .portalBounds(0, 255)
+                .withTags(WorldTypeTags.OVERWORLD, WorldTypeTags.RETRO)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_SKYBLOCK = register(
-            "minecraft:overworld.skyblock",
-            new WorldTypeOverworldSkyblock(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.skyblock")
-                        .bounds(0, 127, 0)
-                        .portalBounds(0, 255)
-            )
+        "minecraft:overworld.skyblock",
+        new WorldTypeOverworldSkyblock(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.skyblock")
+                .bounds(0, 127, 0)
+                .portalBounds(0, 255)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType OVERWORLD_BETA_173 = register(
-            "minecraft:overworld.beta_173",
-            new WorldTypeOverworldB173(
-                    WorldTypeOverworld.defaultProperties("worldType.overworld.beta_173")
-                            .bounds(0, 127, 64)
-            )
+        "minecraft:overworld.beta_173",
+        new WorldTypeOverworldB173(
+            WorldTypeOverworld.defaultProperties("worldType.overworld.beta_173")
+                .bounds(0, 127, 64)
+                .withTags(WorldTypeTags.OVERWORLD)
+        )
     );
     public static final @NotNull WorldType EMPTY = register(
-            "minecraft:empty",
-            new WorldTypeEmpty(
-                    WorldType.Properties.of("worldType.empty")
-                            .brightnessRamp(WorldTypeEmpty.createLightRamp())
-                            .bounds(0, 255, 0)
-                            .allowRespawn()
-            )
+        "minecraft:empty",
+        new WorldTypeEmpty(
+            WorldType.Properties.of("worldType.empty")
+                .brightnessRamp(WorldTypeEmpty.createLightRamp())
+                .bounds(0, 255, 0)
+                .allowRespawn()
+        )
     );
     public static final @NotNull WorldType DEBUG = register(
-            "minecraft:debug",
-            new WorldTypeDebug(
-                    WorldType.Properties.of("worldType.debug")
-                            .brightnessRamp(WorldTypeDebug.createLightRamp())
-                            .bounds(0, 255, 0)
-                            .allowRespawn()
-            )
+        "minecraft:debug",
+        new WorldTypeDebug(
+            WorldType.Properties.of("worldType.debug")
+                .brightnessRamp(WorldTypeDebug.createLightRamp())
+                .bounds(0, 255, 0)
+                .allowRespawn()
+        )
     );
 
     public static @NotNull WorldType register(final @NotNull String key, final @NotNull WorldType worldType) {
@@ -209,5 +226,6 @@ public abstract class WorldTypes {
         return worldType;
     }
 
-    public static void init() { }
+    public static void init() {
+    }
 }
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 f9f47b6f6..a5eb5c736 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
@@ -16,22 +16,22 @@ import net.minecraft.core.world.type.WorldType;
 import org.jetbrains.annotations.NotNull;
 
 public class WorldTypeDrift
-        extends WorldType {
+    extends WorldType {
     public WorldTypeDrift(Properties properties) {
         super(properties);
     }
 
     public static Properties defaultProperties(String translationKey) {
         return Properties.of(translationKey)
-                .brightnessRamp(createLightRamp())
-                .seasonConfig(SeasonConfig.builder()
-                        .withSeasonInCycle(Seasons.DRIFT_GOLD, 28)
-                        .withSeasonInCycle(Seasons.DRIFT_SILVER, 28)
-                        .build()
-                )
-                .fillerBlock(Blocks.MARBLE)
-                .dayNightCycleTicks(Global.DAY_LENGTH_TICKS * 28 * 2)
-                .bounds(0, 255, 0);
+            .brightnessRamp(createLightRamp())
+            .seasonConfig(SeasonConfig.builder()
+                .withSeasonInCycle(Seasons.DRIFT_GOLD, 28)
+                .withSeasonInCycle(Seasons.DRIFT_SILVER, 28)
+                .build()
+            )
+            .fillerBlock(Blocks.MARBLE)
+            .dayNightCycleTicks(Global.DAY_LENGTH_TICKS * 28 * 2)
+            .bounds(0, 255, 0);
     }
 
     private static float[] createLightRamp() {
@@ -59,7 +59,7 @@ public class WorldTypeDrift
 
     @Override
     public @NotNull Biome @NotNull [] allBiomes() {
-        return new Biome[] { Biomes.DRIFT_DRIFT };
+        return new Biome[]{Biomes.DRIFT_DRIFT};
     }
 
     @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 f1d3328e7..453d831db 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
@@ -11,6 +11,7 @@ import net.minecraft.core.world.generate.chunk.ChunkGenerator;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.ChunkGeneratorOverworld;
 import net.minecraft.core.world.season.Seasons;
 import net.minecraft.core.world.type.WorldType;
+import net.minecraft.core.world.type.tag.WorldTypeTags;
 import net.minecraft.core.world.weather.Weather;
 import org.jetbrains.annotations.NotNull;
 
@@ -28,17 +29,17 @@ public class WorldTypeOverworld extends WorldType {
 
     public static @NotNull Properties defaultProperties(@NotNull String translationKey) {
         return Properties.of(translationKey)
-                .brightnessRamp(createLightRamp())
-                .seasonConfig(SeasonConfig.builder()
-                        .withSeasonInCycle(Seasons.OVERWORLD_SPRING, 14)
-                        .withSeasonInCycle(Seasons.OVERWORLD_SUMMER, 14)
-                        .withSeasonInCycle(Seasons.OVERWORLD_FALL, 14)
-                        .withSeasonInCycle(Seasons.OVERWORLD_WINTER, 14)
-                        .build()
-                )
-                .oceanBlock(Blocks.FLUID_WATER_STILL)
-                .fillerBlock(Blocks.STONE)
-                .allowRespawn();
+            .brightnessRamp(createLightRamp())
+            .seasonConfig(SeasonConfig.builder()
+                .withSeasonInCycle(Seasons.OVERWORLD_SPRING, 14)
+                .withSeasonInCycle(Seasons.OVERWORLD_SUMMER, 14)
+                .withSeasonInCycle(Seasons.OVERWORLD_FALL, 14)
+                .withSeasonInCycle(Seasons.OVERWORLD_WINTER, 14)
+                .build()
+            )
+            .oceanBlock(Blocks.FLUID_WATER_STILL)
+            .fillerBlock(Blocks.STONE)
+            .allowRespawn();
     }
 
     public static float[] createLightRamp() {
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/tag/WorldTypeTags.java b/game/core/src/main/java/net/minecraft/core/world/type/tag/WorldTypeTags.java
new file mode 100644
index 000000000..330d6df4d
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/type/tag/WorldTypeTags.java
@@ -0,0 +1,56 @@
+package net.minecraft.core.world.type.tag;
+
+import net.minecraft.core.data.tag.Tag;
+import net.minecraft.core.world.type.WorldType;
+import org.jetbrains.annotations.NotNull;
+
+public final class WorldTypeTags {
+    private WorldTypeTags() throws IllegalAccessException {
+        throw new IllegalAccessException("Attempted instantiation of helper class!");
+    }
+
+    /**
+     * World type is of a "retro" variety - e.g. displays old grass, cobblestone textures
+     */
+    public static final @NotNull Tag<WorldType> RETRO = Tag.of("retro");
+
+    /**
+     * World type displays behaviors consistent with the Overworld dimension.
+     */
+    public static final @NotNull Tag<WorldType> OVERWORLD = Tag.of("overworld");
+
+    /**
+     * World type displays behaviors consistent with the Nether dimension.
+     */
+    public static final @NotNull Tag<WorldType> NETHER = Tag.of("nether");
+
+    /**
+     * World type displays behaviors consistent with the Drift dimension.
+     */
+    public static final @NotNull Tag<WorldType> DRIFT = Tag.of("drift");
+
+    /**
+     * World type is hotter than the Overworld.
+     */
+    public static final @NotNull Tag<WorldType> HOT = Tag.of("hot");
+
+    /**
+     * World type is colder than the Overworld.
+     */
+    public static final @NotNull Tag<WorldType> COLD = Tag.of("cold");
+
+    /**
+     * World type is covered in omnipresent snow.
+     */
+    public static final @NotNull Tag<WorldType> ENDLESS_SNOW = Tag.of("endless_snow");
+
+    /**
+     * Compass displays screwy behavior in this world type.
+     */
+    public static final @NotNull Tag<WorldType> BREAKS_COMPASS = Tag.of("breaks_compass");
+
+    /**
+     * Timepieces (clock, rotary calendar) display screwy behavior in this world type.
+     */
+    public static final @NotNull Tag<WorldType> BREAKS_TIMEPIECES = Tag.of("breaks_timepieces");
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java b/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
index ce6d5835d..f69505d13 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
@@ -2,6 +2,7 @@ package net.minecraft.core.world.weather;
 
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.chunk.Chunk;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.PropertyKey;
@@ -69,7 +70,7 @@ public abstract class Weather {
             final int blockId = world.getBlockId(x, y, z);
             final int blockIdBelow = world.getBlockId(x, y - 1, z);
 
-            if (world.getBlockBiome(x, y, z).hasSurfaceSnow()) {
+            if (world.getBlockBiome(x, y, z).hasTag(BiomeTags.HAS_SURFACE_SNOW)) {
                 if (blockId == Blocks.LAYER_SNOW.id()) {
                     final int meta = world.getBlockMetadata(x, y, z);
                     if (meta != 0) {
@@ -106,7 +107,7 @@ public abstract class Weather {
                 int blockId = chunk.getBlockID(x, y, z);
                 int blockIdBelow = chunk.getBlockID(x, y - 1, z);
 
-                if (world.getBlockBiome(chunk.pos.x * 16 + x, y, chunk.pos.z * 16 + z).hasSurfaceSnow()) {
+                if (world.getBlockBiome(chunk.pos.x * 16 + x, y, chunk.pos.z * 16 + z).hasTag(BiomeTags.HAS_SURFACE_SNOW)) {
                     if (blockId == Blocks.LAYER_SNOW.id()) {
                         chunk.setBlockMetadata(x, y, z, 0);
                     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
index b506f58d3..2d3e063ba 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
@@ -8,6 +8,7 @@ import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.BiomeTags;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.pos.TilePos;
@@ -45,14 +46,13 @@ public class WeatherSnow
         if (world.getWeatherManager().getWeatherPower() <= 0.6f) return;
         for (int x = 0; x < 16; x++) {
             int worldX = chunk.pos.x * 16 + x;
-            zLoop:
             for (int z = 0; z < 16; z++) {
                 int worldZ = chunk.pos.z * 16 + z;
                 int y = world.findTopSolidBlock(worldX, worldZ);
 
                 Biome biome = world.getBlockBiome(worldX, y, worldZ);
-                for (int i = 0; i < biome.blockedWeathers.length; i++) {
-                    if (biome.blockedWeathers[i] == this) continue zLoop;
+                if (biome.blockedWeathers.contains(this)) {
+                    continue;
                 }
 
                 int blockId = chunk.getBlockID(x, y, z);
@@ -92,8 +92,8 @@ public class WeatherSnow
         int blockIdBelow = world.getBlockId(x, y - 1, z);
 
         Biome biome = world.getBlockBiome(x, y, z);
-        for (int i = 0; i < biome.blockedWeathers.length; i++) {
-            if (biome.blockedWeathers[i] == this) return;
+        if (biome.blockedWeathers.contains(this)) {
+            return;
         }
 
         if (world.getWeatherManager().getWeatherPower() > 0.6f && y >= 0 && y < world.getHeightBlocks() && world.getSavedLightValue(LightLayer.Block, x, y, z) < 10) {
@@ -101,7 +101,12 @@ public class WeatherSnow
                 if (snow) {
                     world.setBlockWithNotify(x, y, z, Blocks.LAYER_SNOW.id());
                 }
-            } else if (world.getWeatherManager().getWeatherPower() > 0.5f && blockId == Blocks.LAYER_SNOW.id() && world.getSeasonManager().getCurrentSeason() != null && (world.getSeasonManager().getCurrentSeason().hasDeeperSnow || biome == Biomes.OVERWORLD_GLACIER)) {
+            } else if (
+                world.getWeatherManager().getWeatherPower() > 0.5f &&
+                blockId == Blocks.LAYER_SNOW.id() &&
+                world.getSeasonManager().getCurrentSeason() != null &&
+                (world.getSeasonManager().getCurrentSeason().hasDeeperSnow || biome.hasTag(BiomeTags.DEEPER_SNOW))
+            ) {
                 if (snow) {
                     Blocks.LAYER_SNOW.getLogic().accumulate(world, new TilePos(x, y, z));
                 }
diff --git a/game/core/src/main/resources/lang/en_US/biomes.lang b/game/core/src/main/resources/lang/en_US/biomes.lang
index c63d7b317..3d5aeee0a 100644
--- a/game/core/src/main/resources/lang/en_US/biomes.lang
+++ b/game/core/src/main/resources/lang/en_US/biomes.lang
@@ -2,7 +2,6 @@ biome.overworld.rainforest=Rainforest
 biome.overworld.swampland=Swamp
 biome.overworld.seasonal_forest=Seasonal Forest
 biome.overworld.forest=Forest
-biome.overworld.forest.dry=Dry Forest
 biome.overworld.grasslands=Grasslands
 biome.overworld.outback=Outback
 biome.overworld.shrubland=Shrubland
@@ -26,7 +25,7 @@ biome.nether.old_world=The Old World
 biome.nether.volcanic_islands=Volcanic Islands
 biome.nether.sulfur_pools=Sulfur Pools
 biome.nether.crystal_forest=Crystal Forest
-biome.nether.crystal_field=Crystal Field
+biome.nether.crystal_plains=Crystal Plains
 biome.nether.shelf=The Shelf
 biome.drift.drift=Drift
 
diff --git a/game/core/src/main/resources/lang/en_US/strings.lang b/game/core/src/main/resources/lang/en_US/strings.lang
index a7991f724..a9e8760e3 100644
--- a/game/core/src/main/resources/lang/en_US/strings.lang
+++ b/game/core/src/main/resources/lang/en_US/strings.lang
@@ -16,6 +16,7 @@ weather.overworld.clear.name=Clear
 weather.overworld.hell.clear.name=Clear
 weather.overworld.woods.clear.name=Clear
 weather.overworld.rain.name=Raining
+weather.overworld.rain.blood.name=Raining?
 weather.overworld.snow.name=Snowing
 weather.overworld.winter.snow.name=Snowing
 weather.overworld.storm.name=Thundering
