diff --git a/game/client/build.gradle.kts b/game/client/build.gradle.kts
index 3b7f26ad2..78a61ac68 100644
--- a/game/client/build.gradle.kts
+++ b/game/client/build.gradle.kts
@@ -83,6 +83,8 @@ java {
 
 //region Tasks
 val manifestGenerator by tasks.registering {
+    outputs.upToDateWhen { false }
+
     group = "bta.generator"
     outputs.dir(temporaryDir)
 
diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java
index 39aa080a1..b48af2805 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -76,7 +76,6 @@ import net.minecraft.core.net.command.commands.CommandTime;
 import net.minecraft.core.net.command.commands.CommandWeather;
 import net.minecraft.core.net.command.util.CommandHelper;
 import net.minecraft.core.util.collection.NamespaceID;
-import net.minecraft.core.util.helper.AES;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.LoggedPrintStream;
 import net.minecraft.core.util.helper.UUIDHelper;
@@ -1189,7 +1188,7 @@ public class Minecraft
     {
         try
         {
-            renderGlobal.deleteRenderListBase();
+            renderGlobal.deleteChunkLists();
         }
         catch(Throwable ignored) { }
         try
@@ -1563,7 +1562,7 @@ public class Minecraft
                         	int step = Math.round(gameSettings.flightSpeed.value * steps);
                         	step += MathHelper.clamp(scrollDelta, -1, 1);
                         	float newSpeed = step / steps;
-                        	newSpeed = MathHelper.clamp(newSpeed, 0.0f, 1.0f);
+                        	newSpeed = MathHelper.clamp(newSpeed, 0.0f, 5.0f);
                         	
                         	gameSettings.flightSpeed.value = newSpeed;
                         	
@@ -1687,7 +1686,7 @@ public class Minecraft
                                     {
                                         fullbright = !fullbright;
                                         if(!LightmapHelper.isLightmapEnabled()) {
-                                        	renderGlobal.loadRenderers();
+                                        	renderGlobal.allChanged();
                                         }
                                     }
                                 }
@@ -1697,7 +1696,7 @@ public class Minecraft
                                     {
                                         fullbright = !fullbright;
                                         if(!LightmapHelper.isLightmapEnabled()) {
-                                        	renderGlobal.loadRenderers();
+                                        	renderGlobal.allChanged();
                                         }
                                     }
                                 }
@@ -1708,11 +1707,11 @@ public class Minecraft
                             	if(gameSettings.lightmapStyle.value == LightmapStyle.DISABLED) {
                             		gameSettings.lightmapStyle.value = LightmapStyle.GRAY;
                             		hudIngame.heldItemTooltipElement.setString("Lightmap: On");
-                            		renderGlobal.loadRenderers();
+                            		renderGlobal.allChanged();
                             	}else {
                             		gameSettings.lightmapStyle.value = LightmapStyle.DISABLED;
                             		hudIngame.heldItemTooltipElement.setString("Lightmap: Off");
-                            		renderGlobal.loadRenderers();
+                            		renderGlobal.allChanged();
                             	}
                             }
                             else if (gameSettings.keyCollisionBoxes.isPressEvent())
@@ -1741,7 +1740,7 @@ public class Minecraft
                             }
                             else if (gameSettings.keyReloadChunks.isPressEvent())
                             {
-                                renderGlobal.loadRenderers();
+                                renderGlobal.allChanged();
                             }
                             else if (gameSettings.keySmoothLighting.isPressEvent())
                             {
@@ -1810,7 +1809,7 @@ public class Minecraft
             if(!isGamePaused)
             {
                 worldRenderer.updateRenderer();
-                renderGlobal.updateClouds();
+                renderGlobal.tick();
                 TileEntityRenderDispatcher.instance.tick();
 
                 Debug.change("entity");
@@ -2216,7 +2215,7 @@ public class Minecraft
         texturePackList.refresh();
         renderer.reload();
         if (renderGlobal != null){
-            renderGlobal.loadRenderers();
+            renderGlobal.allChanged();
         }
         LOGGER.debug("RELOAD TOOK '{}' SECONDS!", (System.nanoTime() - start) / 1_000_000_000d);
     }
@@ -2413,7 +2412,7 @@ public class Minecraft
             thePlayer.input = new PlayerInput(this);
             if(renderGlobal != null)
             {
-                renderGlobal.changeWorld(world);
+                renderGlobal.setWorld(world);
             }
             if(particleEngine != null)
             {
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 212d9267e..6076e74e4 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
@@ -33,7 +33,7 @@ public class RichPresenceHandlerThread extends Thread {
     static {
         dimensionNamesMap.put(Dimension.OVERWORLD, "the Overworld");
         dimensionNamesMap.put(Dimension.NETHER, "the Nether");
-        dimensionNamesMap.put(Dimension.PARADISE, "Paradise");
+        dimensionNamesMap.put(Dimension.DRIFT, "the Drift");
     }
 
     private static final Map<Biome, String> biomeNamesMap = new HashMap<>();
@@ -54,7 +54,7 @@ public class RichPresenceHandlerThread extends Thread {
         biomeNamesMap.put(Biomes.OVERWORLD_TUNDRA, "a tundra");
         biomeNamesMap.put(Biomes.OVERWORLD_MEADOW, "a meadow");
         biomeNamesMap.put(Biomes.NETHER_NETHER, "Hell itself");
-        biomeNamesMap.put(Biomes.PARADISE_PARADISE, "the skies");
+        biomeNamesMap.put(Biomes.DRIFT_DRIFT, "the skies");
         biomeNamesMap.put(Biomes.OVERWORLD_BIRCH_FOREST, "a birch forest");
         biomeNamesMap.put(Biomes.OVERWORLD_RETRO, "a world long forgotten");
         biomeNamesMap.put(Biomes.OVERWORLD_HELL, "a ruined world");
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java b/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
index 83c3b7998..e8427f607 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
@@ -569,7 +569,7 @@ public class ScreenOptions
 
     private void reloadIfReady() {
         if (queueReload) {
-            mc.renderGlobal.loadRenderers();
+            mc.renderGlobal.allChanged();
             queueReload = false;
         }
     }
diff --git a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
index d05b0c3ac..a45da7a3a 100644
--- a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
+++ b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
@@ -459,7 +459,7 @@ public class GameSettings {
 			if (mc.currentScreen instanceof ScreenOptions) {
 				ScreenOptions.queueReload = true;
 			} else {
-				mc.renderGlobal.loadRenderers();
+				mc.renderGlobal.allChanged();
 			}
 		}
 
@@ -473,20 +473,20 @@ public class GameSettings {
 		if(option == playerPantRight && mc.thePlayer != null) {mc.thePlayer.playerConfig.setPantRight(playerPantRight.value);}
 
 		if(option == enableVsync) mc.gameWindow.setVsync(enableVsync.value);
-		if(option == fancyGraphics) mc.renderGlobal.loadRenderers();
-		if(option == ambientOcclusion) mc.renderGlobal.loadRenderers();
-		if(option == connectedGlass) mc.renderGlobal.loadRenderers();
-		if(option == advancedOpenGL) mc.renderGlobal.loadRenderers();
+		if(option == fancyGraphics) mc.renderGlobal.allChanged();
+		if(option == ambientOcclusion) mc.renderGlobal.allChanged();
+		if(option == connectedGlass) mc.renderGlobal.allChanged();
+		if(option == advancedOpenGL) mc.renderGlobal.allChanged();
 		if(option == biomeWater) {
-			mc.renderGlobal.loadRenderers();
+			mc.renderGlobal.allChanged();
 			mc.textureManager.updateDynamicTextures(false);
 		}
-		if(option == treeShadows) mc.renderGlobal.loadRenderers();
+		if(option == treeShadows) mc.renderGlobal.allChanged();
 		if(option == placementMode && mc.thePlayer != null) mc.thePlayer.syncPlacementMode();
 		if(option == animations || option == customAnimations) {
 			mc.textureManager.refreshTexturesAndDisplayErrors();
 			mc.textureManager.updateDynamicTextures(false);
-			mc.renderGlobal.loadRenderers();
+			mc.renderGlobal.allChanged();
 		}
 		if(option == fullscreen) mc.gameWindow.updateWindowState();
 		if(option == borderlessFullscreen && fullscreen.value) mc.gameWindow.updateWindowState();
@@ -520,7 +520,7 @@ public class GameSettings {
 		}
 		if(option == lightmapStyle) {
 			if (mc.renderGlobal != null) {
-				mc.renderGlobal.loadRenderers();
+				mc.renderGlobal.allChanged();
 			}
 		}
 		if(option == customLightmap) {
@@ -531,7 +531,7 @@ public class GameSettings {
 		}
 		if(option == enableHolidayTextures) {
 			mc.textureManager.refreshTexturesAndDisplayErrors();
-			mc.renderGlobal.loadRenderers();
+			mc.renderGlobal.allChanged();
 		}
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java
index aad6531bd..318070a11 100644
--- a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java
+++ b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java
@@ -205,11 +205,11 @@ public abstract class PlayerController {
 	public void render(float f) {
 		if (currentDamage <= 0.0F) {
 			mc.hudIngame.damageGuiPartialTime = 0.0F;
-			mc.renderGlobal.damagePartialTime = 0.0F;
+			mc.renderGlobal.destroyProgress = 0.0F;
 		} else {
 			float f1 = previousDamage + (currentDamage - previousDamage) * f;
 			mc.hudIngame.damageGuiPartialTime = f1;
-			mc.renderGlobal.damagePartialTime = f1;
+			mc.renderGlobal.destroyProgress = f1;
 		}
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/ChunkRendererComparator.java b/game/client/src/main/java/net/minecraft/client/render/DirtyChunkRendererSorter.java
similarity index 92%
rename from game/client/src/main/java/net/minecraft/client/render/ChunkRendererComparator.java
rename to game/client/src/main/java/net/minecraft/client/render/DirtyChunkRendererSorter.java
index 292a3ab06..91b34646a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/ChunkRendererComparator.java
+++ b/game/client/src/main/java/net/minecraft/client/render/DirtyChunkRendererSorter.java
@@ -5,11 +5,11 @@ import net.minecraft.client.render.terrain.ChunkRenderer;
 
 import java.util.Comparator;
 
-public class ChunkRendererComparator
+public class DirtyChunkRendererSorter
     implements Comparator<ChunkRenderer>
 {
 
-    public ChunkRendererComparator(ICamera activeCamera)
+    public DirtyChunkRendererSorter(ICamera activeCamera)
     {
         this.activeCamera = activeCamera;
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/LoadingScreenRenderer.java b/game/client/src/main/java/net/minecraft/client/render/LoadingScreenRenderer.java
index 5147e0bf7..3614e14aa 100644
--- a/game/client/src/main/java/net/minecraft/client/render/LoadingScreenRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/LoadingScreenRenderer.java
@@ -111,9 +111,9 @@ public class LoadingScreenRenderer
         {
             backgroundPath = "/assets/minecraft/textures/gui/background-loading-nether.png";
         }
-        else if (dimension == Dimension.PARADISE)
+        else if (dimension == Dimension.DRIFT)
         {
-            backgroundPath = "/assets/minecraft/textures/gui/background-loading-paradise.png";
+            backgroundPath = "/assets/minecraft/textures/gui/background-loading-drift.png";
         }
         else
         {
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 c0ef84e18..93f52d515 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
@@ -7,7 +7,6 @@ import net.minecraft.client.entity.particle.ParticleDispatcher;
 import net.minecraft.client.gui.ScreenPhotoMode;
 import net.minecraft.client.gui.modelviewer.ScreenModelViewer;
 import net.minecraft.client.gui.options.ScreenOptions;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.block.model.BlockModelLeaves;
 import net.minecraft.client.render.camera.EntityCamera;
@@ -18,7 +17,6 @@ import net.minecraft.client.render.terrain.ChunkRenderer;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.client.render.tileentity.TileEntityRenderer;
 import net.minecraft.client.render.worldtype.WorldTypeFX;
 import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher;
 import net.minecraft.client.world.WorldClient;
@@ -66,57 +64,59 @@ public class RenderGlobal
         }
     }
     public static final int RENDER_CHUNK_SIZE = 16;
+    public static final int MAX_VISIBLE_REBUILDS_PER_FRAME = 2;
+    public static final int MAX_INVISIBLE_REBUILDS_PER_FRAME = 1;
     public static final int RENDER_LIST_BASE_WIDTH = 48;
 
-    public List<TileEntity> tileEntities;
-    private WorldClient worldObj;
+    public List<TileEntity> renderableTileEntities = new ArrayList<>();
+    private WorldClient world;
     private final TextureManager textureManager;
-    private final List<ChunkRenderer> chunkRenderersToUpdate;
+    private final List<ChunkRenderer> dirtyChunks = new ArrayList<>();
     private ChunkRenderer[] sortedChunkRenderers;
     private ChunkRenderer[] chunkRenderers;
-    private int renderChunksWide;
-    private int renderChunksTall;
-    private int renderChunksDeep;
-    private int glRenderListBase;
+    private int xChunks;
+    private int yChunks;
+    private int zChunks;
+    private int chunkLists;
     private final Minecraft mc;
-    private IntBuffer glOcclusionQueryBase;
-    private boolean occlusionEnabled;
+    private IntBuffer occlusionCheckIds;
+    private boolean occlusionCheck = false;
     private float lastCloudOffsetX = 0;
     private float lastCloudOffsetZ = 0;
-    private float cloudOffsetX;
-    private float cloudOffsetZ;
+    private float cloudOffsetX = 0;
+    private float cloudOffsetZ = 0;
     private float cloudVelocityX;
     private float cloudVelocityZ;
-
-    private final int starGLCallList;
-    private final int glSkyList;
-    private int minBlockX;
-    private int minBlockY;
-    private int minBlockZ;
-    private int maxBlockX;
-    private int maxBlockY;
-    private int maxBlockZ;
+    private int ticks;
+    private final int starList;
+    private final int skyList;
+    private int xMinChunk;
+    private int yMinChunk;
+    private int zMinChunk;
+    private int xMaxChunk;
+    private int yMaxChunk;
+    private int zMaxChunk;
     private Integer renderDistance = null;
-    private int renderEntitiesStartupCounter;
-    private int countEntitiesTotal;
-    private int countEntitiesRendered;
-    private int countEntitiesHidden;
-    IntBuffer occlusionResult;
-    private int renderersLoaded;
-    private int renderersBeingClipped;
-    private int renderersBeingOccluded;
-    private int renderersBeingRendered;
-    private int renderersSkippingRenderPass;
-    private int worldRenderersCheckIndex;
-    private final List<ChunkRenderer> glRenderLists;
-    private final DisplayList[] allDisplayLists = {
+    private int noEntityRenderFrames = 2;
+    private int totalEntities;
+    private int renderedEntities;
+    private int culledEntities;
+    IntBuffer resultBuffer = GLAllocation.createDirectIntBuffer(64);
+    private int totalChunks;
+    private int offscreenChunks;
+    private int occludedChunks;
+    private int renderedChunks;
+    private int emptyChunks;
+    private int chunkFixOffs;
+    private final List<ChunkRenderer> renderChunks = new ArrayList<>();
+    private final DisplayList[] renderLists = {
         new DisplayList(), new DisplayList(), new DisplayList(), new DisplayList()
     };
-    double prevSortX;
-    double prevSortY;
-    double prevSortZ;
-    public float damagePartialTime;
-    int frustumCheckOffset;
+    double xOld = -9999D;
+    double yOld = -9999D;
+    double zOld = -9999D;
+    public float destroyProgress;
+    int cullStep = 0;
 
     private double auroraBrightness = 0.0f;
     private double targetAuroraBrightness = Double.NaN;
@@ -126,54 +126,43 @@ public class RenderGlobal
     private double targetRainbowBrightness = Double.NaN;
     private double rainbowBrightnessDelta = Double.NaN;
 
-    public RenderGlobal(Minecraft minecraft, TextureManager textureManager)
+    public RenderGlobal(Minecraft mc, TextureManager textureManager)
     {
-        tileEntities = new ArrayList<>();
-        chunkRenderersToUpdate = new ArrayList<>();
-        occlusionEnabled = false;
-        cloudOffsetX = 0;
-        renderEntitiesStartupCounter = 2;
-        occlusionResult = GLAllocation.createDirectIntBuffer(64);
-        glRenderLists = new ArrayList<>();
-        prevSortX = -9999D;
-        prevSortY = -9999D;
-        prevSortZ = -9999D;
-        frustumCheckOffset = 0;
-        mc = minecraft;
+        this.mc = mc;
         this.textureManager = textureManager;
-        glRenderListBase = GLAllocation.generateDisplayLists(RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * 3);
-        occlusionEnabled = OpenGLHelper.enableOcclusionCheck;
-        if(occlusionEnabled)
+        chunkLists = GLAllocation.generateDisplayLists(RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * MAX_VISIBLE_REBUILDS_PER_FRAME);
+        occlusionCheck = OpenGLHelper.enableOcclusionCheck;
+        if(occlusionCheck)
         {
-            occlusionResult.clear();
-            glOcclusionQueryBase = GLAllocation.createDirectIntBuffer(RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH);
-            glOcclusionQueryBase.clear();
-            glOcclusionQueryBase.position(0);
-            glOcclusionQueryBase.limit(RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH);
-            ARBOcclusionQuery.glGenQueriesARB(glOcclusionQueryBase);
+            resultBuffer.clear();
+            occlusionCheckIds = GLAllocation.createDirectIntBuffer(RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH);
+            occlusionCheckIds.clear();
+            occlusionCheckIds.position(0);
+            occlusionCheckIds.limit(RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH);
+            ARBOcclusionQuery.glGenQueriesARB(occlusionCheckIds);
         }
 
         // Set up call list for stars
-        starGLCallList = GLAllocation.generateDisplayLists(3);
+        starList = GLAllocation.generateDisplayLists(3);
         updateStars();
 
         // Set up call list for sky
-        Tessellator tessellator = Tessellator.instance;
-        glSkyList = starGLCallList + 1;
-        GL11.glNewList(glSkyList, GL11.GL_COMPILE);
-        byte byte1 = 64;
-        int i = 256 / byte1 + 2;
-        float y = 16F;
-        for(int x = -byte1 * i; x <= byte1 * i; x += byte1)
+        Tessellator t = Tessellator.instance;
+        skyList = starList + 1;
+        GL11.glNewList(skyList, GL11.GL_COMPILE);
+        int s = 64;
+        int d = 256 / s + 2;
+        float yy = 16F;
+        for(int xx = -s * d; xx <= s * d; xx += s)
         {
-            for(int z = -byte1 * i; z <= byte1 * i; z += byte1)
+            for(int zz = -s * d; zz <= s * d; zz += s)
             {
-                tessellator.startDrawingQuads();
-                tessellator.addVertex(x, y, z);
-                tessellator.addVertex(x + byte1, y, z);
-                tessellator.addVertex(x + byte1, y, z + byte1);
-                tessellator.addVertex(x, y, z + byte1);
-                tessellator.draw();
+                t.startDrawingQuads();
+                t.addVertex(xx, yy, zz);
+                t.addVertex(xx + s, yy, zz);
+                t.addVertex(xx + s, yy, zz + s);
+                t.addVertex(xx, yy, zz + s);
+                t.draw();
             }
         }
         GL11.glEndList();
@@ -181,13 +170,13 @@ public class RenderGlobal
 
     public void updateStars() {
         GL11.glPushMatrix();
-        GL11.glNewList(starGLCallList, GL11.GL_COMPILE);
-        setupStarsCallList();
+        GL11.glNewList(starList, GL11.GL_COMPILE);
+        renderStars();
         GL11.glEndList();
         GL11.glPopMatrix();
     }
 
-    private void setupStarsCallList()
+    private void renderStars()
     {
         Random random = new Random(10842L);
         Random colorRandom = new Random(10842L); // Created a second random so the new color don't change the positions of the stars
@@ -242,36 +231,36 @@ public class RenderGlobal
         tessellator.draw();
     }
 
-    public void changeWorld(final WorldClient world)
+    public void setWorld(final WorldClient world)
     {
-        if(this.worldObj != null)
+        if(this.world != null)
         {
-            this.worldObj.removeListener(this);
+            this.world.removeListener(this);
         }
-        this.prevSortX = -9999D;
-        this.prevSortY = -9999D;
-        this.prevSortZ = -9999D;
-        this.worldObj = world;
+        this.xOld = -9999D;
+        this.yOld = -9999D;
+        this.zOld = -9999D;
+        this.world = world;
         this.auroraBrightness = 0.0f;
         this.targetAuroraBrightness = Float.NaN;
         if(world != null)
         {
             world.addListener(this);
-            loadRenderers();
+            allChanged();
         }
     }
-    public void loadRenderers()
+    public void allChanged()
     {
         ScreenOptions.queueReload = false;
         updateStars();
         // Delete all display lists - this is a (hopefully temporary) workaround to AMD's OpenGL driver leaking memory
         // See https://community.amd.com/t5/opengl-vulkan/high-vram-consumption-in-minecraft/m-p/607299
-        deleteRenderListBase();
-        glRenderListBase = GLAllocation.generateDisplayLists(RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * 3);
+        deleteChunkLists();
+        chunkLists = GLAllocation.generateDisplayLists(RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * RENDER_LIST_BASE_WIDTH * MAX_VISIBLE_REBUILDS_PER_FRAME);
 
         BlockModelLeaves.setGraphicsLevel(mc.gameSettings.fancyGraphics.value == 1);
         renderDistance = mc.gameSettings.renderDistance.value;
-        if (worldObj == null) return;
+        if (world == null) return;
 
         // Reset all world renderers
         if(chunkRenderers != null)
@@ -281,76 +270,83 @@ public class RenderGlobal
                 chunkRenderer.delete();
             }
         }
-        int renderDiameterBlocks = renderDistance * 16 * 2;
-		renderChunksWide = renderDiameterBlocks / RENDER_CHUNK_SIZE + 1;
-        renderChunksTall = worldObj.getHeightBlocks() / RENDER_CHUNK_SIZE;
-		renderChunksDeep =  renderDiameterBlocks / RENDER_CHUNK_SIZE + 1;
-        chunkRenderers = new ChunkRenderer[renderChunksWide * renderChunksTall * renderChunksDeep];
-        sortedChunkRenderers = new ChunkRenderer[renderChunksWide * renderChunksTall * renderChunksDeep];
-        int renderListOffset = 0;
-        int chunkIndex = 0;
-        minBlockX = 0;
-        minBlockY = 0;
-        minBlockZ = 0;
-        maxBlockX = renderChunksWide;
-        maxBlockY = renderChunksTall;
-        maxBlockZ = renderChunksDeep;
-        for (ChunkRenderer cr : chunkRenderersToUpdate)
+        int dist = renderDistance * 16 * 2;
+
+		xChunks = dist / RENDER_CHUNK_SIZE + 1;
+        yChunks = world.getHeightBlocks() / RENDER_CHUNK_SIZE;
+		zChunks =  dist / RENDER_CHUNK_SIZE + 1;
+
+        chunkRenderers = new ChunkRenderer[xChunks * yChunks * zChunks];
+        sortedChunkRenderers = new ChunkRenderer[xChunks * yChunks * zChunks];
+
+        int id = 0;
+        int count = 0;
+
+        xMinChunk = 0;
+        yMinChunk = 0;
+        zMinChunk = 0;
+        xMaxChunk = xChunks;
+        yMaxChunk = yChunks;
+        zMaxChunk = zChunks;
+
+        for (ChunkRenderer cr : dirtyChunks)
         {
             cr.dirty = false;
         }
 
-        chunkRenderersToUpdate.clear();
-        tileEntities.clear();
-        for(int x = 0; x < renderChunksWide; x++)
+        dirtyChunks.clear();
+        renderableTileEntities.clear();
+
+        for(int x = 0; x < xChunks; x++)
         {
-            for(int y = 0; y < renderChunksTall; y++)
+            for(int y = 0; y < yChunks; y++)
             {
-                for(int z = 0; z < renderChunksDeep; z++)
+                for(int z = 0; z < zChunks; z++)
                 {
-                    int index = (z * renderChunksTall + y) * renderChunksWide + x;
-                    chunkRenderers[index] = mc.terrainRenderer.createChunkRenderer(worldObj, tileEntities, x * RENDER_CHUNK_SIZE, y * RENDER_CHUNK_SIZE, z * RENDER_CHUNK_SIZE, RENDER_CHUNK_SIZE, glRenderListBase + renderListOffset);
-                    if(occlusionEnabled)
+                    int index = (z * yChunks + y) * xChunks + x;
+                    chunkRenderers[index] = mc.terrainRenderer.createChunkRenderer(world, renderableTileEntities, x * RENDER_CHUNK_SIZE, y * RENDER_CHUNK_SIZE, z * RENDER_CHUNK_SIZE, RENDER_CHUNK_SIZE, chunkLists + id);
+                    if(occlusionCheck)
                     {
-                        chunkRenderers[index].occlusionId = glOcclusionQueryBase.get(chunkIndex);
+                        chunkRenderers[index].occlusionId = occlusionCheckIds.get(count);
                     }
                     chunkRenderers[index].occlusionQuerying = false;
                     chunkRenderers[index].occlusionVisible = true;
                     chunkRenderers[index].visible = true;
-                    chunkRenderers[index].id = chunkIndex++;
+                    chunkRenderers[index].id = count++;
                     chunkRenderers[index].setDirty();
                     sortedChunkRenderers[index] = chunkRenderers[index];
-                    chunkRenderersToUpdate.add(chunkRenderers[index]);
-                    renderListOffset += ChunkRenderer.MAX_RENDER_PASSES + 1;
+                    dirtyChunks.add(chunkRenderers[index]);
+                    id += ChunkRenderer.MAX_RENDER_PASSES + 1;
                 }
 
             }
 
         }
 
-        if(worldObj != null)
+        if(world != null)
         {
             if (mc.activeCamera != null)
             {
-                markRenderersForNewPosition(MathHelper.floor(mc.activeCamera.getX()), MathHelper.floor(mc.activeCamera.getY()), MathHelper.floor(mc.activeCamera.getZ()));
+                resortChunks(MathHelper.floor(mc.activeCamera.getX()), MathHelper.floor(mc.activeCamera.getY()), MathHelper.floor(mc.activeCamera.getZ()));
                 Arrays.sort(sortedChunkRenderers, new CameraSorter(mc.activeCamera));
             }
         }
-        renderEntitiesStartupCounter = 2;
+
+        noEntityRenderFrames = 2;
     }
 
     public void renderAurora(ICamera camera, float partialTick)
     {
-        float celestialAngle = worldObj.getCelestialAngle(partialTick);
+        float celestialAngle = world.getCelestialAngle(partialTick);
         if (celestialAngle < 0.25f) return;
 
         double cameraX = camera.getX(partialTick);
         double cameraY = camera.getY(partialTick);
         double cameraZ = camera.getZ(partialTick);
         double cameraYaw = camera.getYRot(partialTick);
-        double temperature = worldObj.getBlockTemperature((int)cameraX, (int)cameraZ);
+        double temperature = world.getBlockTemperature((int)cameraX, (int)cameraZ);
         float mult = 0.0f;
-        if ((temperature <= 0.4f || worldObj.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER_ENDLESS) && worldObj.isChunkLoaded((int)cameraX, (int)cameraZ))
+        if ((temperature <= 0.4f || world.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER_ENDLESS) && world.isChunkLoaded((int)cameraX, (int)cameraZ))
         {
             // temperature from 0.0f to 0.4f
             temperature /= 0.4f;
@@ -360,8 +356,8 @@ public class RenderGlobal
             mult += temperature;
         }
 
-        double altitude = worldObj.getWorldType().getYPercentage((int)cameraY);
-        if ((temperature <= 0.6f || worldObj.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER || worldObj.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER_ENDLESS) && altitude >= 0.8f)
+        double altitude = world.getWorldType().getYPercentage((int)cameraY);
+        if ((temperature <= 0.6f || world.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER || world.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER_ENDLESS) && altitude >= 0.8f)
         {
             // altitude from 0.8f to 1.0f
             altitude -= 0.8f;
@@ -392,18 +388,18 @@ public class RenderGlobal
         GL11.glDisable(GL11.GL_ALPHA_TEST);
 
         final double scale = 1f;
-        double auroraY = (worldObj.getWorldType().getMinY() + worldObj.getWorldType().getYRange() + 64f) * 2f;
+        double auroraY = (world.getWorldType().getMinY() + world.getWorldType().getYRange() + 64f) * 2f;
 
         // Draw pieces
         double rotationX = Math.cos(((cameraYaw * Math.PI) / 180D));
         double rotationZ = Math.sin(((cameraYaw * Math.PI) / 180D));
 
         textureManager.bindTexture(textureManager.loadTexture("/assets/minecraft/textures/environment/aurora.png"));
-        double time = worldObj.getWorldTime() + partialTick;
-        AuroraProvider aurora = worldObj.auroraProvider;
+        double time = world.getWorldTime() + partialTick;
+        AuroraProvider aurora = world.auroraProvider;
 
         double radius = 512;
-        long worldTime = worldObj.getWorldTime();
+        long worldTime = world.getWorldTime();
 
         Tessellator.instance.startDrawingQuads();
         for (double x = -radius; x < radius; x += 8f)
@@ -455,30 +451,30 @@ public class RenderGlobal
 
     public void renderEntities(ICamera camera, float partialTick)
     {
-        if(renderEntitiesStartupCounter > 0)
+        if(noEntityRenderFrames > 0)
         {
-            renderEntitiesStartupCounter--;
+            noEntityRenderFrames--;
             return;
         }
-        TileEntityRenderDispatcher.instance.cacheActiveRenderInfo(worldObj, camera, partialTick);
-        EntityRenderDispatcher.instance.cacheActiveRenderInfo(worldObj, camera, partialTick);
-        countEntitiesTotal = 0;
-        countEntitiesRendered = 0;
-        countEntitiesHidden = 0;
+        TileEntityRenderDispatcher.instance.cacheActiveRenderInfo(world, camera, partialTick);
+        EntityRenderDispatcher.instance.cacheActiveRenderInfo(world, camera, partialTick);
+        totalEntities = 0;
+        renderedEntities = 0;
+        culledEntities = 0;
         EntityRenderDispatcher.renderPosX = camera.getX(partialTick);
         EntityRenderDispatcher.renderPosY = camera.getY(partialTick);
         EntityRenderDispatcher.renderPosZ = camera.getZ(partialTick);
         TileEntityRenderDispatcher.renderPosX = camera.getX(partialTick);
         TileEntityRenderDispatcher.renderPosY = camera.getY(partialTick);
         TileEntityRenderDispatcher.renderPosZ = camera.getZ(partialTick);
-        List<Entity> loadedEntities = worldObj.getLoadedEntityList();
-        countEntitiesTotal = loadedEntities.size();
+        List<Entity> loadedEntities = world.getLoadedEntityList();
+        totalEntities = loadedEntities.size();
         Tessellator tessellator = Tessellator.instance;
         // Render weather effects
-        for (int i = 0; i < worldObj.weatherEffects.size(); i++)
+        for (int i = 0; i < world.weatherEffects.size(); i++)
         {
-            Entity entity = worldObj.weatherEffects.get(i);
-            countEntitiesRendered++;
+            Entity entity = world.weatherEffects.get(i);
+            renderedEntities++;
             if(entity.shouldRender(camera.getPosition(partialTick), 1) || mc.thePlayer.vehicle == entity)
             {
                 EntityRenderDispatcher.instance.renderEntity(tessellator, entity, partialTick);
@@ -505,100 +501,110 @@ public class RenderGlobal
             {
                 floorY = 0;
             }
-            if(floorY >= worldObj.getHeightBlocks())
+            if(floorY >= world.getHeightBlocks())
             {
-                floorY = worldObj.getHeightBlocks() - 1;
+                floorY = world.getHeightBlocks() - 1;
 
             }
-            if (worldObj.isBlockLoaded(MathHelper.floor(entity.x), floorY, MathHelper.floor(entity.z)) || mc.thePlayer.vehicle == entity)
+            if (world.isBlockLoaded(MathHelper.floor(entity.x), floorY, MathHelper.floor(entity.z)) || mc.thePlayer.vehicle == entity)
             {
-                countEntitiesRendered++;
+                renderedEntities++;
                 EntityRenderDispatcher.instance.renderEntity(tessellator, entity, partialTick);
             }
         }
 
-        for (int i = 0, tileEntitiesSize = tileEntities.size(); i < tileEntitiesSize; i++) {
-            TileEntity tileEntity = tileEntities.get(i);
+        for (int i = 0, tileEntitiesSize = renderableTileEntities.size(); i < tileEntitiesSize; i++) {
+            TileEntity tileEntity = renderableTileEntities.get(i);
             TileEntityRenderDispatcher.instance.renderTileEntity(tessellator, camera, tileEntity, partialTick);
         }
     }
 
     public String getRendererDebugInfo()
     {
-        return "C: " + renderersBeingRendered + "/" + renderersLoaded + ". F: " + renderersBeingClipped + ", O: " + renderersBeingOccluded + ", E: " + renderersSkippingRenderPass;
+        return "C: " + renderedChunks + "/" + totalChunks + ". F: " + offscreenChunks + ", O: " + occludedChunks + ", E: " + emptyChunks;
     }
 
     public String getEntityDebugInfo()
     {
-        return "E: " + countEntitiesRendered + "/" + countEntitiesTotal + ". B: " + countEntitiesHidden + ", I: " + (countEntitiesTotal - countEntitiesHidden - countEntitiesRendered);
+        return "E: " + renderedEntities + "/" + totalEntities + ". B: " + culledEntities + ", I: " + (totalEntities - culledEntities - renderedEntities);
     }
 
-    public void markRenderersForNewPosition(int x, int y, int z)
+    public void resortChunks(int xc, int yc, int zc)
     {
-        x -= 8;
-//        y -= 8;
-        z -= 8;
-        minBlockX = Integer.MAX_VALUE;
-        minBlockY = Integer.MAX_VALUE;
-        minBlockZ = Integer.MAX_VALUE;
-        maxBlockX = Integer.MIN_VALUE;
-        maxBlockY = Integer.MIN_VALUE;
-        maxBlockZ = Integer.MIN_VALUE;
-        int l = renderChunksWide * RENDER_CHUNK_SIZE;
-        int i1 = l / 2;
-        for(int j1 = 0; j1 < renderChunksWide; j1++)
+        xc -= 8;
+//        yc -= 8;
+        zc -= 8;
+
+        xMinChunk = Integer.MAX_VALUE;
+        yMinChunk = Integer.MAX_VALUE;
+        zMinChunk = Integer.MAX_VALUE;
+        xMaxChunk = Integer.MIN_VALUE;
+        yMaxChunk = Integer.MIN_VALUE;
+        zMaxChunk = Integer.MIN_VALUE;
+
+        int s2 = xChunks * RENDER_CHUNK_SIZE;
+        int s1 = s2 / 2;
+
+        for(int x = 0; x < xChunks; x++)
         {
-            int k1 = j1 * RENDER_CHUNK_SIZE;
-            int l1 = (k1 + i1) - x;
-            if(l1 < 0)
+            int xx = x * RENDER_CHUNK_SIZE;
+            int xOff = (xx + s1) - xc;
+            if(xOff < 0)
             {
-                l1 -= l - 1;
+                xOff -= s2 - 1;
             }
-            l1 /= l;
-            k1 -= l1 * l;
-            if(k1 < minBlockX)
+
+            xOff /= s2;
+            xx -= xOff * s2;
+            if(xx < xMinChunk)
             {
-                minBlockX = k1;
+                xMinChunk = xx;
             }
-            if(k1 > maxBlockX)
+
+            if(xx > xMaxChunk)
             {
-                maxBlockX = k1;
+                xMaxChunk = xx;
             }
-            for(int i2 = 0; i2 < renderChunksDeep; i2++)
+
+            for(int z = 0; z < zChunks; z++)
             {
-                int j2 = i2 * RENDER_CHUNK_SIZE;
-                int k2 = (j2 + i1) - z;
-                if(k2 < 0)
+                int zz = z * RENDER_CHUNK_SIZE;
+                int zOff = (zz + s1) - zc;
+                if(zOff < 0)
                 {
-                    k2 -= l - 1;
+                    zOff -= s2 - 1;
                 }
-                k2 /= l;
-                j2 -= k2 * l;
-                if(j2 < minBlockZ)
+
+                zOff /= s2;
+                zz -= zOff * s2;
+                if(zz < zMinChunk)
                 {
-                    minBlockZ = j2;
+                    zMinChunk = zz;
                 }
-                if(j2 > maxBlockZ)
+
+                if(zz > zMaxChunk)
                 {
-                    maxBlockZ = j2;
+                    zMaxChunk = zz;
                 }
-                for(int l2 = 0; l2 < renderChunksTall; l2++)
+
+                for(int y = 0; y < yChunks; y++)
                 {
-                    int i3 = l2 * RENDER_CHUNK_SIZE;
-                    if(i3 < minBlockY)
+                    int yy = y * RENDER_CHUNK_SIZE;
+                    if(yy < yMinChunk)
                     {
-                        minBlockY = i3;
+                        yMinChunk = yy;
                     }
-                    if(i3 > maxBlockY)
+                    if(yy > yMaxChunk)
                     {
-                        maxBlockY = i3;
+                        yMaxChunk = yy;
                     }
-                    ChunkRenderer worldrenderer = chunkRenderers[(i2 * renderChunksTall + l2) * renderChunksWide + j1];
-                    boolean flag = worldrenderer.dirty;
-                    worldrenderer.setPos(k1, i3, j2);
-                    if(!flag && worldrenderer.dirty)
+
+                    ChunkRenderer renderer = chunkRenderers[(z * yChunks + y) * xChunks + x];
+                    boolean wasDirty = renderer.dirty;
+                    renderer.setPos(xx, yy, zz);
+                    if(!wasDirty && renderer.dirty)
                     {
-                        chunkRenderersToUpdate.add(worldrenderer);
+                        dirtyChunks.add(renderer);
                     }
                 }
 
@@ -607,65 +613,68 @@ public class RenderGlobal
         }
 
     }
-    public int sortAndRender(ICamera camera, int renderPass, double partialTick)
+    public int render(ICamera camera, int renderPass, double partialTick)
     {
         // Find which renderers need updating
         for(int i = 0; i < 10; i++)
         {
-            worldRenderersCheckIndex = (worldRenderersCheckIndex + 1) % chunkRenderers.length;
-            ChunkRenderer chunkRenderer = chunkRenderers[worldRenderersCheckIndex];
-            if(chunkRenderer.dirty && !chunkRenderersToUpdate.contains(chunkRenderer))
+            chunkFixOffs = (chunkFixOffs + 1) % chunkRenderers.length;
+            ChunkRenderer chunkRenderer = chunkRenderers[chunkFixOffs];
+            if(chunkRenderer.dirty && !dirtyChunks.contains(chunkRenderer))
             {
-                chunkRenderersToUpdate.add(chunkRenderer);
+                dirtyChunks.add(chunkRenderer);
             }
         }
 
         if(mc.gameSettings.renderDistance.value != renderDistance)
         {
-            loadRenderers();
+            allChanged();
         }
+
         if(renderPass == 0)
         {
-            renderersLoaded = 0;
-            renderersBeingClipped = 0;
-            renderersBeingOccluded = 0;
-            renderersBeingRendered = 0;
-            renderersSkippingRenderPass = 0;
+            totalChunks = 0;
+            offscreenChunks = 0;
+            occludedChunks = 0;
+            renderedChunks = 0;
+            emptyChunks = 0;
         }
-        double entityPosX = camera.getX((float) partialTick);
-        double entityPosY = camera.getY((float) partialTick);
-        double entityPosZ = camera.getZ((float) partialTick);
-        double dPosX = camera.getX() - prevSortX;
-        double dPosY = camera.getY() - prevSortY;
-        double dPosZ = camera.getZ() - prevSortZ;
-        if(dPosX * dPosX + dPosY * dPosY + dPosZ * dPosZ > RENDER_CHUNK_SIZE)
+
+        double xOff = camera.getX((float) partialTick);
+        double yOff = camera.getY((float) partialTick);
+        double zOff = camera.getZ((float) partialTick);
+        double xd = camera.getX() - xOld;
+        double yd = camera.getY() - yOld;
+        double zd = camera.getZ() - zOld;
+        if(xd * xd + yd * yd + zd * zd > RENDER_CHUNK_SIZE)
         {
-            prevSortX = camera.getX();
-            prevSortY = camera.getY();
-            prevSortZ = camera.getZ();
-            markRenderersForNewPosition(MathHelper.floor(camera.getX()), MathHelper.floor(camera.getY()), MathHelper.floor(camera.getZ()));
+            xOld = camera.getX();
+            yOld = camera.getY();
+            zOld = camera.getZ();
+            resortChunks(MathHelper.floor(camera.getX()), MathHelper.floor(camera.getY()), MathHelper.floor(camera.getZ()));
             Arrays.sort(sortedChunkRenderers, new CameraSorter(camera));
         }
+
         Lighting.disable();
-        int k = 0;
-        if(occlusionEnabled && mc.gameSettings.advancedOpenGL.value && renderPass == 0)
+        int count = 0;
+        if(occlusionCheck && mc.gameSettings.advancedOpenGL.value && renderPass == 0)
         {
-            int min = 0;
-            int max = RENDER_CHUNK_SIZE;
-            checkOcclusionQueryResult(min, max);
-            for(int i = min; i < max; i++)
+            int from = 0;
+            int to = RENDER_CHUNK_SIZE;
+            checkQueryResults(from, to);
+            for(int i = from; i < to; i++)
             {
                 sortedChunkRenderers[i].occlusionVisible = true;
             }
 
-            k += renderSortedRenderers(min, max, renderPass, partialTick);
+            count += renderChunks(from, to, renderPass, partialTick);
             do
             {
-                int byte0 = max;
-                max *= 2;
-                if(max > sortedChunkRenderers.length)
+                from = to;
+                to *= 2;
+                if(to > sortedChunkRenderers.length)
                 {
-                    max = sortedChunkRenderers.length;
+                    to = sortedChunkRenderers.length;
                 }
                 GL11.glDisable(GL11.GL_TEXTURE_2D);
                 GL11.glDisable(GL11.GL_LIGHTING);
@@ -673,50 +682,50 @@ public class RenderGlobal
                 GL11.glDisable(GL11.GL_FOG);
                 GL11.glColorMask(false, false, false, false);
                 GL11.glDepthMask(false);
-                checkOcclusionQueryResult(byte0, max);
+                checkQueryResults(from, to);
                 GL11.glPushMatrix();
-                float f = 0.0F;
-                float f1 = 0.0F;
-                float f2 = 0.0F;
-                for(int k1 = byte0; k1 < max; k1++)
+                float xo = 0.0F;
+                float yo = 0.0F;
+                float zo = 0.0F;
+                for(int ix = from; ix < to; ix++)
                 {
-                    if(sortedChunkRenderers[k1].isEmpty())
+                    if(sortedChunkRenderers[ix].isEmpty())
                     {
-                        sortedChunkRenderers[k1].visible = false;
+                        sortedChunkRenderers[ix].visible = false;
                         continue;
                     }
-                    if(!sortedChunkRenderers[k1].visible)
+                    if(!sortedChunkRenderers[ix].visible)
                     {
-                        sortedChunkRenderers[k1].occlusionVisible = true;
+                        sortedChunkRenderers[ix].occlusionVisible = true;
                     }
-                    if(!sortedChunkRenderers[k1].visible || sortedChunkRenderers[k1].occlusionQuerying)
+                    if(!sortedChunkRenderers[ix].visible || sortedChunkRenderers[ix].occlusionQuerying)
                     {
                         continue;
                     }
-                    float f3 = MathHelper.sqrt_float(sortedChunkRenderers[k1].distanceToCameraSquared(camera));
-                    int l1 = (int)(1.0F + f3 / 128F);
-                    if(cloudOffsetX % l1 != k1 % l1)
+                    float dist = MathHelper.sqrt_float(sortedChunkRenderers[ix].distanceToCameraSquared(camera));
+                    int frequency = (int)(1.0F + dist / 128F);
+                    if(ticks % frequency != ix % frequency)
                     {
                         continue;
                     }
-                    ChunkRenderer worldrenderer1 = sortedChunkRenderers[k1];
-                    float f4 = (float)((double)worldrenderer1.xRender - entityPosX);
-                    float f5 = (float)((double)worldrenderer1.yRender - entityPosY);
-                    float f6 = (float)((double)worldrenderer1.zRender - entityPosZ);
-                    float f7 = f4 - f;
-                    float f8 = f5 - f1;
-                    float f9 = f6 - f2;
-                    if(f7 != 0.0F || f8 != 0.0F || f9 != 0.0F)
+                    ChunkRenderer chunkRenderer = sortedChunkRenderers[ix];
+                    float xt = (float)((double)chunkRenderer.xRender - xOff);
+                    float yt = (float)((double)chunkRenderer.yRender - yOff);
+                    float zt = (float)((double)chunkRenderer.zRender - zOff);
+                    float xdd = xt - xo;
+                    float ydd = yt - yo;
+                    float zdd = zt - zo;
+                    if(xdd != 0.0F || ydd != 0.0F || zdd != 0.0F)
                     {
-                        GL11.glTranslatef(f7, f8, f9);
-                        f += f7;
-                        f1 += f8;
-                        f2 += f9;
+                        GL11.glTranslatef(xdd, ydd, zdd);
+                        xo += xdd;
+                        yo += ydd;
+                        zo += zdd;
                     }
-                    ARBOcclusionQuery.glBeginQueryARB(35092 /*GL_SAMPLES_PASSED_ARB*/, sortedChunkRenderers[k1].occlusionId);
-                    sortedChunkRenderers[k1].renderBB();
-                    ARBOcclusionQuery.glEndQueryARB(35092 /*GL_SAMPLES_PASSED_ARB*/);
-                    sortedChunkRenderers[k1].occlusionQuerying = true;
+                    ARBOcclusionQuery.glBeginQueryARB(GL15.GL_SAMPLES_PASSED, sortedChunkRenderers[ix].occlusionId);
+                    sortedChunkRenderers[ix].renderBB();
+                    ARBOcclusionQuery.glEndQueryARB(GL15.GL_SAMPLES_PASSED);
+                    sortedChunkRenderers[ix].occlusionQuerying = true;
                 }
 
                 GL11.glPopMatrix();
@@ -725,127 +734,129 @@ public class RenderGlobal
                 GL11.glEnable(GL11.GL_TEXTURE_2D);
                 GL11.glEnable(GL11.GL_ALPHA_TEST);
                 GL11.glEnable(GL11.GL_FOG);
-                k += renderSortedRenderers(byte0, max, renderPass, partialTick);
-            } while(max < sortedChunkRenderers.length);
+                count += renderChunks(from, to, renderPass, partialTick);
+            } while(to < sortedChunkRenderers.length);
         }
         else
         {
-            k += renderSortedRenderers(0, sortedChunkRenderers.length, renderPass, partialTick);
+            count += renderChunks(0, sortedChunkRenderers.length, renderPass, partialTick);
         }
-        return k;
+        return count;
     }
 
-    private void checkOcclusionQueryResult(int min, int max)
+    private void checkQueryResults(int from, int to)
     {
-        for(int i = min; i < max; i++)
+        for(int i = from; i < to; i++)
         {
             if(!sortedChunkRenderers[i].occlusionQuerying)
             {
                 continue;
             }
-            occlusionResult.clear();
-            ARBOcclusionQuery.glGetQueryObjectuivARB(sortedChunkRenderers[i].occlusionId, GL15.GL_QUERY_RESULT_AVAILABLE, occlusionResult);
-            if(occlusionResult.get(0) != 0)
+            resultBuffer.clear();
+            ARBOcclusionQuery.glGetQueryObjectuivARB(sortedChunkRenderers[i].occlusionId, GL15.GL_QUERY_RESULT_AVAILABLE, resultBuffer);
+            if(resultBuffer.get(0) != 0)
             {
                 sortedChunkRenderers[i].occlusionQuerying = false;
-                occlusionResult.clear();
-                ARBOcclusionQuery.glGetQueryObjectuivARB(sortedChunkRenderers[i].occlusionId, GL15.GL_QUERY_RESULT, occlusionResult);
-                sortedChunkRenderers[i].occlusionVisible = occlusionResult.get(0) != 0;
+                resultBuffer.clear();
+                ARBOcclusionQuery.glGetQueryObjectuivARB(sortedChunkRenderers[i].occlusionId, GL15.GL_QUERY_RESULT, resultBuffer);
+                sortedChunkRenderers[i].occlusionVisible = resultBuffer.get(0) != 0;
             }
         }
 
     }
 
-    private int renderSortedRenderers(int min, int max, int renderPass, double partialTick)
+    private int renderChunks(int from, int to, int renderPass, double partialTick)
     {
-        glRenderLists.clear();
-        int addedWorldRenderers = 0;
-        for(int i = min; i < max; i++)
+        renderChunks.clear();
+        int count = 0;
+
+        for(int i = from; i < to; i++)
         {
             if(renderPass == 0)
             {
-                renderersLoaded++;
+                totalChunks++;
                 if(sortedChunkRenderers[i].empty[renderPass])
                 {
-                    renderersSkippingRenderPass++;
+                    emptyChunks++;
                 }
                 else if (!sortedChunkRenderers[i].visible)
                 {
-                    renderersBeingClipped++;
+                    offscreenChunks++;
                 }
-                else if (occlusionEnabled && !sortedChunkRenderers[i].occlusionVisible)
+                else if (occlusionCheck && !sortedChunkRenderers[i].occlusionVisible)
                 {
-                    renderersBeingOccluded++;
+                    occludedChunks++;
                 } else
                 {
-                    renderersBeingRendered++;
+                    renderedChunks++;
                 }
             }
-            if(sortedChunkRenderers[i].empty[renderPass] || !sortedChunkRenderers[i].visible || occlusionEnabled && !sortedChunkRenderers[i].occlusionVisible)
+
+            if(sortedChunkRenderers[i].empty[renderPass] || !sortedChunkRenderers[i].visible || occlusionCheck && !sortedChunkRenderers[i].occlusionVisible)
             {
                 continue;
             }
-            int callList = sortedChunkRenderers[i].getList(renderPass);
-            if(callList >= 0)
+            int list = sortedChunkRenderers[i].getList(renderPass);
+            if(list >= 0)
             {
-                glRenderLists.add(sortedChunkRenderers[i]);
-                addedWorldRenderers++;
+                renderChunks.add(sortedChunkRenderers[i]);
+                count++;
             }
         }
 
-        double posX = mc.activeCamera.getX((float) partialTick);
-        double posY = mc.activeCamera.getY((float) partialTick);
-        double posZ = mc.activeCamera.getZ((float) partialTick);
-        int k1 = 0;
-        for (DisplayList displayList : allDisplayLists)
+        double xOff = mc.activeCamera.getX((float) partialTick);
+        double yOff = mc.activeCamera.getY((float) partialTick);
+        double zOff = mc.activeCamera.getZ((float) partialTick);
+        int lists = 0;
+        for (DisplayList displayList : renderLists)
         {
             displayList.clear();
         }
 
-        for (ChunkRenderer chunkRenderer : glRenderLists)
+        for (ChunkRenderer renderer : renderChunks)
         {
-            int displayListIndex = -1;
-            for (int i = 0; i < k1; i++)
+            int list = -1;
+            for (int i = 0; i < lists; i++)
             {
-                if (allDisplayLists[i].isSetToPos(chunkRenderer.xRender, chunkRenderer.yRender, chunkRenderer.zRender))
+                if (renderLists[i].isSetToPos(renderer.xRender, renderer.yRender, renderer.zRender))
                 {
-                    displayListIndex = i;
+                    list = i;
                 }
             }
 
-            if (displayListIndex < 0)
+            if (list < 0)
             {
-                displayListIndex = k1++;
-                allDisplayLists[displayListIndex].setToPos(chunkRenderer.xRender, chunkRenderer.yRender, chunkRenderer.zRender, posX, posY, posZ);
+                list = lists++;
+                renderLists[list].setToPos(renderer.xRender, renderer.yRender, renderer.zRender, xOff, yOff, zOff);
             }
-            allDisplayLists[displayListIndex].addCallToList(chunkRenderer.getList(renderPass));
+            renderLists[list].addCallToList(renderer.getList(renderPass));
         }
 
         if (!mc.gameSettings.fog.value)
         {
             GL11.glDisable(GL11.GL_FOG);
         }
-        callAllDisplayLists(renderPass, partialTick);
+        renderSameAsLast(renderPass, partialTick);
         if (!mc.gameSettings.fog.value)
         {
             GL11.glEnable(GL11.GL_FOG);
         }
-        return addedWorldRenderers;
+        return count;
     }
 
-    public void callAllDisplayLists(int renderPass, double partialTick)
+    public void renderSameAsLast(int renderPass, double partialTick)
     {
-        for (DisplayList displayList : allDisplayLists)
+        for (DisplayList displayList : renderLists)
         {
             displayList.call();
         }
 
     }
 
-    public void updateClouds()
+    public void tick()
     {
-        float windDirection = worldObj.worldType.getWindManager().getWindDirection(worldObj, 0.0f, 500f, 0.0f);
-        float windIntensity = worldObj.worldType.getWindManager().getWindIntensity(worldObj, 0.0f, 500f, 0.0f);
+        float windDirection = world.worldType.getWindManager().getWindDirection(world, 0.0f, 500f, 0.0f);
+        float windIntensity = world.worldType.getWindManager().getWindIntensity(world, 0.0f, 500f, 0.0f);
 
         float dx = -(float) (Math.cos(windDirection * Math.PI * 2) * windIntensity);
         float dz = -(float) (Math.sin(windDirection * Math.PI * 2) * windIntensity);
@@ -863,18 +874,20 @@ public class RenderGlobal
         lastCloudOffsetZ = cloudOffsetZ;
         cloudOffsetX += cloudVelocityX;
         cloudOffsetZ += cloudVelocityZ;
+
+        ticks++;
     }
 
-    public void drawSky(float partialTick)
+    public void renderSky(float partialTick)
     {
         WorldTypeFX worldTypeFX = WorldTypeFXDispatcher.getInstance().getDispatch(mc.currentWorld.getWorldType());
         if(!worldTypeFX.hasSky() || mc.currentScreen instanceof ScreenModelViewer)
         {
             return;
         }
-        float celestialAngle = worldObj.getCelestialAngle(partialTick);
+        float celestialAngle = world.getCelestialAngle(partialTick);
         GL11.glDisable(GL_TEXTURE_2D);
-        Vec3 skyColor = worldObj.getSkyColor(mc.activeCamera, partialTick);
+        Vec3 skyColor = world.getSkyColor(mc.activeCamera, partialTick);
         float r = (float)skyColor.x;
         float g = (float)skyColor.y;
         float b = (float)skyColor.z;
@@ -883,7 +896,7 @@ public class RenderGlobal
         GL11.glDepthMask(false);
         GL11.glEnable(GL_FOG);
         GL11.glColor3f(r, g, b);
-        GL11.glCallList(glSkyList);
+        GL11.glCallList(skyList);
         GL11.glDisable(GL_FOG);
         GL11.glDisable(GL_ALPHA_TEST);
         GL11.glEnable(GL_BLEND);
@@ -921,7 +934,7 @@ public class RenderGlobal
         GL11.glEnable(GL_TEXTURE_2D);
         GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE);
         GL11.glPushMatrix();
-        float sunAlpha = 1.0F - (worldObj.getCurrentWeather() != null && worldObj.getCurrentWeather() != Weathers.OVERWORLD_CLEAR ? (worldObj.weatherManager.getWeatherIntensity() * worldObj.weatherManager.getWeatherPower()) * 1.5f : 0.0f);
+        float sunAlpha = 1.0F - (world.getCurrentWeather() != null && world.getCurrentWeather() != Weathers.OVERWORLD_CLEAR ? (world.weatherManager.getWeatherIntensity() * world.weatherManager.getWeatherPower()) * 1.5f : 0.0f);
 
         float x = 0.0F;
         float y = 0.0F;
@@ -943,10 +956,10 @@ public class RenderGlobal
         t.draw();
 
         // Render Rainbow
-        if (worldObj.rainbowTicks > 0 || (!Double.isNaN(rainbowBrightness) && rainbowBrightness > 0)){
+        if (world.rainbowTicks > 0 || (!Double.isNaN(rainbowBrightness) && rainbowBrightness > 0)){
             // Calculates the progress through the rainbow, with peak brightness halfway through its lifespawn
-            final float halfRainbowLength = (worldObj.startingRainbowTicks/2f);
-            float rainbowTimeScalar = 1 - (Math.abs((worldObj.rainbowTicks + partialTick) - halfRainbowLength) / halfRainbowLength);
+            final float halfRainbowLength = (world.startingRainbowTicks/2f);
+            float rainbowTimeScalar = 1 - (Math.abs((world.rainbowTicks + partialTick) - halfRainbowLength) / halfRainbowLength);
 
             // Calculates the potential max rainbow brightness based on time of day
             float timeScalar;
@@ -966,10 +979,10 @@ public class RenderGlobal
             timeScalar *= cutoff;
             timeScalar *= rainbowTimeScalar;
 
-            Weather[] blocked = worldObj.getBlockBiome(MathHelper.floor(mc.thePlayer.x), MathHelper.floor(mc.thePlayer.y), MathHelper.floor(mc.thePlayer.z)).blockedWeathers;
+            Weather[] blocked = world.getBlockBiome(MathHelper.floor(mc.thePlayer.x), MathHelper.floor(mc.thePlayer.y), MathHelper.floor(mc.thePlayer.z)).blockedWeathers;
             boolean isWeatherBlocked = false;
             for (Weather w : blocked){
-                if (w.equals(worldObj.weatherManager.getLastWeather())) {
+                if (w.equals(world.weatherManager.getLastWeather())) {
                     isWeatherBlocked = true;
                     break;
                 }
@@ -1024,12 +1037,12 @@ public class RenderGlobal
         t.addVertexWithUV(-size, -100D, -size, 1.0D, 0.0D);
         t.draw();
 
-        float f17 = worldObj.getStarBrightness(partialTick) * sunAlpha;
+        float f17 = world.getStarBrightness(partialTick) * sunAlpha;
         if(f17 > 0.0F)
         {
             textureManager.loadTexture("/assets/minecraft/textures/colormap/stars/default.png").bind();
             GL11.glColor4f(f17, f17, f17, f17);
-            GL11.glCallList(starGLCallList);
+            GL11.glCallList(starList);
         }
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
         GL11.glDisable(GL11.GL_TEXTURE_2D);
@@ -1076,7 +1089,7 @@ public class RenderGlobal
         textureManager.loadTexture("/assets/minecraft/textures/environment/clouds.png").bind();
         GL11.glEnable(GL11.GL_BLEND);
         GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
-        Vec3 dimensionColor = worldObj.getDimensionColor(mc.activeCamera, partialTick);
+        Vec3 dimensionColor = world.getDimensionColor(mc.activeCamera, partialTick);
         float r = (float)dimensionColor.x;
         float g = (float)dimensionColor.y;
         float b = (float)dimensionColor.z;
@@ -1115,7 +1128,7 @@ public class RenderGlobal
         WorldTypeFX worldTypeFX = WorldTypeFXDispatcher.getInstance().getDispatch(mc.currentWorld.getWorldType());
     	mc.renderer.beginRenderClouds(partialTick);
     	
-        float celestialAngle = worldObj.getCelestialAngle(partialTick);
+        float celestialAngle = world.getCelestialAngle(partialTick);
         float[] sunriseColor = worldTypeFX.getSunriseColor(celestialAngle, partialTick);
         float rSun = 0.0f, gSun = 0.0f, bSun = 0.0f, aSun = 0.0f;
         if (sunriseColor != null) {
@@ -1125,7 +1138,7 @@ public class RenderGlobal
             aSun = sunriseColor[3] / 2;
         }
 
-        Vec3 dimensionColor = worldObj.getDimensionColor(mc.activeCamera, partialTick);
+        Vec3 dimensionColor = world.getDimensionColor(mc.activeCamera, partialTick);
         final float rDim = (float)dimensionColor.x;
         final float gDim = (float)dimensionColor.y;
         final float bDim = (float)dimensionColor.z;
@@ -1261,81 +1274,88 @@ public class RenderGlobal
     	mc.renderer.endRenderClouds(partialTick);
     }
 
-    public boolean updateRenderers(ICamera camera) {
-        final byte numLayers = 2;
-        final ChunkRendererComparator comparator = new ChunkRendererComparator(camera);
-        final ChunkRenderer[] chunkRenderers = new ChunkRenderer[numLayers];
-        List<ChunkRenderer> rendererList = null;
-        final int numChunkRenderersToUpdate = chunkRenderersToUpdate.size();
-        int renderListSize = 0;
-        for(int i = 0; i < numChunkRenderersToUpdate; i++) {
-            final ChunkRenderer chunkRenderer = chunkRenderersToUpdate.get(i);
-            if(chunkRenderer.distanceToCameraSquared(camera) > 256F) {
-                int layer = 0;
-                while (layer < numLayers && (chunkRenderers[layer] == null || comparator.compare(chunkRenderers[layer], chunkRenderer) <= 0)) {
-                    layer++;
+    public boolean updateDirtyChunks(ICamera camera) {
+        final DirtyChunkRendererSorter dirtyChunkRendererSorter = new DirtyChunkRendererSorter(camera);
+        final ChunkRenderer[] toAdd = new ChunkRenderer[MAX_VISIBLE_REBUILDS_PER_FRAME];
+        List<ChunkRenderer> nearChunks = null;
+
+        final int pendingChunkSize = dirtyChunks.size();
+        int pendingChunkRemoved = 0;
+
+        for(int i = 0; i < pendingChunkSize; i++) {
+            final ChunkRenderer renderer = dirtyChunks.get(i);
+            if(renderer.distanceToCameraSquared(camera) > 1024.0f) {
+                int index = 0;
+
+                while (index < MAX_VISIBLE_REBUILDS_PER_FRAME && (toAdd[index] == null || dirtyChunkRendererSorter.compare(toAdd[index], renderer) <= 0)) {
+                    index++;
                 }
-                if(--layer <= 0) {
+
+                if(--index <= 0) {
                     continue;
                 }
-                for(int i3 = layer; --i3 != 0;) {
-                    chunkRenderers[i3 - 1] = chunkRenderers[i3];
+
+                for(int x = index; --x != 0;) {
+                    toAdd[x - 1] = toAdd[x];
                 }
 
-                chunkRenderers[layer] = chunkRenderer;
+                toAdd[index] = renderer;
                 continue;
             }
-            if(rendererList == null) {
-                rendererList = new ArrayList<>();
+
+            if(nearChunks == null) {
+                nearChunks = new ArrayList<>();
             }
-            renderListSize++;
-            rendererList.add(chunkRenderer);
-            chunkRenderersToUpdate.set(i, null);
+
+            pendingChunkRemoved++;
+            nearChunks.add(renderer);
+            dirtyChunks.set(i, null);
         }
 
-        if(rendererList != null) {
-            if(rendererList.size() > 1) {
-                rendererList.sort(comparator);
+        if(nearChunks != null) {
+            if(nearChunks.size() > 1) {
+                nearChunks.sort(dirtyChunkRendererSorter);
             }
-            for (ChunkRenderer renderer : rendererList){
+            for (ChunkRenderer renderer : nearChunks){
                 renderer.rebuild();
                 renderer.dirty = false;
             }
         }
-        int renderersUpdated = 0;
-        for(int layer = numLayers - 1; layer >= 0; layer--) {
-            ChunkRenderer renderer = chunkRenderers[layer];
-            if(renderer == null) { continue; }
-            if(!renderer.visible && layer != numLayers - 1) {
-                chunkRenderers[layer] = null;
+
+        int secondaryRemoved = 0;
+        for(int i = MAX_VISIBLE_REBUILDS_PER_FRAME - 1; i >= 0; i--) {
+            ChunkRenderer chunkx = toAdd[i];
+            if(chunkx == null) { continue; }
+            if(!chunkx.visible && i != MAX_VISIBLE_REBUILDS_PER_FRAME - 1) {
+                toAdd[i] = null;
                 break;
             }
-            renderer.rebuild();
-            renderer.dirty = false;
-            renderersUpdated++;
+            chunkx.rebuild();
+            chunkx.dirty = false;
+            secondaryRemoved++;
         }
 
-        int renderIndex = 0;
-        int setRenders = 0;
-        label1: for (int size = chunkRenderersToUpdate.size(); renderIndex != size; renderIndex++) {
-            final ChunkRenderer renderer = chunkRenderersToUpdate.get(renderIndex);
+        int cursor = 0;
+        int target = 0;
+        outer: for (int size = dirtyChunks.size(); cursor != size; cursor++) {
+            final ChunkRenderer renderer = dirtyChunks.get(cursor);
             if(renderer == null) { continue; }
-            for(int layer = 0; layer < numLayers; layer++) {
-                if (renderer == chunkRenderers[layer]) {
-                    continue label1;
+            for(int i = 0; i < MAX_VISIBLE_REBUILDS_PER_FRAME; i++) {
+                if (renderer == toAdd[i]) {
+                    continue outer;
                 }
             }
 
-            if(setRenders != renderIndex) {
-                chunkRenderersToUpdate.set(setRenders, renderer);
+            if(target != cursor) {
+                dirtyChunks.set(target, renderer);
             }
-            setRenders++;
+            target++;
         }
 
-        while(--renderIndex >= setRenders) {
-            chunkRenderersToUpdate.remove(renderIndex);
+        while(--cursor >= target) {
+            dirtyChunks.remove(cursor);
         }
-        return numChunkRenderersToUpdate == (renderListSize + renderersUpdated);
+        return pendingChunkSize == (pendingChunkRemoved + secondaryRemoved);
     }
 
     public void drawBlockBreaking(ICamera camera, HitResult hitResult, float partialTick)
@@ -1345,13 +1365,13 @@ public class RenderGlobal
         GL11.glEnable(GL11.GL_ALPHA_TEST);
         GL11.glBlendFunc(770, 1);
         GL11.glColor4f(1.0F, 1.0F, 1.0F, (MathHelper.sin((float)System.currentTimeMillis() / 100F) * 0.2F + 0.4F) * 0.5F);
-        if(damagePartialTime > 0.0F)
+        if(destroyProgress > 0.0F)
         {
             GL11.glBlendFunc(774, 768);
             TextureRegistry.blockAtlas.bind();
             GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.5F);
             GL11.glPushMatrix();
-            int k = worldObj.getBlockId(hitResult.x, hitResult.y, hitResult.z);
+            int k = world.getBlockId(hitResult.x, hitResult.y, hitResult.z);
             Block<?> block = k <= 0 ? null : Blocks.blocksList[k];
             GL11.glDisable(GL11.GL_ALPHA_TEST);
             GL11.glPolygonOffset(-3F, -3F);
@@ -1375,11 +1395,11 @@ public class RenderGlobal
                 .getDispatch(block)
                 .renderWithOverrideTexture(
                     tessellator,
-                    worldObj,
+                    world,
                     hitResult.x,
                     hitResult.y,
                     hitResult.z,
-                    breakingAnimation[MathHelper.clamp((int)(damagePartialTime * 10F), 0, breakingAnimation.length - 1)]);
+                    breakingAnimation[MathHelper.clamp((int)(destroyProgress * 10F), 0, breakingAnimation.length - 1)]);
             tessellator.draw();
             tessellator.setTranslation(0.0D, 0.0D, 0.0D);
             GL11.glDisable(GL11.GL_ALPHA_TEST);
@@ -1411,17 +1431,17 @@ public class RenderGlobal
             if(hitResult.hitType == HitResult.HitType.TILE)
             {
                 float expand = 0.002F;
-                int j = worldObj.getBlockId(hitResult.x, hitResult.y, hitResult.z);
+                int j = world.getBlockId(hitResult.x, hitResult.y, hitResult.z);
                 if(j > 0)
                 {
-                    BoundingVolume volume = Blocks.blocksList[j].getBoundingVolume(worldObj, hitResult.x, hitResult.y, hitResult.z);
+                    BoundingVolume volume = Blocks.blocksList[j].getBoundingVolume(world, hitResult.x, hitResult.y, hitResult.z);
                     if (volume != null)
                     {
                         drawOutlinedVolume(volume, hitResult.x - offsetX, hitResult.y - offsetY, hitResult.z - offsetZ, expand);
                     }
                     else
                     {
-                        drawOutlinedBoundingBox(Blocks.blocksList[j].getSelectedBoundingBoxFromPool(worldObj, hitResult.x, hitResult.y, hitResult.z).grow(expand, expand, expand).cloneMove(-offsetX, -offsetY, -offsetZ));
+                        drawOutlinedBoundingBox(Blocks.blocksList[j].getSelectedBoundingBoxFromPool(world, hitResult.x, hitResult.y, hitResult.z).grow(expand, expand, expand).cloneMove(-offsetX, -offsetY, -offsetZ));
                     }
                 }
             }
@@ -1444,7 +1464,7 @@ public class RenderGlobal
 		double offsetY = camera.getY(partialTicks);
 		double offsetZ = camera.getZ(partialTicks);
 		float expand = 0.002F;
-		List<AABB> collidingBoundingBoxes = worldObj.getCubes(mc.thePlayer, mc.thePlayer.bb.grow(expand, expand, expand));
+		List<AABB> collidingBoundingBoxes = world.getCubes(mc.thePlayer, mc.thePlayer.bb.grow(expand, expand, expand));
         glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
 		for (AABB aabb : collidingBoundingBoxes) {
 			drawOutlinedBoundingBox(aabb.cloneMove(-offsetX, -offsetY, -offsetZ).grow(expand, expand, expand));
@@ -1454,7 +1474,7 @@ public class RenderGlobal
 		if(mc.thePlayer.getGamemode() == Gamemode.creative) {
 			entityRadius = 100.0f;
 		}
-		List<Entity> entitiesNearby = worldObj.getEntitiesWithinAABBExcludingEntity(null, mc.thePlayer.bb.grow(entityRadius, entityRadius, entityRadius));
+		List<Entity> entitiesNearby = world.getEntitiesWithinAABBExcludingEntity(null, mc.thePlayer.bb.grow(entityRadius, entityRadius, entityRadius));
         for (Entity e : entitiesNearby) {
             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
             drawInterpolatedEntityBoundingBox(e, e.bb, camera, partialTicks); // Bounds
@@ -1644,41 +1664,42 @@ public class RenderGlobal
         t.draw();
     }
 
-    public void markDirty(int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
+    public void setDirty(int x0, int y0, int z0, int x1, int y1, int z1)
     {
-        int wrMinX = MathHelper.bucketInt(minX, RENDER_CHUNK_SIZE);
-        int wrMinY = MathHelper.bucketInt(minY, RENDER_CHUNK_SIZE);
-        int wrMinZ = MathHelper.bucketInt(minZ, RENDER_CHUNK_SIZE);
-        int wrMaxX = MathHelper.bucketInt(maxX, RENDER_CHUNK_SIZE);
-        int wrMaxY = MathHelper.bucketInt(maxY, RENDER_CHUNK_SIZE);
-        int wrMaxZ = MathHelper.bucketInt(maxZ, RENDER_CHUNK_SIZE);
-        for(int wrX = wrMinX; wrX <= wrMaxX; wrX++)
+        int _x0 = MathHelper.bucketInt(x0, RENDER_CHUNK_SIZE);
+        int _y0 = MathHelper.bucketInt(y0, RENDER_CHUNK_SIZE);
+        int _z0 = MathHelper.bucketInt(z0, RENDER_CHUNK_SIZE);
+        int _x1 = MathHelper.bucketInt(x1, RENDER_CHUNK_SIZE);
+        int _y1 = MathHelper.bucketInt(y1, RENDER_CHUNK_SIZE);
+        int _z1 = MathHelper.bucketInt(z1, RENDER_CHUNK_SIZE);
+        for(int x = _x0; x <= _x1; x++)
         {
-            int realWrX = wrX % renderChunksWide;
-            if(realWrX < 0)
+            int xx = x % xChunks;
+            if(xx < 0)
             {
-                realWrX += renderChunksWide;
+                xx += xChunks;
             }
-            for(int wrY = wrMinY; wrY <= wrMaxY; wrY++)
+            for(int y = _y0; y <= _y1; y++)
             {
-                int realWrY = wrY % renderChunksTall;
-                if(realWrY < 0)
+                int yy = y % yChunks;
+                if(yy < 0)
                 {
-                    realWrY += renderChunksTall;
+                    yy += yChunks;
                 }
-                for(int wrZ = wrMinZ; wrZ <= wrMaxZ; wrZ++)
+                for(int z = _z0; z <= _z1; z++)
                 {
-                    int realWrZ = wrZ % renderChunksDeep;
-                    if(realWrZ < 0)
+                    int zz = z % zChunks;
+                    if(zz < 0)
                     {
-                        realWrZ += renderChunksDeep;
+                        zz += zChunks;
                     }
-                    int i = (realWrZ * renderChunksTall + realWrY) * renderChunksWide + realWrX;
-                    ChunkRenderer worldrenderer = chunkRenderers[i];
-                    if(!worldrenderer.dirty)
+                    int p = (zz * yChunks + yy) * xChunks + xx;
+
+                    ChunkRenderer renderer = chunkRenderers[p];
+                    if(!renderer.dirty)
                     {
-                        chunkRenderersToUpdate.add(worldrenderer);
-                        worldrenderer.setDirty();
+                        dirtyChunks.add(renderer);
+                        renderer.setDirty();
                     }
                 }
             }
@@ -1688,26 +1709,26 @@ public class RenderGlobal
     @Override
     public void blockChanged(int x, int y, int z)
     {
-        markDirty(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1);
+        setDirty(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1);
     }
 
     @Override
     public void setBlocksDirty(int x0, int y0, int z0, int x1, int y1, int z1)
     {
-        markDirty(x0 - 1, y0 - 1, z0 - 1, x1 + 1, y1 + 1, z1 + 1);
+        setDirty(x0 - 1, y0 - 1, z0 - 1, x1 + 1, y1 + 1, z1 + 1);
     }
 
-    public void clipRenderersByFrustum(CameraFrustum frustum, float partialTick)
+    public void cull(CameraFrustum frustum, float partialTick)
     {
         for(int i = 0; i < chunkRenderers.length; i++)
         {
-            if(!chunkRenderers[i].isEmpty() && (!chunkRenderers[i].visible || (i + frustumCheckOffset & 0xf) == 0))
+            if(!chunkRenderers[i].isEmpty() && (!chunkRenderers[i].visible || (i + cullStep & 0xf) == 0))
             {
                 chunkRenderers[i].cull(frustum, partialTick);
             }
         }
 
-        frustumCheckOffset++;
+        cullStep++;
     }
 
     @Override
@@ -1751,7 +1772,7 @@ public class RenderGlobal
         {
             return;
         }
-        Particle fx = ParticleDispatcher.getInstance().getDispatch(particleId).newParticle(worldObj, x, y, z, motionX, motionY, motionZ, data);
+        Particle fx = ParticleDispatcher.getInstance().getDispatch(particleId).newParticle(world, x, y, z, motionX, motionY, motionZ, data);
         if (fx != null){
             mc.particleEngine.add(fx);
         }
@@ -1765,7 +1786,7 @@ public class RenderGlobal
 		if(seasonChanged || lightChanged && !LightmapHelper.isLightmapEnabled()) {
 			for(ChunkRenderer chunkRenderer : chunkRenderers) {
 				if(chunkRenderer.skyLit && !chunkRenderer.dirty) {
-					chunkRenderersToUpdate.add(chunkRenderer);
+					dirtyChunks.add(chunkRenderer);
 					chunkRenderer.setDirty();
 				}
 			}
@@ -1777,30 +1798,30 @@ public class RenderGlobal
     {
     }
 
-    public void deleteRenderListBase()
+    public void deleteChunkLists()
     {
-        if (glRenderListBase >= 0) {
-            GLAllocation.deleteDisplayList(glRenderListBase);
+        if (chunkLists >= 0) {
+            GLAllocation.deleteDisplayList(chunkLists);
         }
     }
     @Override
     public void levelEvent(Player player, int id, int x, int y, int z, int data)
     {
-        Random random = worldObj.rand;
+        Random random = world.rand;
         switch(id) {
             default:
                 break;
 
             case EVENT_DISPENSER_EMPTY: // Dispenser empty click
-                worldObj.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, x, y, z, "tile.dispenser.click", 1.0F, 1.0F);
+                world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, x, y, z, "tile.dispenser.click", 1.0F, 1.0F);
                 break;
 
             case EVENT_DISPENSER_ITEM: // Dispenser fire item
-                worldObj.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, x, y, z, "tile.dispenser.eject", 1.0F, 1.0F);
+                world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, x, y, z, "tile.dispenser.eject", 1.0F, 1.0F);
                 break;
 
             case EVENT_DISPENSER_PROJECTILE: // Dispenser fire projectile
-                worldObj.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, x, y, z, "tile.dispenser.fire", 1.0F, 1.2F);
+                world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, x, y, z, "tile.dispenser.fire", 1.0F, 1.2F);
                 break;
 
             case EVENT_DISPENSER_PARTICLES: // Dispenser eject particles
@@ -1828,36 +1849,36 @@ public class RenderGlobal
                 if(data > 0) {
                     Block<?> block = Blocks.blocksList[data];
 
-                    worldObj.playBlockSoundEffect(null, (float)x + 0.5F, (float)y + 0.5F, (float)z + 0.5F, block, EnumBlockSoundEffectType.MINE);
+                    world.playBlockSoundEffect(null, (float)x + 0.5F, (float)y + 0.5F, (float)z + 0.5F, block, EnumBlockSoundEffectType.MINE);
                 }
-                mc.particleEngine.destroy(x, y, z, data, worldObj.getBlockMetadata(x, y, z));
+                mc.particleEngine.destroy(x, y, z, data, world.getBlockMetadata(x, y, z));
                 break;
 
             case EVENT_DOOR_SOUND: // Door sound
                 if(java.lang.Math.random() < 0.5D) {
-                    worldObj.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double)x + 0.5D, (double)y + 0.5D, (double)z + 0.5D, "random.door_open", 1.0F, worldObj.rand.nextFloat() * 0.1F + 0.9F);
+                    world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double)x + 0.5D, (double)y + 0.5D, (double)z + 0.5D, "random.door_open", 1.0F, world.rand.nextFloat() * 0.1F + 0.9F);
                 } else {
-                    worldObj.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double)x + 0.5D, (double)y + 0.5D, (double)z + 0.5D, "random.door_close", 1.0F, worldObj.rand.nextFloat() * 0.1F + 0.9F);
+                    world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double)x + 0.5D, (double)y + 0.5D, (double)z + 0.5D, "random.door_close", 1.0F, world.rand.nextFloat() * 0.1F + 0.9F);
                 }
                 break;
 
             case EVENT_FIRE_EXTINGUISH: // Fire extinguish sound
-                worldObj.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (float)x + 0.5F, (float)y + 0.5F, (float)z + 0.5F, "random.fizz", 0.5F, 2.6F + (random.nextFloat() - random.nextFloat()) * 0.8F);
+                world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (float)x + 0.5F, (float)y + 0.5F, (float)z + 0.5F, "random.fizz", 0.5F, 2.6F + (random.nextFloat() - random.nextFloat()) * 0.8F);
                 break;
 
             case EVENT_JUKEBOX_TOGGLE: // Jukebox play/stop record
                 if(Item.itemsList[data] instanceof ItemDiscMusic) {
                     ItemDiscMusic record = ((ItemDiscMusic)Item.itemsList[data]);
-                    worldObj.playRecord(record.recordName, record.recordAuthor, x, y, z);
+                    world.playRecord(record.recordName, record.recordAuthor, x, y, z);
                 } else {
-                    worldObj.playRecord(null, null, x, y, z);
+                    world.playRecord(null, null, x, y, z);
                 }
                 break;
             case EVENT_PISTON_EXTEND: // Piston extend
-                worldObj.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double)x + 0.5F, (double)y + 0.5F, (double)z + 0.5F, "tile.piston.out", 0.5F, worldObj.rand.nextFloat() * 0.25F + 0.6F);
+                world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double)x + 0.5F, (double)y + 0.5F, (double)z + 0.5F, "tile.piston.out", 0.5F, world.rand.nextFloat() * 0.25F + 0.6F);
                 break;
             case EVENT_PISTON_RETRACT: // Piston retract
-                worldObj.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double)x + 0.5F, (double)y + 0.5F, (double)z + 0.5F, "tile.piston.in", 0.5F, worldObj.rand.nextFloat() * 0.25F + 0.6F);
+                world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double)x + 0.5F, (double)y + 0.5F, (double)z + 0.5F, "tile.piston.in", 0.5F, world.rand.nextFloat() * 0.25F + 0.6F);
                 break;
         }
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/TextureManager.java b/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
index 66940ee52..f41b3dc38 100644
--- a/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
+++ b/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
@@ -127,9 +127,9 @@ public class TextureManager {
 				assert cNether.hasMeta("animation") : "Coordinate " + cNether.namespaceId + " is expected to have animation data attached!";
 				addDynamicTexture(new DynamicTextureCustom(cNether, cNether.getMeta("animation", AnimationProperties.class)));
 
-				final IconCoordinate cParadise = TextureRegistry.getTexture("minecraft:block/portal_paradise/" + c.colorID);
-				assert cParadise.hasMeta("animation") : "Coordinate " + cParadise.namespaceId + " is expected to have animation data attached!";
-				addDynamicTexture(new DynamicTextureCustom(cParadise, cParadise.getMeta("animation", AnimationProperties.class)));
+				final IconCoordinate cDrift = TextureRegistry.getTexture("minecraft:block/portal_drift/" + c.colorID);
+				assert cDrift.hasMeta("animation") : "Coordinate " + cDrift.namespaceId + " is expected to have animation data attached!";
+				addDynamicTexture(new DynamicTextureCustom(cDrift, cDrift.getMeta("animation", AnimationProperties.class)));
 			}
 		}
 	}
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 fb9713e93..32a4f00ad 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
@@ -523,12 +523,14 @@ public class WorldRenderer
             if(mc.gameSettings.enableVsync.value || mc.gameSettings.customFpsLimit.value > 0) // Power saver
             {
                 Debug.change("sleep");
-                long l1 = ((systemTime + (nsPerSecond / c)) - System.nanoTime()) / 1_000_000;
-                if(l1 > 0L && l1 < 500L)
+                long timeToSleep = ((systemTime + (nsPerSecond / c)) - System.nanoTime());
+                long millis = timeToSleep / 1_000_000L;
+                int nanos = (int) (timeToSleep - (millis * 1_000_000L));
+                if(millis > 0L && millis < 500L)
                 {
                     try
                     {
-                        Thread.sleep(l1);
+                        Thread.sleep(millis, nanos);
                     }
                     catch(InterruptedException e)
                     {
@@ -552,7 +554,7 @@ public class WorldRenderer
             if(mc.gameSettings.enableVsync.value || mc.gameSettings.customFpsLimit.value > 0)
             {
                 Debug.change("sleep");
-                long l2 = ((systemTime + (long)(0x3b9aca00 / c)) - System.nanoTime()) / 0xf4240L;
+                long l2 = ((systemTime + (long)(1_000_000_000L / c)) - System.nanoTime()) / 1_000_000L;
                 if(l2 < 0L)
                 {
                     l2 += 10L;
@@ -644,7 +646,7 @@ public class WorldRenderer
             fogManager.setupFog(FogManager.FOG_MODE_SKY, farPlaneDistance, partialTicks);
             glDisable(GL_FOG);
 
-            renderGlobal.drawSky(partialTicks);
+            renderGlobal.renderSky(partialTicks);
         }
         
         Debug.change("misc");
@@ -655,7 +657,7 @@ public class WorldRenderer
             glShadeModel(GL11.GL_SMOOTH);
         }
         
-        mc.renderGlobal.clipRenderersByFrustum(mc.activeCamera.getFrustum(), partialTicks);
+        mc.renderGlobal.cull(mc.activeCamera.getFrustum(), partialTicks);
 
         Debug.change("aurora");
         if (mc.gameSettings.aurora.value && WorldTypeFXDispatcher.getInstance().getDispatch(mc.currentWorld.getWorldType()).hasAurora())
@@ -669,15 +671,15 @@ public class WorldRenderer
         	loops = 40;
         }
         for(int i=0; i < loops; i++) {
-            long l1;
+            long timeRemaining;
             do
             {
-                if(mc.renderGlobal.updateRenderers(mc.activeCamera) || updateRenderersUntil == 0L)
+                if(mc.renderGlobal.updateDirtyChunks(mc.activeCamera) || updateRenderersUntil == 0L)
                 {
                     break;
                 }
-                l1 = updateRenderersUntil - System.nanoTime();
-            } while(l1 >= 0L && l1 <= nsPerSecond);
+                timeRemaining = updateRenderersUntil - System.nanoTime();
+            } while(timeRemaining >= 0L && timeRemaining <= nsPerSecond);
         }
 
         fogManager.setupFog(FogManager.FOG_MODE_NORMAL, farPlaneDistance, partialTicks);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
index 3080645cf..a1b152b1c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
@@ -751,7 +751,7 @@ public final class BlockModelDispatcher
         addDispatch(new BlockModelStandard<>(Blocks.GLOWSTONE).setAllTextures(BLOCK_TEXTURES, "minecraft:block/glowstone"));
 
         addDispatch(new BlockModelPortal<>(Blocks.PORTAL_NETHER, "minecraft:block/portal_nether/").setAllTextures(BLOCK_TEXTURES, "minecraft:block/portal_nether"));
-        addDispatch(new BlockModelPortal<>(Blocks.PORTAL_PARADISE, "minecraft:block/portal_paradise/").setAllTextures(BLOCK_TEXTURES, "minecraft:block/portal_nether"));
+        addDispatch(new BlockModelPortal<>(Blocks.PORTAL_DRIFT, "minecraft:block/portal_drift/").setAllTextures(BLOCK_TEXTURES, "minecraft:block/portal_nether"));
 
         addDispatch(new BlockModelCake<>(Blocks.CAKE)
             .setTex(BLOCK_TEXTURES, "minecraft:block/cake/top", Side.TOP)
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererDeer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererDeer.java
index d82bf3db4..c7309ae4b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererDeer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererDeer.java
@@ -14,6 +14,12 @@ public class MobRendererDeer extends MobRenderer<MobDeer> {
         super(shadowSize);
     }
 
+    @Override
+    protected void preRenderTransform(@NotNull final MobDeer entity, final double x, final double y, final double z, final float yaw, final float partialTick) {
+        super.preRenderTransform(entity, x, y, z, yaw, partialTick);
+        GL11.glScalef(1.1F, 1.1F, 1.1F);
+    }
+
     @Override
     protected @Nullable StaticEntityModel getAndSetupModelForLayer(@NotNull final MobDeer entity, final float brightness, final float partialTick, final int layer) {
         final StaticEntityModel model = getModel("main");
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
index bda5a26b6..180426e20 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
@@ -377,10 +377,10 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
             .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
         addDispatch(new ItemModelStandard(Items.DOOR_STEEL, "minecraft"));
         addDispatch(new ItemModelPaintbrush(Items.PAINTBRUSH, "minecraft")
-            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
-            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
-            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
-            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND,  new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 90, -90, 25, 0.68f, 0.68f, 0.68f))
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 90, 90, -25, 0.68f, 0.68f, 0.68f))
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, new DisplayPos(0, 4.0f/16f, 0.5f/16f, 90, -90, 55, 0.85f, 0.85f, 0.85f))
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, new DisplayPos(0, 4.0f/16f, 0.5f/16f, 90,  90, -55, 0.85f, 0.85f, 0.85f)));
 
         addDispatch(new ItemModelStandard(Items.RECORD_13, "minecraft"));
         addDispatch(new ItemModelStandard(Items.RECORD_CAT, "minecraft"));
@@ -400,7 +400,7 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
         addDispatch(new ItemModelBlock((ItemBlock<?>) Blocks.GLOWSTONE.asItem()).setFullBright());
         addDispatch(new ItemModelBlock((ItemBlock<?>) Blocks.PUMPKIN_CARVED_ACTIVE.asItem()).setFullBright());
         addDispatch(new ItemModelBlock((ItemBlock<?>) Blocks.LAMP_ACTIVE.asItem()).setFullBright());
-        addDispatch(new ItemModelBlock((ItemBlock<?>) Blocks.PORTAL_PARADISE.asItem()).setFullBright());
+        addDispatch(new ItemModelBlock((ItemBlock<?>) Blocks.PORTAL_DRIFT.asItem()).setFullBright());
         addDispatch(new ItemModelBlock((ItemBlock<?>) Blocks.PORTAL_NETHER.asItem()).setFullBright());
 
         addDispatch(new ItemModelStandard(Items.JAR_BUTTERFLY_BLUE, "minecraft"));
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRendererLegacy.java b/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRendererLegacy.java
index b14ad2712..933f981f3 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRendererLegacy.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRendererLegacy.java
@@ -17,23 +17,23 @@ public class TerrainRendererLegacy extends TerrainRenderer {
 
 	@Override
 	public void renderSolidTerrain(float partialTicks) {
-        mc.renderGlobal.sortAndRender(mc.activeCamera, 0, partialTicks);
+        mc.renderGlobal.render(mc.activeCamera, 0, partialTicks);
 	}
 
 	@Override
 	public void renderTranslucentTerrain(float partialTicks) {
 		RenderGlobal renderGlobal = mc.renderGlobal;
 		if(mc.gameSettings.fancyGraphics.value == 0) {
-			renderGlobal.sortAndRender(mc.activeCamera, 1, partialTicks);
+			renderGlobal.render(mc.activeCamera, 1, partialTicks);
 			return;
 		}
 		
 		glColorMask(false, false, false, false);
-		int renderCount = renderGlobal.sortAndRender(mc.activeCamera, 1, partialTicks);
+		int renderCount = renderGlobal.render(mc.activeCamera, 1, partialTicks);
 		glColorMask(true, true, true, true);
 		
 		if(renderCount > 0) {
-			renderGlobal.callAllDisplayLists(1, partialTicks);
+			renderGlobal.renderSameAsLast(1, partialTicks);
 		}
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRendererMultiDraw.java b/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRendererMultiDraw.java
index cfb6debe9..44a612fda 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRendererMultiDraw.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRendererMultiDraw.java
@@ -80,7 +80,7 @@ public class TerrainRendererMultiDraw extends TerrainRenderer {
 			int y = MathHelper.floor(renderPosY);
 			int z = MathHelper.floor(renderPosZ);
 			
-			mc.renderGlobal.markRenderersForNewPosition(x, y, z);
+			mc.renderGlobal.resortChunks(x, y, z);
 		}
 		
 		if(terrainVertexConfig == null) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java b/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
index d1f26d2ba..712769d54 100644
--- a/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
+++ b/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
@@ -99,7 +99,7 @@ public class TexturePackList
 
 	public void refresh(){
 		mc.textureManager.refreshTexturesAndDisplayErrors();
-		mc.renderGlobal.loadRenderers();
+		mc.renderGlobal.allChanged();
 		if (mc.currentScreen != null) {
 			mc.currentScreen.updateFont();
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDispatcher.java
index 42e8ea491..4ce89e1cf 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDispatcher.java
@@ -1,7 +1,6 @@
 package net.minecraft.client.render.worldtype;
 
 import net.minecraft.client.util.dispatch.Dispatcher;
-import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypes;
 
@@ -32,7 +31,7 @@ public class WorldTypeFXDispatcher extends Dispatcher<WorldType, WorldTypeFX> {
             .setHasAurora(true)
             .setCloudHeight(128f - 20f));
         addDispatch(new WorldTypeFXOverworld(WorldTypes.OVERWORLD_RETRO)
-            .setHasAurora(true));
+            .setHasAurora(false));
         addDispatch(new WorldTypeFXOverworld(WorldTypes.OVERWORLD_ISLANDS)
             .setHasAurora(true));
         addDispatch(new WorldTypeFXOverworld(WorldTypes.OVERWORLD_WINTER)
@@ -49,9 +48,12 @@ public class WorldTypeFXDispatcher extends Dispatcher<WorldType, WorldTypeFX> {
             .setHasAurora(true));
         addDispatch(new WorldTypeFXOverworld(WorldTypes.OVERWORLD_SKYBLOCK)
             .setHasAurora(true));
+        addDispatch(new WorldTypeFXOverworld(WorldTypes.OVERWORLD_BETA_173)
+            .setHasAurora(false));
         addDispatch(new WorldTypeFX(WorldTypes.OVERWORLD_HELL));
 
         addDispatch(new WorldTypeFX(WorldTypes.FLAT)
+            .setHasAurora(false)
             .setCloudHeight(256f - 20f));
 
         addDispatch(new WorldTypeFXNether(WorldTypes.NETHER_DEFAULT)
@@ -61,7 +63,7 @@ public class WorldTypeFXDispatcher extends Dispatcher<WorldType, WorldTypeFX> {
             .setHasClouds(false)
             .setHasSky(false));
 
-        addDispatch(new WorldTypeFXParadise(WorldTypes.PARADISE_DEFAULT)
+        addDispatch(new WorldTypeFXDrift(WorldTypes.DRIFT_DEFAULT)
             .setCloudHeight(8f)
             .setHasGround(false));
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXParadise.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDrift.java
similarity index 95%
rename from game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXParadise.java
rename to game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDrift.java
index d43b8b23d..5852c737a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXParadise.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDrift.java
@@ -6,8 +6,8 @@ import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.type.WorldType;
 
-public class WorldTypeFXParadise extends WorldTypeFX{
-    public WorldTypeFXParadise(WorldType worldType) {
+public class WorldTypeFXDrift extends WorldTypeFX{
+    public WorldTypeFXDrift(WorldType worldType) {
         super(worldType);
     }
 
diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/player/player.geo.json b/game/client/src/main/resources/assets/minecraft/models/entity/player/player.geo.json
index 848b8387d..a567e5418 100644
--- a/game/client/src/main/resources/assets/minecraft/models/entity/player/player.geo.json
+++ b/game/client/src/main/resources/assets/minecraft/models/entity/player/player.geo.json
@@ -152,7 +152,7 @@
 					"parent": "head",
 					"pivot": [0, 28, 0],
 					"cubes": [
-						{"origin": [-4, 24, -4], "size": [8, 8, 8], "inflate": 0.25, "uv": [32, 0]}
+						{"origin": [-4, 24, -4], "size": [8, 8, 8], "inflate": 0.5, "uv": [32, 0]}
 					]
 				},
 				{
@@ -340,7 +340,7 @@
 					"parent": "head",
 					"pivot": [0, 28, 0],
 					"cubes": [
-						{"origin": [-4, 24, -4], "size": [8, 8, 8], "inflate": 0.25, "uv": [32, 0]}
+						{"origin": [-4, 24, -4], "size": [8, 8, 8], "inflate": 0.5, "uv": [32, 0]}
 					]
 				},
 				{
diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/slime/slime.geo.json b/game/client/src/main/resources/assets/minecraft/models/entity/slime/slime.geo.json
index ac0a9ee2f..d9a16c175 100644
--- a/game/client/src/main/resources/assets/minecraft/models/entity/slime/slime.geo.json
+++ b/game/client/src/main/resources/assets/minecraft/models/entity/slime/slime.geo.json
@@ -12,25 +12,11 @@
 				"pivot": [0, 24, 0],
 				"cubes": [
 					{"origin": [-3, 1, -3], "size": [6, 6, 6], "uv": [0, 16]},
+					{"origin": [-3.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 0]},
+					{"origin": [1.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 4]},
 					{"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [0, 0]}
 				]
 			},
-			{
-				"name": "eye0",
-				"parent": "cube",
-				"pivot": [0, 24, 0],
-				"cubes": [
-					{"origin": [-3.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 0]}
-				]
-			},
-			{
-				"name": "eye1",
-				"parent": "cube",
-				"pivot": [0, 24, 0],
-				"cubes": [
-					{"origin": [1.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 4]}
-				]
-			},
 			{
 				"name": "mouth",
 				"parent": "cube",
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/PortalColors.xcf b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/PortalColors.xcf
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/PortalColors.xcf
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/PortalColors.xcf
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/black.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/black.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/black.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/black.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/black.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/black.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/black.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/black.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/blue.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/blue.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/blue.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/blue.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/blue.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/blue.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/blue.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/blue.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/brown.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/brown.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/brown.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/brown.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/brown.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/brown.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/brown.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/brown.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/cyan.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/cyan.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/cyan.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/cyan.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/cyan.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/cyan.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/cyan.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/cyan.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/gray.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/gray.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/gray.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/gray.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/gray.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/gray.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/gray.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/gray.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/green.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/green.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/green.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/green.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/green.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/green.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/green.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/green.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/lightblue.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/lightblue.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/lightblue.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/lightblue.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/lightblue.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/lightblue.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/lightblue.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/lightblue.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/lime.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/lime.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/lime.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/lime.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/lime.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/lime.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/lime.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/lime.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/magenta.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/magenta.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/magenta.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/magenta.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/magenta.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/magenta.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/magenta.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/magenta.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/orange.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/orange.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/orange.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/orange.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/orange.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/orange.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/orange.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/orange.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/pink.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/pink.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/pink.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/pink.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/pink.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/pink.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/pink.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/pink.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/purple.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/purple.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/purple.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/purple.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/purple.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/purple.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/purple.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/purple.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/red.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/red.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/red.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/red.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/red.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/red.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/red.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/red.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/silver.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/silver.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/silver.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/silver.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/silver.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/silver.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/silver.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/silver.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/white.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/white.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/white.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/white.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/white.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/white.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/white.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/white.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/yellow.png b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/yellow.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/yellow.png
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/yellow.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/yellow.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/yellow.png.mcmeta
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/block/portal_paradise/yellow.png.mcmeta
rename to game/client/src/main/resources/assets/minecraft/textures/block/portal_drift/yellow.png.mcmeta
diff --git a/game/client/src/main/resources/assets/minecraft/textures/colormap/grass/paradise_gold.png b/game/client/src/main/resources/assets/minecraft/textures/colormap/grass/drift_gold.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/colormap/grass/paradise_gold.png
rename to game/client/src/main/resources/assets/minecraft/textures/colormap/grass/drift_gold.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/colormap/grass/paradise_silver.png b/game/client/src/main/resources/assets/minecraft/textures/colormap/grass/drift_silver.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/colormap/grass/paradise_silver.png
rename to game/client/src/main/resources/assets/minecraft/textures/colormap/grass/drift_silver.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/colormap/oak/paradise_gold.png b/game/client/src/main/resources/assets/minecraft/textures/colormap/oak/drift_gold.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/colormap/oak/paradise_gold.png
rename to game/client/src/main/resources/assets/minecraft/textures/colormap/oak/drift_gold.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/colormap/oak/paradise_silver.png b/game/client/src/main/resources/assets/minecraft/textures/colormap/oak/drift_silver.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/colormap/oak/paradise_silver.png
rename to game/client/src/main/resources/assets/minecraft/textures/colormap/oak/drift_silver.png
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/background-loading-paradise.png b/game/client/src/main/resources/assets/minecraft/textures/gui/background-loading-drift.png
similarity index 100%
rename from game/client/src/main/resources/assets/minecraft/textures/gui/background-loading-paradise.png
rename to game/client/src/main/resources/assets/minecraft/textures/gui/background-loading-drift.png
diff --git a/game/core/build.gradle.kts b/game/core/build.gradle.kts
index 90b5c0cbd..926dc3843 100644
--- a/game/core/build.gradle.kts
+++ b/game/core/build.gradle.kts
@@ -1,3 +1,4 @@
+import org.gradle.internal.impldep.org.bouncycastle.util.Integers
 import java.util.*
 
 plugins {
@@ -5,10 +6,10 @@ plugins {
 }
 
 group = providers.gradleProperty("bta.group").get()
-version = providers.gradleProperty("bta.version").get()
+var version: String = providers.gradleProperty("bta.version").get()
 val assetPackFormat = providers.gradleProperty("bta.assetPackFormat").get()
 val buildChannel = providers.gradleProperty("bta.buildChannel").get()
-val mpProtocolVersion = providers.gradleProperty("bta.mpProtocolVersion").get()
+//val mpProtocolVersion = providers.gradleProperty("bta.mpProtocolVersion").get()
 
 run {
     val file = File("version.txt")
@@ -49,6 +50,8 @@ java {
 
 //region Tasks
 val versionGenerator by tasks.registering {
+    outputs.upToDateWhen { false }
+
     group = "bta.generator"
     val versionDir = project.layout.buildDirectory.dir("generated/sources/version/java")
     val outputFile = versionDir.get().file("net/minecraft/core/Version.java").asFile
@@ -59,19 +62,70 @@ val versionGenerator by tasks.registering {
         outputFile.writeText(
                 """
                     package net.minecraft.core;
-                    
+
                     public final class Version {
                         public static final String VERSION = "$version";
                         public static final long BUILD_TIME = ${Date().time}L;
                         public static final int ASSET_PACK_FORMAT = $assetPackFormat;
                         public static final BuildChannel BUILD_CHANNEL = $buildChannel;
-                        public static final int MP_PROTOCOL_VERSION = $mpProtocolVersion;
+                        public static final int MP_PROTOCOL_VERSION = ${genProtocol(version, buildChannel)};
                     }
                 """.trimIndent()
         )
     }
 }
 
+// Protocol version scheme:
+// 2 byte value
+// 1st nibble: Major version
+// 2nd nibble: Minor version
+// 3rd nibble: 0 if release, 1 if prerelease, 2 if nightly/dev release
+// 4th nibble: Prerelease version or patch version
+// For example, 7.1_01 would be encoded as 0x7101
+// 7.1 prerelease 1 would be encoded as 0x7111
+fun genProtocol(version: String, channel: String): String {
+    val parts = version.split(".") // 7.3_01
+    var major = 0;
+    var minor = 0;
+    var patch = 0;
+    val chn = when(channel.removePrefix("BuildChannel.")) {
+        "RELEASE" -> 0
+        "PRERELEASE" -> 1
+        "DEVELOPMENT" -> 2
+        "NIGHTLY" -> 2
+        else -> {
+            2
+        }
+    }
+
+    if (channel == "BuildChannel.NIGHTLY") {
+        major = 0xF;
+        minor = 0xF;
+        patch = 0;
+    } else if (parts.isNotEmpty()) {
+        major = parts[0].trim().toInt()
+        if (parts.size > 1) {
+            if (parts[1].contains("_")) {
+                val parts2 = parts[1].split("_")
+                minor = parts2[0].trim().toInt()
+                patch = parts2[1].trim().toInt()
+            } else if (parts[1].contains("prerelease", true)) {
+                val parts2 = parts[1].lowercase().split("prerelease")
+                minor = parts2[0].trim().toInt()
+                patch = parts2[1].trim().toInt()
+            } else if (parts[1].contains("pre", true)) {
+                val parts2 = parts[1].lowercase().split("pre")
+                minor = parts2[0].trim().toInt()
+                patch = parts2[1].trim().toInt()
+            } else {
+                minor = parts[1].trim().toInt()
+            }
+        }
+    }
+
+    return "0x" + Integer.toHexString(major) + Integer.toHexString(minor) + Integer.toHexString(chn) + Integer.toHexString(patch)
+}
+
 tasks.withType(JavaCompile::class.java) {
     options.isIncremental = false
     options.encoding = "UTF-8"
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBedrock.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBedrock.java
index f2df63cd7..dc2cb5902 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBedrock.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBedrock.java
@@ -16,7 +16,7 @@ public class BlockLogicBedrock
 	public void onBlockPlacedByWorld(World world, int x, int y, int z)
     {
         if (world.getBlockId(x, y - 1, z) == Blocks.GLOWSTONE.id()) {
-            Blocks.PORTAL_PARADISE.getLogic().tryToCreatePortal(world, x, y, z, DyeColor.SILVER);
+            Blocks.PORTAL_DRIFT.getLogic().tryToCreatePortal(world, x, y, z, DyeColor.SILVER);
         }
     }
 }
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 dc255f166..d05c07b32 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
@@ -22,7 +22,7 @@ public class BlockLogicPumice extends BlockLogic {
     {
         super.onBlockPlacedByWorld(world, x, y, z);
         byte radius = 2;
-        if(isWet && (inWater(world, x, y, z) || world.dimension.id == Dimension.PARADISE.id)){
+        if(isWet && (inWater(world, x, y, z) || world.dimension.id == Dimension.DRIFT.id)){
             world.setBlockWithNotify(x, y, z, Blocks.PUMICE_DRY.id());
             world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, x + 0.5D, y + 0.5D, 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/Blocks.java b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
index d3b4d5984..8c0611d23 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Blocks.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
@@ -22,7 +22,6 @@ import net.minecraft.core.item.block.ItemBlockPainted;
 import net.minecraft.core.item.block.ItemBlockStairsPainted;
 import net.minecraft.core.item.block.ItemBlockLamp;
 import net.minecraft.core.item.block.ItemBlockSlabPainted;
-import net.minecraft.core.sound.BlockSound;
 import net.minecraft.core.sound.BlockSounds;
 import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.world.Dimension;
@@ -1117,7 +1116,7 @@ public final class Blocks {
     public static final Block<BlockLogicPortal> PORTAL_NETHER = register("portal.nether", "minecraft:block/portal_nether", 830, (BlockLogicSupplier<BlockLogicPortal>) b -> new BlockLogicPortal(b, Dimension.NETHER, Blocks.OBSIDIAN, Blocks.FIRE))
         .withSound(BlockSounds.GLASS).withHardness(-1F).withLightEmission(0.75F).withOverrideColor(MaterialColor.paintedPurple).withDisabledStats()
         .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU);
-    public static final Block<BlockLogicPortal> PORTAL_PARADISE = register("portal.paradise", "minecraft:block/portal_paradise", 831, (BlockLogicSupplier<BlockLogicPortal>) b -> new BlockLogicPortal(b, Dimension.PARADISE, Blocks.GLOWSTONE, Blocks.BEDROCK))
+    public static final Block<BlockLogicPortal> PORTAL_DRIFT = register("portal.drift", "minecraft:block/portal_drift", 831, (BlockLogicSupplier<BlockLogicPortal>) b -> new BlockLogicPortal(b, Dimension.DRIFT, Blocks.GLOWSTONE, Blocks.BEDROCK))
         .withSound(BlockSounds.GLASS).withHardness(-1F).withLightEmission(0.75f).withOverrideColor(MaterialColor.paintedPurple).withDisabledStats()
         .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU);
 
diff --git a/game/core/src/main/java/net/minecraft/core/data/legacy/LegacyBiomes.java b/game/core/src/main/java/net/minecraft/core/data/legacy/LegacyBiomes.java
index 37972feb7..50d0fb1ad 100644
--- a/game/core/src/main/java/net/minecraft/core/data/legacy/LegacyBiomes.java
+++ b/game/core/src/main/java/net/minecraft/core/data/legacy/LegacyBiomes.java
@@ -44,7 +44,7 @@ public abstract class LegacyBiomes
         register(Biomes.OVERWORLD_TUNDRA, 12);
         register(Biomes.OVERWORLD_MEADOW, 13);
         register(Biomes.NETHER_NETHER, 14);
-        register(Biomes.PARADISE_PARADISE, 15);
+        register(Biomes.DRIFT_DRIFT, 15);
         register(Biomes.OVERWORLD_BIRCH_FOREST, 16);
         register(Biomes.OVERWORLD_RETRO, 17);
         register(Biomes.OVERWORLD_HELL, 18);
diff --git a/game/core/src/main/java/net/minecraft/core/data/legacy/LegacyWorldTypes.java b/game/core/src/main/java/net/minecraft/core/data/legacy/LegacyWorldTypes.java
index a87f4c6b9..53eb26ac7 100644
--- a/game/core/src/main/java/net/minecraft/core/data/legacy/LegacyWorldTypes.java
+++ b/game/core/src/main/java/net/minecraft/core/data/legacy/LegacyWorldTypes.java
@@ -53,7 +53,7 @@ public abstract class LegacyWorldTypes
         register(WorldTypes.OVERWORLD_RETRO, 7, "retro");
         register(WorldTypes.OVERWORLD_EXTENDED, 10, "extended");
         register(WorldTypes.NETHER_DEFAULT, 11, "nether");
-        register(WorldTypes.PARADISE_DEFAULT, 12, "paradise_"); // _ to prevent name clash
+        register(WorldTypes.DRIFT_DEFAULT, 12, "drift");
         register(WorldTypes.EMPTY, 13, "empty");
         register(WorldTypes.DEBUG, 14, "debug");
         register(WorldTypes.OVERWORLD_FLOATING, 15, "floating");
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Mob.java b/game/core/src/main/java/net/minecraft/core/entity/Mob.java
index ba8615728..fce44bd69 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Mob.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Mob.java
@@ -94,6 +94,7 @@ public abstract class Mob extends Entity
     protected float flightSmoothness = 0.5f;
     private @Nullable Entity currentTarget = null;
     protected int numTicksToChaseTarget;
+    protected double jumpHeight = 0.42D;
     public @NotNull String nickname = "";
     public byte chatColor = 0;
     protected float lastStrafe = 0.0f;
@@ -890,7 +891,7 @@ public abstract class Mob extends Entity
             move(xd, yd, zd);
             if((horizontalCollision || isJumping) && canClimb())
             {
-                yd = 0.25D;
+                //yd = 0.25D;
             }
             if (!onGround){
                 movementScale = MathHelper.lerp(movementScale, 1f, pushTime);
@@ -1051,7 +1052,7 @@ public abstract class Mob extends Entity
     	if(noPhysics) {
     		return;
     	}
-        yd = 0.42D;
+        yd = jumpHeight;
         if (isSprinting())
         {
             float f = yRot * 0.01745329F;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobButterfly.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobButterfly.java
index 3fb849bf9..0676c72b1 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobButterfly.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobButterfly.java
@@ -4,6 +4,8 @@ import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.Global;
 import net.minecraft.core.WeightedRandomBag;
 import net.minecraft.core.block.Block;
+import net.minecraft.core.block.Blocks;
+import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.MobFlying;
 import net.minecraft.core.entity.SkinVariantList;
@@ -26,7 +28,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.function.Supplier;
 
-public class MobButterfly extends MobFlying implements Creature {
+public class MobButterfly extends MobFlying implements AmbientCreature {
     public static final Map<Integer, ButterflyEntry> colorEntries = new HashMap<>();
 
     public static final int DATA_COLOR_ID = 16;
@@ -143,6 +145,21 @@ public class MobButterfly extends MobFlying implements Creature {
         setColor(entry.id);
     }
 
+    @Override
+    public boolean canSpawnHere()
+    {
+        if (!world.isDaytime()) return false;
+        int x = MathHelper.floor(this.x);
+        int y = MathHelper.floor(bb.minY);
+        int z = MathHelper.floor(this.z);
+        int id = world.getBlockId(x, y - 1, z);
+        if (Blocks.blocksList[id] != null)
+        {
+            return Blocks.blocksList[id].hasTag(BlockTags.PASSIVE_MOBS_SPAWN) && world.getFullBlockLightValue(x, y, z) > 8 && super.canSpawnHere();
+        }
+        return false;
+    }
+
     private boolean isCourseTraversable(double waypointX, double waypointY, double waypointZ, double distanceFromEntity)
     {
 
@@ -263,6 +280,11 @@ public class MobButterfly extends MobFlying implements Creature {
         setColor(tag.getByte("Color") & 0xFF);
     }
 
+    @Override
+    public @NotNull String getDefaultEntityTexture() {
+        return getEntityTexture();
+    }
+
     @Override
     public @NotNull String getEntityTexture() {
         return this.basePath + getTextureReference() + "_0.png";
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobDeer.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobDeer.java
index d368c873f..70dd32174 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobDeer.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobDeer.java
@@ -2,35 +2,150 @@ package net.minecraft.core.entity.animal;
 
 import net.minecraft.core.WeightedRandomLootObject;
 import net.minecraft.core.entity.AgedMob;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.MobAge;
+import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Items;
 import com.mojang.nbt.tags.CompoundTag;
+import net.minecraft.core.util.helper.DamageType;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.season.Seasons;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
 
 public class MobDeer
         extends MobAnimal
         implements AgedMob
 {
     private final @NotNull MobAge age;
+    private @Nullable Entity closestThreat;
+
+    private int runawayTimer = 0;
+    private int counter = 0;
+    private boolean isRunningAway = false;
+
+    private final int MAX_RUNAWAY_TIME = 200;
+    private final int COUNTER_TIME = 30;
 
     public MobDeer(World world)
     {
         super(world);
         setTextureIdentifier("minecraft", "deer");
         setSize(0.9F, 1.3F);
+        moveSpeed = 0.8F;
         mobDrops.add(new WeightedRandomLootObject(Items.FOOD_VENISON_RAW.getDefaultStack(), 1, 2));
         this.age = MobAge.newRandom(this, MobAge.YEAR_LENGTH_DAYS * 5, 14, MobAge.YEAR_LENGTH_DAYS * 4);
+        this.jumpHeight = 0.5D;
     }
 
     @Override
     public void onLivingUpdate() {
         super.onLivingUpdate();
-
         this.getMobAge().tick(this.world);
     }
 
+    @Override
+    public boolean hurt(@Nullable Entity attacker, int damage, DamageType type)
+    {
+        if (attacker != null) {
+            beginRunaway();
+        }
+
+        return super.hurt(attacker, damage, type);
+    }
+
+    private void beginRunaway() {
+        runawayTimer = MAX_RUNAWAY_TIME;
+        counter = COUNTER_TIME;
+        moveSpeed = 2.5F;
+        findRandomPathToRunTo();
+    }
+
+    private void stopRunaway() {
+        isRunningAway = false;
+        this.counter = 0;
+        moveSpeed = 0.4F;
+    }
+
+    @Override
+    protected void updateAI()
+    {
+        super.updateAI();
+
+        if(runawayTimer <= 0) {
+            findThreatNearby();
+            if (this.closestThreat != null)
+                beginRunaway();
+            else if(isRunningAway)
+                stopRunaway();
+        } else {
+            //this.isJumping = true;
+            isRunningAway = true;
+            if(counter >= 0) {
+                counter--;
+            } else {
+                findRandomPathToRunTo();
+                counter = COUNTER_TIME;
+            }
+            runawayTimer--;
+
+        }
+
+        if(isRunningAway && onGround && !isJumping && isWalking) {
+            // hop along the ground when scared
+                yd = 0.35d;
+                float f = yRot * 0.01745329F;
+                xd -= MathHelper.sin(f) * 0.25F;
+                zd += MathHelper.cos(f) * 0.25F;
+
+        }
+
+    }
+
+    protected void findThreatNearby() {
+        int dist = 10;
+        Player player = world.getClosestPlayer(x, y, z, dist);
+        if(player != null && !player.isSneaking()){
+            this.closestThreat = player;
+            return;
+        }
+
+        if(player == null){
+            List<MobWolf> nearbyWolves = world.getEntitiesWithinAABB(MobWolf.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(8D, 4D, 8D));
+            if (!nearbyWolves.isEmpty()) {
+                this.closestThreat = nearbyWolves.get(random.nextInt(nearbyWolves.size()));
+                return;
+            }
+        }
+        this.closestThreat = null;
+    }
+
+    private void findRandomPathToRunTo() {
+        if (this.closestThreat != null)
+            getPathAwayFromPoint(this.x + random.nextInt(8)-4, this.z + random.nextInt(8)-4, closestThreat.x, closestThreat.z);
+        else
+            getPathAwayFromPoint(this.x, this.z, this.x + random.nextInt(8)-4, this.z + random.nextInt(8)-4);
+    }
+
+    protected void getPathAwayFromPoint(double x, double z, double pX, double pZ) {
+        int scale = 10;
+        double dX = x - pX;
+        double dZ = z - pZ;
+
+        double sqrt = Math.sqrt(dX * dX + dZ * dZ);
+
+        double nDX = dX / sqrt;
+        double nDZ = dZ / sqrt;
+
+        Vec3 safePoint = Vec3.getTempVec3(x + nDX * scale, y, z + nDZ * scale);
+        pathToEntity = world.getEntityPathToXYZ(this, MathHelper.floor(safePoint.x), MathHelper.floor(y), MathHelper.floor(safePoint.z), 16F);
+    }
+
     @Override
     public @NotNull MobAge getMobAge() {
         return this.age;
@@ -40,7 +155,7 @@ public class MobDeer
     public void addAdditionalSaveData(@NotNull CompoundTag tag)
     {
         super.addAdditionalSaveData(tag);
-
+        tag.putShort("RunawayTimer", (short) runawayTimer);
         this.age.writeTag(tag);
     }
 
@@ -56,7 +171,7 @@ public class MobDeer
     public void readAdditionalSaveData(@NotNull CompoundTag tag)
     {
         super.readAdditionalSaveData(tag);
-
+        this.runawayTimer = tag.getShort("RunawayTimer");
         this.age.readTag(tag);
     }
 
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 bb3d06526..a2f44f0f9 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
@@ -453,7 +453,7 @@ public class MobFireflyCluster extends MobFlying
 				Biomes.OVERWORLD_TUNDRA,
 				Biomes.OVERWORLD_BOREAL_FOREST,
 				Biomes.OVERWORLD_GLACIER,
-				Biomes.PARADISE_PARADISE
+				Biomes.DRIFT_DRIFT
 		},
 				new float[]{0.67f, 1f, 0.99f}));
 		public static FireflyColor RED = register(new FireflyColor(3, "fireflyRed", new Biome[] {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWaterAnimal.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWaterAnimal.java
index 7eebfcfbf..f40415e21 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWaterAnimal.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWaterAnimal.java
@@ -6,7 +6,7 @@ import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 
 public class MobWaterAnimal extends MobPathfinder
-	implements Creature
+	implements WaterCreature
 {
 
     public MobWaterAnimal(World world)
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
index eeda93f1a..557c8ca65 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
@@ -341,10 +341,18 @@ public class MobWolf
         } else
         if(getTarget() == null && !hasPath())
         {
-            if(!isWolfTamed() && world.rand.nextInt(100) == 0){
-                List<MobSheep> nearbySheep = world.getEntitiesWithinAABB(MobSheep.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
-                if (!nearbySheep.isEmpty()) {
-                    setTarget(nearbySheep.get(world.rand.nextInt(nearbySheep.size())));
+            if(!isWolfTamed() && world.rand.nextInt(50) == 0){
+                List<MobAnimal> validTargets = new ArrayList<>();
+                List<MobAnimal> nearbyAnimals = world.getEntitiesWithinAABB(MobAnimal.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
+                if (!nearbyAnimals.isEmpty()) {
+                    for(int i = 0; i < nearbyAnimals.size(); i++){
+                        MobAnimal animal = nearbyAnimals.get(i);
+                        if(animal instanceof MobSheep || animal instanceof MobDeer)
+                            validTargets.add(animal);
+                    }
+                }
+                if (!validTargets.isEmpty()) {
+                    setTarget(validTargets.get(world.rand.nextInt(validTargets.size())));
                 }
             }
         }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/WaterCreature.java b/game/core/src/main/java/net/minecraft/core/entity/animal/WaterCreature.java
new file mode 100644
index 000000000..5378b9e0e
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/WaterCreature.java
@@ -0,0 +1,4 @@
+package net.minecraft.core.entity.animal;
+
+public interface WaterCreature {
+}
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/Enemy.java b/game/core/src/main/java/net/minecraft/core/entity/monster/Enemy.java
index a644bf256..70e5cf70c 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/Enemy.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/Enemy.java
@@ -1,9 +1,6 @@
 package net.minecraft.core.entity.monster;
 
 
-import net.minecraft.core.entity.animal.Creature;
-
 public interface Enemy
-	extends Creature
 {
 }
diff --git a/game/core/src/main/java/net/minecraft/core/enums/MobCategory.java b/game/core/src/main/java/net/minecraft/core/enums/MobCategory.java
index f51929a83..e655f22b3 100644
--- a/game/core/src/main/java/net/minecraft/core/enums/MobCategory.java
+++ b/game/core/src/main/java/net/minecraft/core/enums/MobCategory.java
@@ -2,16 +2,18 @@ package net.minecraft.core.enums;
 
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.animal.AmbientCreature;
+import net.minecraft.core.entity.animal.Creature;
 import net.minecraft.core.entity.animal.MobAnimal;
 import net.minecraft.core.entity.animal.MobWaterAnimal;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.animal.WaterCreature;
 import net.minecraft.core.entity.monster.Enemy;
 
 public enum MobCategory {
 
 	monster("monster", 0, Enemy.class, 70, Material.air, false),
-    creature("creature", 1, MobAnimal.class, 15, Material.air, true),
-    waterCreature("waterCreature", 2, MobWaterAnimal.class, 5, Material.water, true),
+    creature("creature", 1, Creature.class, 15, Material.air, true),
+    waterCreature("waterCreature", 2, WaterCreature.class, 5, Material.water, true),
     ambientCreature("ambient", 3, AmbientCreature.class, 2, Material.air, true);
 	
 	private final Class<?> baseClass;
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeSeason.java b/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeSeason.java
index 8d2805996..44aef888a 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeSeason.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeSeason.java
@@ -19,7 +19,7 @@ import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
 public class ArgumentTypeSeason implements ArgumentType<String> {
-    private static final List<String> EXAMPLES = Arrays.asList("overworld.winter", "overworld.summer", "paradise.gold");
+    private static final List<String> EXAMPLES = Arrays.asList("overworld.winter", "overworld.summer", "drift.gold");
 
     public static ArgumentType<String> season() {
         return new ArgumentTypeSeason();
diff --git a/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryAnimal.java b/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryAnimal.java
index 45bc7d06b..2e2567967 100644
--- a/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryAnimal.java
+++ b/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryAnimal.java
@@ -10,10 +10,11 @@ import net.minecraft.core.net.packet.Packet;
 import net.minecraft.core.net.packet.PacketAddMob;
 import org.jetbrains.annotations.NotNull;
 
-public class NetEntryAnimal<T extends Creature> implements IPacketEntry<T>, ITrackedEntry<T> {
+public class NetEntryAnimal<T extends Mob> implements IPacketEntry<T>, ITrackedEntry<T> {
+    @SuppressWarnings("unchecked")
     @Override
     public @NotNull Class<T> getAppliedClass() {
-        return (Class<T>) Creature.class;
+        return (Class<T>) Mob.class;
     }
 
     @Override
@@ -32,12 +33,12 @@ public class NetEntryAnimal<T extends Creature> implements IPacketEntry<T>, ITra
     }
 
     @Override
-    public void onEntityTracked(EntityTracker tracker, EntityTrackerEntry trackerEntry, Creature trackedObject) {
+    public void onEntityTracked(EntityTracker tracker, EntityTrackerEntry trackerEntry, Mob trackedObject) {
 
     }
 
     @Override
-    public Packet getSpawnPacket(EntityTrackerEntry tracker, Creature trackedObject) {
-        return new PacketAddMob((Mob) trackedObject);
+    public Packet getSpawnPacket(EntityTrackerEntry tracker, Mob trackedObject) {
+        return new PacketAddMob(trackedObject);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/Dimension.java b/game/core/src/main/java/net/minecraft/core/world/Dimension.java
index 22450e328..b33eab778 100644
--- a/game/core/src/main/java/net/minecraft/core/world/Dimension.java
+++ b/game/core/src/main/java/net/minecraft/core/world/Dimension.java
@@ -79,7 +79,7 @@ public class Dimension
 
 	public static final Dimension OVERWORLD = new Dimension("overworld", null, 1.0f, null, WorldTypes.OVERWORLD_DEFAULT);
 	public static final Dimension NETHER = new Dimension("nether", OVERWORLD, 0.125f, Blocks.PORTAL_NETHER, WorldTypes.NETHER_DEFAULT);
-	public static final Dimension PARADISE = new Dimension("paradise", OVERWORLD, 8.0f, Blocks.PORTAL_PARADISE, WorldTypes.PARADISE_DEFAULT);
+	public static final Dimension DRIFT = new Dimension("drift", OVERWORLD, 8.0f, Blocks.PORTAL_DRIFT, WorldTypes.DRIFT_DEFAULT);
 
 	public static Map<Integer, Dimension> getDimensionList()
 	{
@@ -100,6 +100,6 @@ public class Dimension
 	public static void init(){
 		registerDimension(0, OVERWORLD);
 		registerDimension(1, NETHER);
-		registerDimension(2, PARADISE);
+		registerDimension(2, DRIFT);
 	}
 }
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 2b9e3f455..821817428 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
@@ -56,6 +56,7 @@ public class Biome
         spawnableCreatureList.add(new SpawnListEntry(MobDeer.class, 10));
         spawnableWaterCreatureList.add(new SpawnListEntry(MobSquid.class, 10));
         spawnableAmbientCreatureList.add(new SpawnListEntry(MobFireflyCluster.class, 10));
+        spawnableAmbientCreatureList.add(new SpawnListEntry(MobButterfly.class, 65));
     }
 
     public WorldFeature getRandomWorldGenForTrees(Random random)
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 bf5205f60..9e2c8d5b2 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
@@ -4,7 +4,8 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.world.biome.nether.*;
 import net.minecraft.core.world.biome.overworld.*;
-import net.minecraft.core.world.biome.paradise.BiomeParadise;
+import net.minecraft.core.world.biome.drift.BiomeDrift;
+import net.minecraft.core.world.biome.overworld.legacy.*;
 import net.minecraft.core.world.weather.Weathers;
 
 public class Biomes
@@ -24,7 +25,7 @@ public class Biomes
     public static final Biome OVERWORLD_GLACIER = register("minecraft:overworld.glacier", new Biome("overworld.glacier").setColor(0xcbf6ff).setSurfaceSnow().setTopBlock(Blocks.BLOCK_SNOW.id()).setFillerBlock(Blocks.BLOCK_SNOW.id()));
     public static final Biome OVERWORLD_TUNDRA = register("minecraft:overworld.tundra", new Biome("overworld.tundra").setColor(0x57e0ff).setSurfaceSnow());
     public static final Biome OVERWORLD_MEADOW = register("minecraft:overworld.meadow", new BiomeBorealForest("overworld.meadow").setColor(0x8c8c22));
-    public static final Biome PARADISE_PARADISE = register("minecraft:paradise.paradise", new BiomeParadise("overworld.paradise").setColor(0x8080FF).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG));
+    public static final Biome DRIFT_DRIFT = register("minecraft:drift.drift", new BiomeDrift("drift.drift").setColor(0x8080FF).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG));
     public static final Biome OVERWORLD_BIRCH_FOREST = register("minecraft:overworld.birch_forest", new BiomeBirchForest("overworld.birch_forest").setColor(0x4bcb5e));
     public static final Biome OVERWORLD_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()));
@@ -39,6 +40,17 @@ public class Biomes
     public static final Biome NETHER_ASH_PLAINS = register("minecraft:nether.ash_plains", new BiomeAshPlains("nether.ash_plains").setColor(0xDD0000).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.SLATE.id()).setFillerBlock(Blocks.SLATE.id()));
     public static final Biome NETHER_BONEYARD = register("minecraft:nether.boneyard", new BiomeBoneyard("nether.boneyard").setColor(0xDD0000).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG).setTopBlock(Blocks.SOULSAND.id()).setFillerBlock(Blocks.SOULSAND.id()));
 
+    public static final Biome OVERWORLD_LEGACY_RAINFOREST = register("minecraft:overworld.legacy.rainforest", new BiomeRainforestLegacy("overworld.legacy.rainforest").setColor(0xd9e023).setBlockedWeathers(Weathers.OVERWORLD_SNOW));
+    public static final Biome OVERWORLD_LEGACY_SWAMPLAND = register("minecraft:overworld.legacy.swampland", new BiomeSwampLegacy("overworld.legacy.swampland").setColor(0x07f9b2));
+    public static final Biome OVERWORLD_LEGACY_SEASONAL_FOREST = register("minecraft:overworld.legacy.seasonal_forest", new Biome("overworld.legacy.seasonal_forest").setColor(0x9be023));
+    public static final Biome OVERWORLD_LEGACY_FOREST = register("minecraft:overworld.legacy.forest", new BiomeForestLegacy("overworld.legacy.forest").setColor(0x056621));
+    public static final Biome OVERWORLD_LEGACY_SAVANNA = register("minecraft:overworld.legacy.savanna", new BiomeDesertLegacy("overworld.legacy.savanna").setColor(0xd9e023).setBlockedWeathers(Weathers.OVERWORLD_SNOW));
+    public static final Biome OVERWORLD_LEGACY_SHRUBLAND = register("minecraft:overworld.legacy.shrubland", new Biome("overworld.legacy.shrubland").setColor(0xa1ad20));
+    public static final Biome OVERWORLD_LEGACY_TAIGA = register("minecraft:overworld.legacy.taiga", new BiomeTaigaLegacy("overworld.legacy.taiga").setColor(0x2eb153).setSurfaceSnow());
+    public static final Biome OVERWORLD_LEGACY_DESERT = register("minecraft:overworld.legacy.desert", new BiomeDesertLegacy("overworld.legacy.desert").setColor(0xfa9418).setBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM).setTopBlock(Blocks.SAND.id()).setFillerBlock(Blocks.SAND.id()));
+    public static final Biome OVERWORLD_LEGACY_PLAINS = register("minecraft:overworld.legacy.plains", new BiomeDesertLegacy("overworld.legacy.plains").setColor(0xffd910));
+    public static final Biome OVERWORLD_LEGACY_TUNDRA = register("minecraft:overworld.legacy.tundra", new Biome("overworld.legacy.tundra").setColor(0x57ebf9).setSurfaceSnow());
+
     public static Biome register(String key, Biome biome)
     {
         Registries.BIOMES.register(key, biome);
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/paradise/BiomeParadise.java b/game/core/src/main/java/net/minecraft/core/world/biome/drift/BiomeDrift.java
similarity index 78%
rename from game/core/src/main/java/net/minecraft/core/world/biome/paradise/BiomeParadise.java
rename to game/core/src/main/java/net/minecraft/core/world/biome/drift/BiomeDrift.java
index dbd136566..b3f0cc0f3 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/paradise/BiomeParadise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/drift/BiomeDrift.java
@@ -1,12 +1,12 @@
-package net.minecraft.core.world.biome.paradise;
+package net.minecraft.core.world.biome.drift;
 
 import net.minecraft.core.entity.animal.MobChicken;
 import net.minecraft.core.entity.SpawnListEntry;
 import net.minecraft.core.world.biome.Biome;
 
-public class BiomeParadise extends Biome
+public class BiomeDrift extends Biome
 {	
-    public BiomeParadise(String key)
+    public BiomeDrift(String key)
     {
     	super(key);
         spawnableMonsterList.clear();
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeDesertLegacy.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeDesertLegacy.java
new file mode 100644
index 000000000..fdcae4926
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeDesertLegacy.java
@@ -0,0 +1,11 @@
+package net.minecraft.core.world.biome.overworld.legacy;
+
+import net.minecraft.core.world.biome.Biome;
+
+public class BiomeDesertLegacy
+    extends Biome
+{
+    public BiomeDesertLegacy(final String key) {
+        super(key);
+    }
+}
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
new file mode 100644
index 000000000..66d2bd8cc
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeForestLegacy.java
@@ -0,0 +1,29 @@
+package net.minecraft.core.world.biome.overworld.legacy;
+
+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.WorldFeatureTree;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
+
+import java.util.Random;
+
+public class BiomeForestLegacy
+    extends Biome
+{
+    public BiomeForestLegacy(final String key) {
+        super(key);
+        spawnableCreatureList.add(new SpawnListEntry(MobWolf.class, 2));
+    }
+
+    @Override
+    public WorldFeature getRandomWorldGenForTrees(final Random random) {
+        if (random.nextInt(5) == 0) {
+            return new WorldFeatureTree(Blocks.LEAVES_BIRCH.id(), Blocks.LOG_BIRCH.id(), 5);
+        } else {
+            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/BiomeRainforestLegacy.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeRainforestLegacy.java
new file mode 100644
index 000000000..3faa48598
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeRainforestLegacy.java
@@ -0,0 +1,22 @@
+package net.minecraft.core.world.biome.overworld.legacy;
+
+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.WorldFeatureTree;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
+
+import java.util.Random;
+
+public class BiomeRainforestLegacy
+    extends Biome
+{
+    public BiomeRainforestLegacy(final String key) {
+        super(key);
+    }
+
+    @Override
+    public WorldFeature getRandomWorldGenForTrees(final 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/BiomeSwampLegacy.java b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeSwampLegacy.java
new file mode 100644
index 000000000..84f550c2c
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeSwampLegacy.java
@@ -0,0 +1,11 @@
+package net.minecraft.core.world.biome.overworld.legacy;
+
+import net.minecraft.core.world.biome.Biome;
+
+public class BiomeSwampLegacy
+    extends Biome
+{
+    public BiomeSwampLegacy(final String key) {
+        super(key);
+    }
+}
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
new file mode 100644
index 000000000..48842c748
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/overworld/legacy/BiomeTaigaLegacy.java
@@ -0,0 +1,28 @@
+package net.minecraft.core.world.biome.overworld.legacy;
+
+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.WorldFeatureTreeTaigaBushy;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeTaigaTall;
+
+import java.util.Random;
+
+public class BiomeTaigaLegacy
+    extends Biome
+{
+    public BiomeTaigaLegacy(final String key) {
+        super(key);
+    }
+
+    @Override
+    public WorldFeature getRandomWorldGenForTrees(final Random random) {
+        if(random.nextInt(3) == 0)
+        {
+            return new WorldFeatureTreeTaigaTall(Blocks.LEAVES_PINE.id(), Blocks.LOG_PINE.id());
+        } else
+        {
+            return new WorldFeatureTreeTaigaBushy(Blocks.LEAVES_PINE.id(), Blocks.LOG_PINE.id());
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java
new file mode 100644
index 000000000..be264996d
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java
@@ -0,0 +1,178 @@
+package net.minecraft.core.world.biome.provider;
+
+import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.biome.Biomes;
+import net.minecraft.core.world.noise.PerlinSimplexNoise;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.Random;
+
+public class BiomeProviderB173
+    extends BiomeProvider
+{
+    private static final float ZOOM = 2.0f;
+    private static final float TEMP_SCALE = 0.025F;
+    private static final float DOWNFALL_SCALE = 0.05F;
+    private static final float NOISE_SCALE = 0.25F;
+
+    private final @NotNull PerlinSimplexNoise temperatureMap;
+    private final @NotNull PerlinSimplexNoise downfallMap;
+    private final @NotNull PerlinSimplexNoise noiseMap;
+
+    public BiomeProviderB173(final long seed) {
+        this.temperatureMap = new PerlinSimplexNoise(new Random(seed * 9871L), 4);
+        this.downfallMap = new PerlinSimplexNoise(new Random(seed * 39811L), 4);
+        this.noiseMap = new PerlinSimplexNoise(new Random(seed * 543321L), 2);
+    }
+
+    @Override
+    public Biome[] getBiomes(Biome[] biomes, double[] temperatures, double[] humidities, double[] varieties, final int x, final int y, final int z, final int xSize, final int ySize, final int zSize) {
+        if (biomes == null || biomes.length < xSize * ySize * zSize) {
+            biomes = new Biome[xSize * ySize * zSize];
+        }
+
+        if (temperatures == null || temperatures.length < xSize * zSize) {
+            temperatures = new double[xSize * zSize];
+        }
+        this.temperatureMap.getValue(temperatures, x, z, xSize, xSize, 0.025, 0.025, 0.25);
+
+        if (humidities == null || humidities.length < xSize * zSize) {
+            humidities = new double[xSize * zSize];
+        }
+        this.downfallMap.getValue(humidities, x, z, xSize, xSize, 0.05, 0.05, 1.0 / 3.0);
+
+        if (varieties == null || varieties.length < xSize * zSize) {
+            varieties = new double[xSize * zSize];
+        }
+        Arrays.fill(varieties, 0.0);
+
+        final double[] noises = this.noiseMap.getValue(null, x, z, xSize, xSize, 0.25, 0.25, 0.5882352941176471D);
+
+        for (int xx = 0; xx < xSize; xx++) {
+            for (int zz = 0; zz < zSize; zz++) {
+                final double a = noises[xx * zSize + zz] * 1.1 + 0.5;
+                double b = 0.01;
+                double c = 1.0 - b;
+                double temperature = (temperatures[xx * zSize + zz] * 0.15 + 0.7) * c + a * b;
+
+                b = 0.002;
+                c = 1.0 - b;
+                double downfall = (humidities[xx * zSize + zz] * 0.15 + 0.5) * c + a * b;
+
+                temperature = 1.0 - (1.0 - temperature) * (1.0 - temperature);
+
+                if (temperature < 0.0) {
+                    temperature = 0.0;
+                }
+                if (temperature > 1.0) {
+                    temperature = 1.0;
+                }
+
+                if (downfall < 0.0) {
+                    downfall = 0.0;
+                }
+                if (downfall > 1.0) {
+                    downfall = 1.0;
+                }
+
+                temperatures[xx * zSize + zz] = temperature;
+                humidities[xx * zSize + zz] = downfall;
+
+                for (int yy = 0; yy < ySize; yy++) {
+                    biomes[yy * xSize * zSize + zz * xSize + xx] = this.lookupBiome(temperature, downfall, 0.0, 0.0);
+                }
+            }
+        }
+
+        return biomes;
+    }
+
+    @Override
+    public double[] getTemperatures(double[] temperatures, final int x, final int z, final int xSize, final int zSize) {
+        if (temperatures == null || temperatures.length < xSize * zSize) {
+            temperatures = new double[xSize * zSize];
+        }
+
+        this.temperatureMap.getValue(temperatures, x, z, xSize, xSize, 0.025, 0.025, 0.25);
+        final double[] noises = this.noiseMap.getValue(null, x, z, xSize, zSize, 0.25, 0.25, 0.5882352941176471D);
+
+        int i = 0;
+        for (int xx = 0; xx < xSize; xx++) {
+            for (int zz = 0; zz < zSize; zz++) {
+                final double a = noises[i] * 1.1 + 0.5;
+                final double b = 0.01;
+                final double c = 1.0 - b;
+                double temperature = (temperatures[i] * 0.15 + 0.7) * c + a * b;
+                temperature = 1.0 - (1.0 - temperature) * (1.0 - temperature);
+
+                if (temperature < 0.0) {
+                    temperature = 0.0;
+                }
+                if (temperature > 1.0) {
+                    temperature = 1.0;
+                }
+
+                temperatures[i++] = temperature;
+            }
+        }
+
+        return temperatures;
+    }
+
+    @Override
+    public double[] getHumidities(double[] humidities, final int x, final int z, final int xSize, final int zSize) {
+        if (humidities == null || humidities.length < xSize * zSize) {
+            humidities = new double[xSize * zSize];
+        }
+
+        return this.downfallMap.getValue(humidities, x, z, xSize, zSize, 0.05, 0.05, 0.5);
+    }
+
+    @Override
+    public double[] getVarieties(double[] varieties, final int x, final int z, final int xSize, final int zSize) {
+        if (varieties == null || varieties.length < xSize * zSize) {
+            varieties = new double[xSize * zSize];
+        }
+
+        Arrays.fill(varieties, 0.0);
+
+        return varieties;
+    }
+
+    @Override
+    public double[] getBiomenesses(double[] biomenesses, final int x, final int y, final int z, final int xSize, final int ySize, final int zSize) {
+        if (biomenesses == null || biomenesses.length < xSize * ySize * zSize) {
+            biomenesses = new double[xSize * ySize * zSize];
+        }
+
+        Arrays.fill(biomenesses, 1.0);
+
+        return biomenesses;
+    }
+
+    @Override
+    public Biome lookupBiome(final double temperature, double humidity, final double altitude, final double variety) {
+        humidity *= temperature;
+
+        if (temperature < 0.1) {
+            return Biomes.OVERWORLD_LEGACY_TUNDRA;
+        } else if (humidity < 0.2) {
+            if (temperature < 0.5) {
+                return Biomes.OVERWORLD_LEGACY_TUNDRA;
+            } else {
+                return temperature < 0.95 ? Biomes.OVERWORLD_LEGACY_SAVANNA : Biomes.OVERWORLD_LEGACY_DESERT;
+            }
+        } else if (humidity > 0.5 && temperature < 0.7) {
+            return Biomes.OVERWORLD_LEGACY_SWAMPLAND;
+        } else if (temperature < 0.5) {
+            return Biomes.OVERWORLD_LEGACY_TAIGA;
+        } else if (temperature < 0.97) {
+            return humidity < 0.35 ? Biomes.OVERWORLD_LEGACY_SHRUBLAND : Biomes.OVERWORLD_LEGACY_FOREST;
+        } else if (humidity < 0.45) {
+            return Biomes.OVERWORLD_LEGACY_PLAINS;
+        } else {
+            return humidity < 0.9 ? Biomes.OVERWORLD_LEGACY_SEASONAL_FOREST : Biomes.OVERWORLD_LEGACY_RAINFOREST;
+        }
+    }
+}
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 db17755be..9635a88d9 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
@@ -55,16 +55,19 @@ public final class BiomeProviderNether
         }
         if (temperatures == null || temperatures.length < xSize * zSize)
         {
-            temperatures = getTemperatures(temperatures, x, z, xSize, zSize);
+            temperatures = new double[xSize * zSize];
         }
+        getTemperatures(temperatures, x, z, xSize, zSize);
         if (humidities == null || humidities.length < xSize * zSize)
         {
-            humidities = getHumidities(humidities, x, z, xSize, zSize);
+            humidities = new double[xSize * zSize];
         }
+        getHumidities(humidities, x, z, xSize, zSize);
         if (varieties == null || varieties.length < xSize * zSize)
         {
-            varieties = getVarieties(varieties, x, z, xSize, zSize);
+            varieties = new double[xSize * zSize];
         }
+        getVarieties(varieties, x, z, xSize, zSize);
 
         for (int dx = 0; dx < xSize; dx++)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
index 61c5dc3a1..8affa5997 100644
--- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java
@@ -91,16 +91,19 @@ public final class BiomeProviderOverworld
         }
         if (temperatures == null || temperatures.length < xSize * zSize)
         {
-            temperatures = getTemperatures(temperatures, x, z, xSize, zSize);
+            temperatures = new double[xSize * zSize];
         }
+        getTemperatures(temperatures, x, z, xSize, zSize);
         if (humidities == null || humidities.length < xSize * zSize)
         {
-            humidities = getHumidities(humidities, x, z, xSize, zSize);
+            humidities = new double[xSize * zSize];
         }
+        getHumidities(humidities, x, z, xSize, zSize);
         if (varieties == null || varieties.length < xSize * zSize)
         {
-            varieties = getVarieties(varieties, x, z, xSize, zSize);
+            varieties = new double[xSize * zSize];
         }
+        getVarieties(varieties, x, z, xSize, zSize);
 
         for (int dx = 0; dx < xSize; dx++)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/LargeFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/LargeFeature.java
index fc15fb1e5..18434c87f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/LargeFeature.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/LargeFeature.java
@@ -29,7 +29,6 @@ public class LargeFeature
             }
 
         }
-
     }
 
     protected void doGeneration(World world, int chunkX, int chunkZ, int baseChunkX, int baseChunkZ, ChunkGeneratorResult result)
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
new file mode 100644
index 000000000..90928c9f6
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java
@@ -0,0 +1,239 @@
+package net.minecraft.core.world.generate;
+
+import net.minecraft.core.block.Blocks;
+import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.chunk.ChunkSection;
+import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult;
+
+import java.util.Random;
+
+public class RetroCavesLargeFeature extends LargeFeature {
+    private Random rand;
+    private final int minY;
+    private final int maxY;
+
+    public RetroCavesLargeFeature() {
+        this(0, Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y);
+    }
+
+    public RetroCavesLargeFeature(int minY, int maxY) {
+        this.minY = minY;
+        this.maxY = maxY;
+        this.rand = new Random();
+    }
+
+    @Override
+    public void generate(World world, int baseChunkX, int baseChunkZ, ChunkGeneratorResult result)
+    {
+        int radius = radiusChunk;
+        rand.setSeed(world.getRandomSeed());
+        worldObj = world;
+        long randX = (this.rand.nextLong() / 2L) * 2L + 1L;
+        long randZ = (this.rand.nextLong() / 2L) * 2L + 1L;
+        for(int chunkX = baseChunkX - radius; chunkX <= baseChunkX + radius; chunkX++)
+        {
+            for(int chunkZ = baseChunkZ - radius; chunkZ <= baseChunkZ + radius; chunkZ++)
+            {
+                this.rand.setSeed((long)chunkX * randX + (long)chunkZ * randZ ^ world.getRandomSeed());
+                doGeneration(world, chunkX, chunkZ, baseChunkX, baseChunkZ, result);
+            }
+
+        }
+    }
+
+    protected void generateHubRoom(int baseChunkX, int baseChunkZ, ChunkGeneratorResult result, double blockX, double blockY, double blockZ) {
+        generateCave(baseChunkX, baseChunkZ, result, blockX, blockY, blockZ, 1.0F + this.rand.nextFloat() * 6F, 0.0F, 0.0F, -1, -1, 0.5D);
+    }
+
+    protected void generateCave(int baseChunkX, int baseChunkZ, ChunkGeneratorResult result, double blockX, double blockY,
+                                double blockZ, float initialRadius, float yRot, float xRot, int startPos, int endPos,
+                                double heightMod) {
+        double chunkMiddleX = baseChunkX * Chunk.CHUNK_SIZE_X + Chunk.CHUNK_SIZE_X / 2;
+        double chunkMiddleZ = baseChunkZ * Chunk.CHUNK_SIZE_Z + Chunk.CHUNK_SIZE_Z / 2;
+        float rotHorOffset = 0.0F;
+        float rotVerOffset = 0.0F;
+        Random random = new Random(this.rand.nextLong());
+        if (endPos <= 0) {
+            int maxLength = radiusChunk * 16 - 16;
+            endPos = maxLength - random.nextInt(maxLength / 4);
+        }
+        boolean noBranches = false;
+        if (startPos == -1) {
+            startPos = endPos / 2;
+            noBranches = true;
+        }
+        int branchPos = random.nextInt(endPos / 2) + endPos / 4;
+        boolean sharpRotVer = random.nextInt(6) == 0;
+        for (; startPos < endPos; startPos++) {
+            double width = 1.5D + (MathHelper.sin((startPos * MathHelper.PI) / endPos) * initialRadius * 1.0F);
+            double height = width * heightMod;
+            float xzScale = MathHelper.cos(xRot);
+            float yOffset = MathHelper.sin(xRot);
+            blockX += MathHelper.cos(yRot) * xzScale;
+            blockY += yOffset;
+            blockZ += MathHelper.sin(yRot) * xzScale;
+            if (sharpRotVer) {
+                xRot *= 0.92F;
+            } else {
+                xRot *= 0.7F;
+            }
+            xRot += rotVerOffset * 0.1F;
+            yRot += rotHorOffset * 0.1F;
+            rotVerOffset *= 0.9F;
+            rotHorOffset *= 0.75F;
+            rotVerOffset += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2.0F;
+            rotHorOffset += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4F;
+
+            // Do adjacent branches if necessary
+            if (!noBranches && startPos == branchPos && initialRadius > 1.0F) {
+                generateCave(baseChunkX, baseChunkZ, result, blockX, blockY, blockZ, random.nextFloat() * 0.5F + 0.5F, yRot - MathHelper.PI / 2F, xRot / 3F, startPos, endPos, 1.0D);
+                generateCave(baseChunkX, baseChunkZ, result, blockX, blockY, blockZ, random.nextFloat() * 0.5F + 0.5F, yRot + MathHelper.PI / 2F, xRot / 3F, startPos, endPos, 1.0D);
+                return;
+            }
+
+            // Randomly skip a section
+            if (!noBranches && random.nextInt(4) == 0) {
+                continue;
+            }
+
+            // Check if we've gone far enough, and stop if so
+            double dxFromMiddle = blockX - chunkMiddleX;
+            double dzFromMiddle = blockZ - chunkMiddleZ;
+            double length = endPos - startPos;
+            double maxRadius = initialRadius + 2.0F + 16F;
+            if ((dxFromMiddle * dxFromMiddle + dzFromMiddle * dzFromMiddle) - length * length > maxRadius * maxRadius) {
+                return;
+            }
+            if (blockX < chunkMiddleX - Chunk.CHUNK_SIZE_X - width * 2D || blockZ < chunkMiddleZ - Chunk.CHUNK_SIZE_Z - width * 2D || blockX > chunkMiddleX + Chunk.CHUNK_SIZE_X + width * 2D || blockZ > chunkMiddleZ + Chunk.CHUNK_SIZE_Z + width * 2D) {
+                continue;
+            }
+
+            // Determine sizes of current section
+            int minX = MathHelper.floor(blockX - width) - baseChunkX * Chunk.CHUNK_SIZE_X - 1;
+            int maxX = (MathHelper.floor(blockX + width) - baseChunkX * Chunk.CHUNK_SIZE_X) + 1;
+            int minY = MathHelper.floor(blockY - height) - 1;
+            int maxY = MathHelper.floor(blockY + height) + 1;
+            int minZ = MathHelper.floor(blockZ - width) - baseChunkZ * Chunk.CHUNK_SIZE_Z - 1;
+            int maxZ = (MathHelper.floor(blockZ + width) - baseChunkZ * Chunk.CHUNK_SIZE_Z) + 1;
+            if (minX < 0) {
+                minX = 0;
+            }
+            if (maxX > Chunk.CHUNK_SIZE_X) {
+                maxX = Chunk.CHUNK_SIZE_X;
+            }
+            if (minY < this.minY + 1) {
+                minY = this.minY + 1;
+            }
+            if (maxY > this.maxY - (ChunkSection.SECTION_SIZE_Y / 2)) {
+                maxY = this.maxY - (ChunkSection.SECTION_SIZE_Y / 2);
+            }
+            if (minZ < 0) {
+                minZ = 0;
+            }
+            if (maxZ > Chunk.CHUNK_SIZE_Z) {
+                maxZ = Chunk.CHUNK_SIZE_Z;
+            }
+
+            // Check if we've hit the ocean, and if so, stop generating
+            if (worldObj.getWorldType().getOceanBlockId() != 0) {
+                boolean hasHitOcean = false;
+                for (int x = minX; !hasHitOcean && x < maxX; x++) {
+                    for (int z = minZ; !hasHitOcean && z < maxZ; z++) {
+                        for (int y = maxY + 1; !hasHitOcean && y >= minY - 1; y--) {
+                            int blockId = result.getBlock(x, y, z);
+
+                            if (y < this.minY || y >= this.maxY) {
+                                continue;
+                            }
+                            if (blockId == worldObj.getWorldType().getOceanBlockId()) {
+                                hasHitOcean = true;
+                            }
+                            if (y != minY - 1 && x != minX && x != maxX - 1 && z != minZ && z != maxZ - 1) {
+                                y = minY;
+                            }
+                        }
+                    }
+                }
+                if (hasHitOcean) {
+                    continue;
+                }
+            }
+
+            // Delete blocks in section
+            for (int x = minX; x < maxX; x++) {
+                double xPercentage = (((x + baseChunkX * Chunk.CHUNK_SIZE_X) + 0.5D) - blockX) / width;
+                for (int z = minZ; z < maxZ; z++) {
+                    double zPercentage = (((z + baseChunkZ * Chunk.CHUNK_SIZE_Z) + 0.5D) - blockZ) / width;
+                    int yIndex = maxY;
+                    boolean replaceTopBlock = false;
+                    if (xPercentage * xPercentage + zPercentage * zPercentage < 1.0D) {
+                        for (int y = maxY - 1; y >= minY; y--) {
+                            double yPercentage = ((y + 0.5D) - blockY) / height;
+                            if (yPercentage > -0.7D && xPercentage * xPercentage + yPercentage * yPercentage + zPercentage * zPercentage < 1.0D) {
+                                int blockId = result.getBlock(x, yIndex, z);
+                                if (Blocks.hasTag(blockId, BlockTags.CAVE_GEN_REPLACES_SURFACE)) {
+                                    replaceTopBlock = true;
+                                }
+                                if (blockId == Blocks.STONE.id() || blockId == Blocks.DIRT.id() || blockId == Blocks.GRASS.id()) {
+                                    if (y < 10) {
+                                        result.setBlock(x, yIndex, z, Blocks.FLUID_LAVA_STILL.id());
+                                    } else {
+                                        result.setBlock(x, yIndex, z, 0);
+
+                                        if (replaceTopBlock) {
+                                            Biome biome = worldObj.getBlockBiome(x, yIndex - 1, z);
+                                            int topBlockId = biome.topBlock;
+                                            int fillBlockId = biome.fillerBlock;
+                                            int id = result.getBlock(x, yIndex - 1, z);
+                                            if (id == fillBlockId) {
+                                                result.setBlock(x, yIndex - 1, z, topBlockId);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+
+                            yIndex--;
+                        }
+                    }
+                }
+            }
+
+            if (noBranches) {
+                break;
+            }
+        }
+    }
+
+    @Override
+    protected void doGeneration(World world, int chunkX, int chunkZ, int baseChunkX, int baseChunkZ, ChunkGeneratorResult result) {
+        int cavesToGenerate = rand.nextInt(rand.nextInt(rand.nextInt(40) + 1) + 1);
+        if (this.rand.nextInt(15) != 0) {
+            cavesToGenerate = 0;
+        }
+
+        final int yRange = maxY - minY;
+
+        for (int i = 0; i < cavesToGenerate; i++) {
+            double blockX = chunkX * Chunk.CHUNK_SIZE_X + this.rand.nextInt(Chunk.CHUNK_SIZE_X);
+            double blockY = minY + this.rand.nextInt(this.rand.nextInt(yRange - (ChunkSection.SECTION_SIZE_Y / 2)) + (ChunkSection.SECTION_SIZE_Y / 2));
+            double blockZ = chunkZ * Chunk.CHUNK_SIZE_Z + this.rand.nextInt(Chunk.CHUNK_SIZE_Z);
+
+            int numBranches = 1;
+            if (rand.nextInt(4) == 0) {
+                generateHubRoom(baseChunkX, baseChunkZ, result, blockX, blockY, blockZ);
+                numBranches += rand.nextInt(4);
+            }
+            for (int l1 = 0; l1 < numBranches; l1++) {
+                float yRot = this.rand.nextFloat() * MathHelper.PI * 2.0F; // 0 - 2Pi
+                float xRot = ((this.rand.nextFloat() - 0.5F) * 2.0F) / 8F; // -0.125 - 0.125
+                float initialRadius = this.rand.nextFloat() * 2.0F + this.rand.nextFloat(); // 0 - 3
+                generateCave(baseChunkX, baseChunkZ, result, blockX, blockY, blockZ, initialRadius, yRot, xRot, 0, 0, 1.0f);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/ChunkGeneratorParadise.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/ChunkGeneratorDrift.java
similarity index 66%
rename from game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/ChunkGeneratorParadise.java
rename to game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/ChunkGeneratorDrift.java
index ec6e5c2b8..aaf56a65f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/ChunkGeneratorParadise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/ChunkGeneratorDrift.java
@@ -1,4 +1,4 @@
-package net.minecraft.core.world.generate.chunk.perlin.paradise;
+package net.minecraft.core.world.generate.chunk.perlin.drift;
 
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.generate.CavesLargeFeature;
@@ -7,11 +7,11 @@ import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.ChunkDecoratorOverworld;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld;
 
-public class ChunkGeneratorParadise
+public class ChunkGeneratorDrift
     extends ChunkGeneratorPerlin
 {
-    public ChunkGeneratorParadise(World world)
+    public ChunkGeneratorDrift(World world)
     {
-        super(world, new ChunkDecoratorOverworld(world), new TerrainGeneratorParadise(world), new SurfaceGeneratorOverworld(world), new LargeFeature[] { new CavesLargeFeature() });
+        super(world, new ChunkDecoratorOverworld(world), new TerrainGeneratorDrift(world), new SurfaceGeneratorOverworld(world), new LargeFeature[] { new CavesLargeFeature() });
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/DensityGeneratorParadise.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
similarity index 97%
rename from game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/DensityGeneratorParadise.java
rename to game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
index 99e5c9882..8e3b726d9 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/DensityGeneratorParadise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
@@ -1,11 +1,11 @@
-package net.minecraft.core.world.generate.chunk.perlin.paradise;
+package net.minecraft.core.world.generate.chunk.perlin.drift;
 
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
 import net.minecraft.core.world.noise.PerlinNoise;
 
-public class DensityGeneratorParadise
+public class DensityGeneratorDrift
     implements DensityGenerator
 {
     private final World world;
@@ -16,7 +16,7 @@ public class DensityGeneratorParadise
 //    private final PerlinNoise scaleNoise;
 //    private final PerlinNoise depthNoise;
 
-    public DensityGeneratorParadise(World world)
+    public DensityGeneratorDrift(World world)
     {
         this.world = world;
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/TerrainGeneratorParadise.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/TerrainGeneratorDrift.java
similarity index 77%
rename from game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/TerrainGeneratorParadise.java
rename to game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/TerrainGeneratorDrift.java
index 79f38ccdd..ae40b5199 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/paradise/TerrainGeneratorParadise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/TerrainGeneratorDrift.java
@@ -1,4 +1,4 @@
-package net.minecraft.core.world.generate.chunk.perlin.paradise;
+package net.minecraft.core.world.generate.chunk.perlin.drift;
 
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.Chunk;
@@ -6,16 +6,16 @@ import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
 import net.minecraft.core.world.generate.chunk.perlin.TerrainGeneratorLerp;
 import net.minecraft.core.world.type.WorldType;
 
-public class TerrainGeneratorParadise
+public class TerrainGeneratorDrift
     extends TerrainGeneratorLerp
 {
     private final DensityGenerator densityGenerator;
 
-    public TerrainGeneratorParadise(World world)
+    public TerrainGeneratorDrift(World world)
     {
         super(world);
 
-        this.densityGenerator = new DensityGeneratorParadise(world);
+        this.densityGenerator = new DensityGeneratorDrift(world);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkGeneratorNether.java
index 533a57c14..087267360 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkGeneratorNether.java
@@ -17,9 +17,9 @@ public class ChunkGeneratorNether
             new SurfaceGeneratorNether(world),
             new LargeFeature[]
                 {
-                    new CavesLargeFeature(128, 256),
+                    new CavesLargeFeature(64, 256),
                     new WarrensCavesLargeFeature(0, 128),
-                    new NetherBonesLargeFeature(128, 256)
+                    new NetherBonesLargeFeature(64, 256)
                 }
         );
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
index a709f569e..bb68f8bda 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
@@ -59,11 +59,11 @@ public class DensityGeneratorNether
         this.poolNoiseUnder = new PerlinSimplexNoise(rand, 1);
 
         densityGeneratorMap.put(Biomes.NETHER_NETHER, this::generateDensityMapBiomeNether);
-        densityGeneratorMap.put(Biomes.NETHER_VOLCANIC_ISLANDS, this::generateDensityMapBiomeVolcanicIslands);
-        densityGeneratorMap.put(Biomes.NETHER_SULFUR_POOLS, this::generateDensityMapBiomeSulphurPools);
-        densityGeneratorMap.put(Biomes.NETHER_CRYSTAL_FOREST, this::generateDensityMapOcean);
-        densityGeneratorMap.put(Biomes.NETHER_ASH_PLAINS, this::generateDensityMapBiomeTest);
-        densityGeneratorMap.put(Biomes.NETHER_BONEYARD, this::generateDensityMapBiomeTest);
+        densityGeneratorMap.put(Biomes.NETHER_VOLCANIC_ISLANDS, this::generateDensityMapBiomeNether);
+        densityGeneratorMap.put(Biomes.NETHER_SULFUR_POOLS, this::generateDensityMapBiomeNether);
+        densityGeneratorMap.put(Biomes.NETHER_CRYSTAL_FOREST, this::generateDensityMapBiomeNether);
+        densityGeneratorMap.put(Biomes.NETHER_ASH_PLAINS, this::generateDensityMapBiomeNether);
+        densityGeneratorMap.put(Biomes.NETHER_BONEYARD, this::generateDensityMapBiomeNether);
     }
 
     @Override
@@ -79,7 +79,8 @@ public class DensityGeneratorNether
         int y = 0;
         int z = chunk.zPosition * 4;
 
-        int halfYSize = ((terrainHeight / 2) / 8) + 1;
+        int quarterYSize = ((terrainHeight / 4) / 8) + 1;
+        int threeQuarterYSize = ((int) (terrainHeight * 0.75f) / 8) + 1;
 
         double[] densityMapArray = new double[xSize * ySize * zSize];
         Map<Biome, double[]> perBiomeDensityMaps = new HashMap<>();
@@ -98,11 +99,11 @@ public class DensityGeneratorNether
                 biomeProvider.getOverlap(temperature, overlapPair);
 
                 if (!perBiomeDensityMaps.containsKey(overlapPair.biomeA)) {
-                    perBiomeDensityMaps.put(overlapPair.biomeA, densityGeneratorMap.get(overlapPair.biomeA).generateDensityMap(chunk, terrainHeight / 2, xSize, halfYSize, zSize, x, y, z));
+                    perBiomeDensityMaps.put(overlapPair.biomeA, densityGeneratorMap.get(overlapPair.biomeA).generateDensityMap(chunk, (int) (terrainHeight * 0.75f), xSize, threeQuarterYSize, zSize, x, y, z));
                 }
                 if (overlapPair.hasOverlap) {
                     if (!perBiomeDensityMaps.containsKey(overlapPair.biomeB)) {
-                        perBiomeDensityMaps.put(overlapPair.biomeB, densityGeneratorMap.get(overlapPair.biomeB).generateDensityMap(chunk, terrainHeight / 2, xSize, halfYSize, zSize, x, y, z));
+                        perBiomeDensityMaps.put(overlapPair.biomeB, densityGeneratorMap.get(overlapPair.biomeB).generateDensityMap(chunk, (int) (terrainHeight * 0.75f), xSize, threeQuarterYSize, zSize, x, y, z));
                     }
                 }
             }
@@ -119,15 +120,15 @@ public class DensityGeneratorNether
                 }
 
                 if (densityMapB != null) {
-                    for (int dy = 0; dy < halfYSize; dy++) {
-                        double densityA = densityMapA[(dx * zSize * halfYSize) + (dz * halfYSize) + dy];
-                        double densityB = densityMapB[(dx * zSize * halfYSize) + (dz * halfYSize) + dy];
-                        densityMapArray[(dx * zSize * ySize) + (dz * ySize) + (dy + halfYSize - 1)] = MathHelper.lerp(densityA, densityB, overlapPair.biomeBPercentage);
+                    for (int dy = 0; dy < threeQuarterYSize; dy++) {
+                        double densityA = densityMapA[(dx * zSize * threeQuarterYSize) + (dz * threeQuarterYSize) + dy];
+                        double densityB = densityMapB[(dx * zSize * threeQuarterYSize) + (dz * threeQuarterYSize) + dy];
+                        densityMapArray[(dx * zSize * ySize) + (dz * ySize) + (dy + quarterYSize - 1)] = MathHelper.lerp(densityA, densityB, overlapPair.biomeBPercentage);
                     }
                 } else {
-                    for (int dy = 0; dy < halfYSize; dy++) {
-                        double densityA = densityMapA[(dx * zSize * halfYSize) + (dz * halfYSize) + dy];
-                        densityMapArray[(dx * zSize * ySize) + (dz * ySize) + (dy + halfYSize - 1)] = densityA;
+                    for (int dy = 0; dy < threeQuarterYSize; dy++) {
+                        double densityA = densityMapA[(dx * zSize * threeQuarterYSize) + (dz * threeQuarterYSize) + dy];
+                        densityMapArray[(dx * zSize * ySize) + (dz * ySize) + (dy + quarterYSize - 1)] = densityA;
                     }
                 }
             }
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 03772c650..648d7f637 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,9 +5,12 @@ 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.chunk.ChunkSection;
 import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator;
 import net.minecraft.core.world.generate.chunk.perlin.TerrainGeneratorLerp;
+import net.minecraft.core.world.noise.PerlinNoise;
 import net.minecraft.core.world.type.WorldType;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -17,14 +20,18 @@ public class TerrainGeneratorNether
 {
     private final DensityGenerator densityGenerator;
 
-    private int lastX = -1;
-    private int lastZ = -1;
+    private int lastX = Integer.MIN_VALUE;
+    private int lastZ = Integer.MIN_VALUE;
     private Biome lastBiome = null;
     private Biome lastBiomeNegX = null;
     private Biome lastBiomePosX = null;
     private Biome lastBiomeNegZ = null;
     private Biome lastBiomePosZ = null;
     private Map<Biome, Integer> fluidLookup = new HashMap<>();
+    private int lastChunkX = Integer.MIN_VALUE;
+    private int lastChunkZ = Integer.MIN_VALUE;
+    private final @NotNull PerlinNoise noise = new PerlinNoise(0L, 4, 0);
+    private final double @NotNull [] cache = new double[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z * (Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y)];
 
     public TerrainGeneratorNether(World world)
     {
@@ -66,11 +73,23 @@ public class TerrainGeneratorNether
                 lastBiomePosZ = chunk.getBlockBiome(x, 0, z + 1);
             }
         }
+        if (lastChunkX != chunk.xPosition || lastChunkZ != chunk.zPosition) {
+            lastChunkX = chunk.xPosition;
+            lastChunkZ = chunk.zPosition;
+            noise.get(cache, chunk.xPosition * Chunk.CHUNK_SIZE_X, 0, chunk.zPosition * Chunk.CHUNK_SIZE_Z, Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, 0.2, 0.2, 0.2);
+
+            float avg = 0;
+            for (int i = 0; i < cache.length; i++) {
+                avg += cache[i];
+            }
+            avg /= cache.length;
+            System.out.println("avg: " + avg);
+        }
 
         WorldType type = world.getWorldType();
-        int halfHeight = type.getMaxY() / 2;
+        int quarterHeight = type.getMaxY() / 4;
 
-        if (y < halfHeight)
+        if (y < quarterHeight)
         {
             return 0;
         }
@@ -78,7 +97,7 @@ public class TerrainGeneratorNether
         {
             return Blocks.BEDROCK.id();
         }
-//        else if (y >= halfHeight - rand.nextInt(5) && y <= halfHeight + 5 - rand.nextInt(5))
+//        else if (y >= quarterHeight - rand.nextInt(5) && y <= quarterHeight + 5 - rand.nextInt(5))
 //        {
 //            return Blocks.BEDROCK.id();
 //        }
@@ -86,19 +105,29 @@ public class TerrainGeneratorNether
 //        {
 //            return Blocks.BEDROCK.id();
 //        }
-//        else if (y <= halfHeight)
+//        else if (y <= quarterHeight)
 //        {
 //            return Blocks.SOULSCHIST.id();
 //        }
-        else if (y <= halfHeight + rand.nextInt(5))
+        else if (y <= quarterHeight + rand.nextInt(5))
         {
             return Blocks.BEDROCK.id();
         }
         else if (density > 0.0)
         {
+            if (lastBiome == Biomes.NETHER_CRYSTAL_FOREST) {
+                int sizeY = Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y;
+                // YZX ordering
+                final double d = ((cache[(x * Chunk.CHUNK_SIZE_Z * sizeY) + (z * sizeY) + y]));
+                if (d > 0 && d < 2) {
+                    return Blocks.CRYSTAL.id();
+                } else if (d > -1 && d < 3) {
+                    return Blocks.COBBLE_NETHERRACK_MOSSY.id();
+                }
+            }
             return type.getFillerBlockId();
         }
-        else if (y >= halfHeight && y < type.getOceanY())
+        else if (y >= quarterHeight && y < type.getOceanY())
         {
             int biomeFluid = fluidLookup.getOrDefault(lastBiome, 0);
             int biomeFluidNegX = fluidLookup.getOrDefault(lastBiomeNegX, 0);
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
new file mode 100644
index 000000000..432c9a201
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
@@ -0,0 +1,321 @@
+package net.minecraft.core.world.generate.chunk.perlin.overworld.b173;
+
+import net.minecraft.core.block.BlockLogicSand;
+import net.minecraft.core.block.Blocks;
+import net.minecraft.core.block.material.Material;
+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.ChunkDecorator;
+import net.minecraft.core.world.generate.feature.*;
+import net.minecraft.core.world.noise.PerlinNoise;
+import net.minecraft.core.world.type.WorldTypes;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public class ChunkDecoratorOverworldB173
+    implements ChunkDecorator
+{
+    private final @NotNull World world;
+    private final @NotNull PerlinNoise forestNoise;
+
+    public ChunkDecoratorOverworldB173(final @NotNull World world) {
+        this.world = world;
+
+        this.forestNoise = new PerlinNoise(world.getRandomSeed(), 8, 82);
+    }
+
+    @Override
+    public void decorate(final Chunk chunk) {
+        this.world.scheduledUpdatesAreImmediate = true;
+        BlockLogicSand.fallInstantly = true;
+
+        final int x = chunk.xPosition;
+        final int z = chunk.zPosition;
+
+        final int minY = this.world.getWorldType().getMinY();
+        final int maxY = this.world.getWorldType().getMaxY();
+        final int rangeY = (maxY + 1) - minY;
+
+        final int wx = x * 16;
+        final int wz = z * 16;
+
+        final @NotNull Biome biome = this.world.getBlockBiome(wx, 0, wz);
+
+        final @NotNull Random rand = new Random(this.world.getRandomSeed());
+
+        final long rx = rand.nextLong() / 2L * 2L + 1L;
+        final long rz = rand.nextLong() / 2L * 2L + 1L;
+
+        rand.setSeed(rx * x + rz * z ^ this.world.getRandomSeed());
+
+        if (rand.nextInt(4) == 0) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureLake(Blocks.FLUID_WATER_STILL.id()).place(this.world, rand, fx, fy, fz);
+        }
+
+        if (rand.nextInt(8) == 0) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            if (fy < rangeY / 2 || rand.nextInt(10) == 0) {
+                new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id()).place(this.world, rand, fx, fy, fz);
+            }
+        }
+
+        for (int i = 0; i < 8; i++) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureDungeon(Blocks.COBBLE_STONE.id(), Blocks.COBBLE_STONE_MOSSY.id(), null).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 10; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureClay(32).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 20; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureOre(Blocks.DIRT.id(), 32).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 10; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureOre(Blocks.GRAVEL.id(), 32).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 20; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureOre(Blocks.ORE_COAL_STONE.id(), 16).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 20; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY / 2);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureOre(Blocks.ORE_IRON_STONE.id(), 8).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 2; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY / 4);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureOre(Blocks.ORE_GOLD_STONE.id(), 8).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 8; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY / 8);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureOre(Blocks.ORE_REDSTONE_STONE.id(), 7).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 1; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY / 16);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureOre(Blocks.ORE_DIAMOND_STONE.id(), 7).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 1; i++) {
+            final int fx = wx + rand.nextInt(16);
+            final int fy = rand.nextInt(rangeY / 16) + rand.nextInt(rangeY / 16);
+            final int fz = wz + rand.nextInt(16);
+            new WorldFeatureOre(Blocks.ORE_LAPIS_STONE.id(), 6).place(this.world, rand, fx, fy, fz);
+        }
+
+        final double forestNoiseScale = 0.5;
+        final int forestNoiseValue = (int) ((this.forestNoise.get(wx * forestNoiseScale, wz * forestNoiseScale) / 8.0 + rand.nextDouble() * 4.0 + 4.0) / 3.0);
+        int numTrees = 0;
+
+        if (rand.nextInt(10) == 0) {
+            numTrees++;
+        }
+
+        if (biome == Biomes.OVERWORLD_LEGACY_FOREST) {
+            numTrees += forestNoiseValue + 5;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_RAINFOREST) {
+            numTrees += forestNoiseValue + 5;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_SEASONAL_FOREST) {
+            numTrees += forestNoiseValue + 2;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_TAIGA) {
+            numTrees += forestNoiseValue + 5;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_DESERT) {
+            numTrees -= 20;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_TUNDRA) {
+            numTrees -= 20;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_PLAINS) {
+            numTrees -= 20;
+        }
+
+        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);
+            feature.init(1.0, 1.0, 1.0);
+            biome.getRandomWorldGenForTrees(rand).place(this.world, rand, fx, this.world.getHeightValue(fx, fz), fz);
+        }
+
+        int numYellowFlowers = 0;
+        if (biome == Biomes.OVERWORLD_LEGACY_FOREST) {
+            numYellowFlowers += 2;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_SEASONAL_FOREST) {
+            numYellowFlowers += 4;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_TAIGA) {
+            numYellowFlowers += 2;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_PLAINS) {
+            numYellowFlowers += 3;
+        }
+
+        for (int i = 0; i < numYellowFlowers; i++) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureFlowers(Blocks.FLOWER_YELLOW.id(), 64, false).place(this.world, rand, fx, fy, fz);
+        }
+
+        int numPlants = 0;
+        if (biome == Biomes.OVERWORLD_LEGACY_FOREST) {
+            numPlants += 2;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_RAINFOREST) {
+            numPlants += 10;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_SEASONAL_FOREST) {
+            numPlants += 2;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_TAIGA) {
+            numPlants += 1;
+        }
+        if (biome == Biomes.OVERWORLD_LEGACY_PLAINS) {
+            numPlants += 10;
+        }
+
+        for (int i = 0; i < numPlants; i++) {
+            int plantBlockId = Blocks.TALLGRASS.id();
+            if (biome == Biomes.OVERWORLD_LEGACY_RAINFOREST && rand.nextInt(3) != 0) {
+                plantBlockId = Blocks.TALLGRASS_FERN.id();
+            }
+
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureTallGrass(plantBlockId).place(this.world, rand, fx, fy, fz);
+        }
+
+        int numDeadBushes = 0;
+        if (biome == Biomes.OVERWORLD_LEGACY_DESERT) {
+            numDeadBushes += 2;
+        }
+
+        for (int i = 0; i < numDeadBushes; i++) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureDeadBush(Blocks.DEADBUSH.id()).place(this.world, rand, fx, fy, fz);
+        }
+
+        if (rand.nextInt(2) == 0) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureFlowers(Blocks.FLOWER_RED.id(), 64, false).place(this.world, rand, fx, fy, fz);
+        }
+
+        if (rand.nextInt(4) == 0) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureFlowers(Blocks.MUSHROOM_BROWN.id(), 64, false).place(this.world, rand, fx, fy, fz);
+        }
+
+        if (rand.nextInt(8) == 0) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureFlowers(Blocks.MUSHROOM_RED.id(), 64, false).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 10; i++) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureSugarCane().place(this.world, rand, fx, fy, fz);
+        }
+
+        if (rand.nextInt(32) == 0) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeaturePumpkin().place(this.world, rand, fx, fy, fz);
+        }
+
+        int numCacti = 0;
+        if (biome == Biomes.OVERWORLD_LEGACY_DESERT) {
+            numCacti += 10;
+        }
+
+        for (int i = 0; i < numCacti; i++) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureCactus().place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 50; i++) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureLiquid(Blocks.FLUID_WATER_FLOWING.id()).place(this.world, rand, fx, fy, fz);
+        }
+
+        for (int i = 0; i < 20; i++) {
+            final int fx = wx + rand.nextInt(16) + 8;
+            final int fy = rand.nextInt(rangeY);
+            final int fz = wz + rand.nextInt(16) + 8;
+            new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id()).place(this.world, rand, fx, fy, fz);
+        }
+
+        final int oceanY = this.world.getWorldType().getOceanY();
+        for(int xx = x + 8; xx < x + 8 + 16; xx++) {
+            for(int zz = z + 8; zz < z + 8 + 16; zz++) {
+                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 (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.hasSurfaceSnow() && (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());
+                }
+            }
+        }
+
+        BlockLogicSand.fallInstantly = false;
+        this.world.scheduledUpdatesAreImmediate = false;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkGeneratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkGeneratorOverworldB173.java
new file mode 100644
index 000000000..47f280c6e
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkGeneratorOverworldB173.java
@@ -0,0 +1,20 @@
+package net.minecraft.core.world.generate.chunk.perlin.overworld.b173;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.generate.CavesLargeFeature;
+import net.minecraft.core.world.generate.LargeFeature;
+import net.minecraft.core.world.generate.RetroCavesLargeFeature;
+import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin;
+
+public class ChunkGeneratorOverworldB173
+    extends ChunkGeneratorPerlin
+{
+    public ChunkGeneratorOverworldB173(World world) {
+        super(world,
+              new ChunkDecoratorOverworldB173(world),
+              new TerrainGeneratorOverworldB173(world),
+              new SurfaceGeneratorOverworldB173(world),
+              new LargeFeature[] { new RetroCavesLargeFeature(world.getWorldType().getMinY(), world.getWorldType().getMaxY() + 1) }
+        );
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/DensityGeneratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/DensityGeneratorOverworldB173.java
new file mode 100644
index 000000000..1d8d47db3
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/DensityGeneratorOverworldB173.java
@@ -0,0 +1,21 @@
+package net.minecraft.core.world.generate.chunk.perlin.overworld.b173;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.generate.chunk.perlin.overworld.DensityGeneratorOverworld;
+import net.minecraft.core.world.noise.BetaPerlinNoise;
+
+public class DensityGeneratorOverworldB173
+    extends DensityGeneratorOverworld
+{
+
+    public DensityGeneratorOverworldB173(final World world) {
+        super(world,
+            new BetaPerlinNoise(world.getRandomSeed(), 16, 0),
+            new BetaPerlinNoise(world.getRandomSeed(), 16, 16),
+            new BetaPerlinNoise(world.getRandomSeed(), 8, 32),
+            new BetaPerlinNoise(world.getRandomSeed(), 10, 48),
+            new BetaPerlinNoise(world.getRandomSeed(), 16, 58),
+            false
+        );
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/SurfaceGeneratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/SurfaceGeneratorOverworldB173.java
new file mode 100644
index 000000000..dff75eae1
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/SurfaceGeneratorOverworldB173.java
@@ -0,0 +1,18 @@
+package net.minecraft.core.world.generate.chunk.perlin.overworld.b173;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld;
+import net.minecraft.core.world.noise.BetaPerlinNoise;
+
+public class SurfaceGeneratorOverworldB173
+    extends SurfaceGeneratorOverworld
+{
+    public SurfaceGeneratorOverworldB173(final World world) {
+        super(world,
+            new BetaPerlinNoise(world.getRandomSeed(), 4, 40),
+            new BetaPerlinNoise(world.getRandomSeed(), 4, 44),
+            new BetaPerlinNoise(world.getRandomSeed(), 8, 32),
+            false
+        );
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/TerrainGeneratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/TerrainGeneratorOverworldB173.java
new file mode 100644
index 000000000..d8de84463
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/TerrainGeneratorOverworldB173.java
@@ -0,0 +1,14 @@
+package net.minecraft.core.world.generate.chunk.perlin.overworld.b173;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.generate.chunk.perlin.overworld.TerrainGeneratorOverworld;
+
+public class TerrainGeneratorOverworldB173
+    extends TerrainGeneratorOverworld
+{
+    public TerrainGeneratorOverworldB173(final World world) {
+        super(world,
+            new DensityGeneratorOverworldB173(world)
+        );
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/floating/ChunkGeneratorOverworldFloating.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/floating/ChunkGeneratorOverworldFloating.java
index dc3009002..0308cc9ec 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/floating/ChunkGeneratorOverworldFloating.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/floating/ChunkGeneratorOverworldFloating.java
@@ -6,13 +6,13 @@ import net.minecraft.core.world.generate.LargeFeature;
 import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.ChunkDecoratorOverworld;
 import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld;
-import net.minecraft.core.world.generate.chunk.perlin.paradise.TerrainGeneratorParadise;
+import net.minecraft.core.world.generate.chunk.perlin.drift.TerrainGeneratorDrift;
 
 public class ChunkGeneratorOverworldFloating
     extends ChunkGeneratorPerlin
 {
     public ChunkGeneratorOverworldFloating(World world)
     {
-        super(world, new ChunkDecoratorOverworld(world), new TerrainGeneratorParadise(world), new SurfaceGeneratorOverworld(world), new LargeFeature[] { new CavesLargeFeature() });
+        super(world, new ChunkDecoratorOverworld(world), new TerrainGeneratorDrift(world), new SurfaceGeneratorOverworld(world), new LargeFeature[] { new CavesLargeFeature() });
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkGeneratorOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkGeneratorOverworldRetro.java
index fe6ec3396..2ec4add36 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkGeneratorOverworldRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkGeneratorOverworldRetro.java
@@ -3,6 +3,7 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld.retro;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.generate.CavesLargeFeature;
 import net.minecraft.core.world.generate.LargeFeature;
+import net.minecraft.core.world.generate.RetroCavesLargeFeature;
 import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin;
 
 public class ChunkGeneratorOverworldRetro
@@ -15,7 +16,7 @@ public class ChunkGeneratorOverworldRetro
               new ChunkDecoratorOverworldRetro(world),
               new TerrainGeneratorOverworldRetro(world),
               new SurfaceGeneratorOverworldRetro(world),
-              new LargeFeature[] { new CavesLargeFeature() }
+              new LargeFeature[] { new RetroCavesLargeFeature(world.getWorldType().getMinY(), world.getWorldType().getMaxY() + 1) }
         );
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureOre.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureOre.java
index 0c2586012..b73382f39 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureOre.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureOre.java
@@ -32,20 +32,20 @@ public class WorldFeatureOre extends WorldFeature
 	public boolean place(World world, Random random, int xStart, int yStart, int zStart)
     {
         float f = random.nextFloat() * MathHelper.PI;
-        double xMax = (float)(xStart + 8) + (MathHelper.sin(f) * (float)numberOfBlocks) / 8F;
-        double xMin = (float)(xStart + 8) - (MathHelper.sin(f) * (float)numberOfBlocks) / 8F;
-        double zMax = (float)(zStart + 8) + (MathHelper.cos(f) * (float)numberOfBlocks) / 8F;
-        double zMin = (float)(zStart + 8) - (MathHelper.cos(f) * (float)numberOfBlocks) / 8F;
+        double xMax = (float)(xStart + 8) + MathHelper.sin(f) * (float)numberOfBlocks / 8F;
+        double xMin = (float)(xStart + 8) - MathHelper.sin(f) * (float)numberOfBlocks / 8F;
+        double zMax = (float)(zStart + 8) + MathHelper.cos(f) * (float)numberOfBlocks / 8F;
+        double zMin = (float)(zStart + 8) - MathHelper.cos(f) * (float)numberOfBlocks / 8F;
         double yMax = yStart + random.nextInt(3) + 2;
         double yMin = yStart - random.nextInt(3) + 2;
         for(int l = 0; l <= numberOfBlocks; l++)
         {
-            double d6 = xMax + ((xMin - xMax) * (double)l) / (double)numberOfBlocks;
-            double d7 = yMax + ((yMin - yMax) * (double)l) / (double)numberOfBlocks;
-            double d8 = zMax + ((zMin - zMax) * (double)l) / (double)numberOfBlocks;
-            double d9 = (random.nextDouble() * (double)numberOfBlocks) / 16D;
-            double d10 = (double)(MathHelper.sin(((float)l * MathHelper.PI) / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
-            double d11 = (double)(MathHelper.sin(((float)l * MathHelper.PI) / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
+            double d6 = xMax + (xMin - xMax) * (double)l / (double)numberOfBlocks;
+            double d7 = yMax + (yMin - yMax) * (double)l / (double)numberOfBlocks;
+            double d8 = zMax + (zMin - zMax) * (double)l / (double)numberOfBlocks;
+            double d9 = random.nextDouble() * (double)numberOfBlocks / 16D;
+            double d10 = (double)(MathHelper.sin((float)l * MathHelper.PI / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
+            double d11 = (double)(MathHelper.sin((float)l * MathHelper.PI / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
             int xVeinStart = MathHelper.floor(d6 - d10 / 2D);
             int yVeinStart = MathHelper.floor(d7 - d11 / 2D);
             int zVeinStart = MathHelper.floor(d8 - d10 / 2D);
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/BetaImprovedNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/BetaImprovedNoise.java
new file mode 100644
index 000000000..4e88dac6e
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/BetaImprovedNoise.java
@@ -0,0 +1,131 @@
+package net.minecraft.core.world.noise;
+
+import java.util.Random;
+
+public class BetaImprovedNoise
+    extends BaseImprovedNoise
+{
+    public BetaImprovedNoise(final Random random) {
+        super(random);
+    }
+
+    @Override
+    public void add(final double[] arr, final double x, final double y, final double z, final int xSize, final int ySize, final int zSize, final double xScale, final double yScale, final double zScale, final double levelScale) {
+        if (ySize == 1) {
+            int var64 = 0;
+            int var66 = 0;
+            int var21 = 0;
+            int var69 = 0;
+            double var72 = 0.0;
+            double var76 = 0.0;
+            int var80 = 0;
+            double var82 = 1.0 / levelScale;
+
+            for (int var30 = 0; var30 < xSize; var30++) {
+                double var83 = (x + (double)var30) * xScale + this.xo;
+                int var85 = (int)var83;
+                if (var83 < (double)var85) {
+                    var85--;
+                }
+
+                int var34 = var85 & 0xFF;
+                var83 -= (double)var85;
+                double var86 = var83 * var83 * var83 * (var83 * (var83 * 6.0 - 15.0) + 10.0);
+
+                for (int var87 = 0; var87 < zSize; var87++) {
+                    double var89 = (z + (double)var87) * zScale + this.zo;
+                    int var91 = (int)var89;
+                    if (var89 < (double)var91) {
+                        var91--;
+                    }
+
+                    int var92 = var91 & 0xFF;
+                    var89 -= (double)var91;
+                    double var93 = var89 * var89 * var89 * (var89 * (var89 * 6.0 - 15.0) + 10.0);
+                    var64 = this.p[var34] + 0;
+                    var66 = this.p[var64] + var92;
+                    var21 = this.p[var34 + 1] + 0;
+                    var69 = this.p[var21] + var92;
+                    var72 = this.lerp(var86, this.grad(this.p[var66], var83, var89), this.grad(this.p[var69], var83 - 1.0, 0.0, var89));
+                    var76 = this.lerp(var86, this.grad(this.p[var66 + 1], var83, 0.0, var89 - 1.0), this.grad(this.p[var69 + 1], var83 - 1.0, 0.0, var89 - 1.0));
+                    double var94 = this.lerp(var93, var72, var76);
+                    arr[var80++] += var94 * var82;
+                }
+            }
+        } else {
+            int var19 = 0;
+            double var20 = 1.0 / levelScale;
+            int var22 = -1;
+            int var23 = 0;
+            int var24 = 0;
+            int var25 = 0;
+            int var26 = 0;
+            int var27 = 0;
+            int var28 = 0;
+            double var29 = 0.0;
+            double var31 = 0.0;
+            double var33 = 0.0;
+            double var35 = 0.0;
+
+            for (int var37 = 0; var37 < xSize; var37++) {
+                double var38 = (x + (double)var37) * xScale + this.xo;
+                int var40 = (int)var38;
+                if (var38 < (double)var40) {
+                    var40--;
+                }
+
+                int var41 = var40 & 0xFF;
+                var38 -= (double)var40;
+                double var42 = var38 * var38 * var38 * (var38 * (var38 * 6.0 - 15.0) + 10.0);
+
+                for (int var44 = 0; var44 < zSize; var44++) {
+                    double var45 = (z + (double)var44) * zScale + this.zo;
+                    int var47 = (int)var45;
+                    if (var45 < (double)var47) {
+                        var47--;
+                    }
+
+                    int var48 = var47 & 0xFF;
+                    var45 -= (double)var47;
+                    double var49 = var45 * var45 * var45 * (var45 * (var45 * 6.0 - 15.0) + 10.0);
+
+                    for (int var51 = 0; var51 < ySize; var51++) {
+                        double var52 = (y + (double)var51) * yScale + this.yo;
+                        int var54 = (int)var52;
+                        if (var52 < (double)var54) {
+                            var54--;
+                        }
+
+                        int var55 = var54 & 0xFF;
+                        var52 -= (double)var54;
+                        double var56 = var52 * var52 * var52 * (var52 * (var52 * 6.0 - 15.0) + 10.0);
+                        if (var51 == 0 || var55 != var22) {
+                            var22 = var55;
+                            var23 = this.p[var41] + var55;
+                            var24 = this.p[var23] + var48;
+                            var25 = this.p[var23 + 1] + var48;
+                            var26 = this.p[var41 + 1] + var55;
+                            var27 = this.p[var26] + var48;
+                            var28 = this.p[var26 + 1] + var48;
+                            var29 = this.lerp(var42, this.grad(this.p[var24], var38, var52, var45), this.grad(this.p[var27], var38 - 1.0, var52, var45));
+                            var31 = this.lerp(var42, this.grad(this.p[var25], var38, var52 - 1.0, var45), this.grad(this.p[var28], var38 - 1.0, var52 - 1.0, var45));
+                            var33 = this.lerp(
+                                var42, this.grad(this.p[var24 + 1], var38, var52, var45 - 1.0), this.grad(this.p[var27 + 1], var38 - 1.0, var52, var45 - 1.0)
+                            );
+                            var35 = this.lerp(
+                                var42,
+                                this.grad(this.p[var25 + 1], var38, var52 - 1.0, var45 - 1.0),
+                                this.grad(this.p[var28 + 1], var38 - 1.0, var52 - 1.0, var45 - 1.0)
+                            );
+                        }
+
+                        double var58 = this.lerp(var56, var29, var31);
+                        double var60 = this.lerp(var56, var33, var35);
+                        double var62 = this.lerp(var49, var58, var60);
+                        arr[var19++] += var62 * var20;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/noise/BetaPerlinNoise.java b/game/core/src/main/java/net/minecraft/core/world/noise/BetaPerlinNoise.java
new file mode 100644
index 000000000..a117b2687
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/noise/BetaPerlinNoise.java
@@ -0,0 +1,26 @@
+package net.minecraft.core.world.noise;
+
+import java.util.Random;
+
+public class BetaPerlinNoise
+    extends BasePerlinNoise<BetaImprovedNoise>
+{
+    public BetaPerlinNoise(final long seed, final int numOctaves) {
+        super(seed, numOctaves);
+    }
+
+    public BetaPerlinNoise(final long seed, final int numOctaves, final int preOctaves) {
+        super(seed, numOctaves, preOctaves);
+    }
+
+    @Override
+    protected BetaImprovedNoise[] newOctaves(final Random random, final int numOctaves) {
+        BetaImprovedNoise[] levels = new BetaImprovedNoise[numOctaves];
+
+        for (int i = 0; i < numOctaves; i++) {
+            levels[i] = new BetaImprovedNoise(random);
+        }
+
+        return levels;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/ChunkConverter.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/ChunkConverter.java
index cca61f394..51130e82b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/conversion/ChunkConverter.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/ChunkConverter.java
@@ -307,7 +307,7 @@ public class ChunkConverter
 			converters[0].addMapping(new MappingSimple(132, 593)); //Block.doorIronTop.blockID));
 
 			converters[0].addMapping(new MappingSimple(134, 721)); //Block.layerLeavesOak.blockID));
-			converters[0].addMapping(new MappingSimple(135, 831)); //Block.portalParadise.blockID));
+			converters[0].addMapping(new MappingSimple(135, 831)); //Block.portalDrift.blockID));
 			converters[0].addMapping(new MappingSimple(136, 201)); //Block.grassRetro.blockID));
 			converters[0].addMapping(new MappingSimple(137, 291)); //Block.leavesOakRetro.blockID));
 			converters[0].addMapping(new MappingSimple(138, 671)); //Block.trommelActive.blockID));
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterLegacyTo19132.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterLegacyTo19132.java
index 075b31c56..11b7f86fd 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterLegacyTo19132.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterLegacyTo19132.java
@@ -71,7 +71,7 @@ public class SaveConverterLegacyTo19132
             deleteOldWorldData(dim1ChunkDirs, dim0ChunkFiles.size() + dim1ChunkFiles.size() + dim0ChunkDirs.size(), totalConversions, progress);
         }
 
-        tag.putByteArray("WorldTypes", new byte[] { (byte) LegacyWorldTypes.getWorldTypeId(WorldTypes.OVERWORLD_RETRO), (byte) LegacyWorldTypes.getWorldTypeId(WorldTypes.NETHER_DEFAULT), (byte) LegacyWorldTypes.getWorldTypeId(WorldTypes.PARADISE_DEFAULT) });
+        tag.putByteArray("WorldTypes", new byte[] { (byte) LegacyWorldTypes.getWorldTypeId(WorldTypes.OVERWORLD_RETRO), (byte) LegacyWorldTypes.getWorldTypeId(WorldTypes.NETHER_DEFAULT), (byte) LegacyWorldTypes.getWorldTypeId(WorldTypes.DRIFT_DEFAULT) });
     }
 
     private void getOldFormatFolders(File file, ArrayList<ChunkFile> chunkFileList, ArrayList<File> chunkDirList)
diff --git a/game/core/src/main/java/net/minecraft/core/world/season/SeasonDriftGold.java b/game/core/src/main/java/net/minecraft/core/world/season/SeasonDriftGold.java
new file mode 100644
index 000000000..bffd3a7ec
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/season/SeasonDriftGold.java
@@ -0,0 +1,7 @@
+package net.minecraft.core.world.season;
+
+public class SeasonDriftGold extends Season {
+	public SeasonDriftGold(String id) {
+		super(id, true, false);
+	}
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/season/SeasonDriftSilver.java b/game/core/src/main/java/net/minecraft/core/world/season/SeasonDriftSilver.java
new file mode 100644
index 000000000..afd580931
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/season/SeasonDriftSilver.java
@@ -0,0 +1,7 @@
+package net.minecraft.core.world.season;
+
+public class SeasonDriftSilver extends Season {
+	public SeasonDriftSilver(String id) {
+		super(id, true, false);
+	}
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/season/SeasonParadiseGold.java b/game/core/src/main/java/net/minecraft/core/world/season/SeasonParadiseGold.java
deleted file mode 100644
index 3bde361de..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/season/SeasonParadiseGold.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.minecraft.core.world.season;
-
-public class SeasonParadiseGold extends Season {
-	public SeasonParadiseGold(String id) {
-		super(id, true, false);
-	}
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/season/SeasonParadiseSilver.java b/game/core/src/main/java/net/minecraft/core/world/season/SeasonParadiseSilver.java
deleted file mode 100644
index 997ccd0f1..000000000
--- a/game/core/src/main/java/net/minecraft/core/world/season/SeasonParadiseSilver.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.minecraft.core.world.season;
-
-public class SeasonParadiseSilver extends Season {
-	public SeasonParadiseSilver(String id) {
-		super(id, true, false);
-	}
-}
diff --git a/game/core/src/main/java/net/minecraft/core/world/season/Seasons.java b/game/core/src/main/java/net/minecraft/core/world/season/Seasons.java
index a029095b6..e01ae3a28 100644
--- a/game/core/src/main/java/net/minecraft/core/world/season/Seasons.java
+++ b/game/core/src/main/java/net/minecraft/core/world/season/Seasons.java
@@ -17,8 +17,8 @@ public abstract class Seasons
     public final static Season OVERWORLD_WINTER = register(new SeasonWinter("overworld.winter").allowWeather(Weathers.OVERWORLD_SNOW, 0.5f).allowWeather(Weathers.OVERWORLD_FOG, 0.25f).setLetWeatherCleanUpSnow(false).setDayLength(0.3f).setCropGrowthFactor(0.25f).setKillFlowers().setSaplingDropFactor(0.1f));
     public final static Season OVERWORLD_HELL = register(new SeasonOverworldHell("overworld.hell"));
     public final static Season OVERWORLD_WINTER_ENDLESS = register(new SeasonWinter("overworld.winter.endless").allowWeather(Weathers.OVERWORLD_WINTER_SNOW, 1.0f).setLetWeatherCleanUpSnow(false).setDayLength(0.3f).setCropGrowthFactor(0.25f).setKillFlowers().setSaplingDropFactor(0.1f));
-    public final static Season PARADISE_GOLD = register(new SeasonParadiseGold("paradise.gold").setLetWeatherCleanUpSnow(false));
-    public final static Season PARADISE_SILVER = register(new SeasonParadiseSilver("paradise.silver").setLetWeatherCleanUpSnow(false));
+    public final static Season DRIFT_GOLD = register(new SeasonDriftGold("drift.gold").setLetWeatherCleanUpSnow(false));
+    public final static Season DRIFT_SILVER = register(new SeasonDriftSilver("drift.silver").setLetWeatherCleanUpSnow(false));
 
     public static Season getSeason(String key)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeGroups.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeGroups.java
index 3d9ccc21f..6045382e0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeGroups.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeGroups.java
@@ -45,6 +45,9 @@ public class WorldTypeGroups {
         GROUPS.add(
             new Group(WorldTypes.OVERWORLD_PARADISE)
         );
+        GROUPS.add(
+            new Group(WorldTypes.OVERWORLD_BETA_173)
+        );
         GROUPS.add(
             new Group(WorldTypes.OVERWORLD_CLASSIC)
         );
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 294fb8285..0fd6c03a9 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
@@ -7,7 +7,7 @@ import net.minecraft.core.world.season.Seasons;
 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.paradise.WorldTypeParadise;
+import net.minecraft.core.world.type.drift.WorldTypeDrift;
 import net.minecraft.core.world.weather.Weathers;
 
 public abstract class WorldTypes {
@@ -38,10 +38,10 @@ public abstract class WorldTypes {
                         .bounds(0, 127, 0)
             )
     );
-    public static final WorldType PARADISE_DEFAULT = register(
-            "minecraft:paradise.default",
-            new WorldTypeParadise(
-                    WorldTypeParadise.defaultProperties("worldType.paradise.default")
+    public static final WorldType DRIFT_DEFAULT = register(
+            "minecraft:drift.default",
+            new WorldTypeDrift(
+                    WorldTypeDrift.defaultProperties("worldType.drift.default")
             )
     );
     public static final WorldType FLAT = register(
@@ -167,6 +167,13 @@ public abstract class WorldTypes {
                         .bounds(0, 127, 0)
             )
     );
+    public static final WorldType OVERWORLD_BETA_173 = register(
+            "minecraft:overworld.beta_173",
+            new WorldTypeOverworldB173(
+                    WorldTypeOverworld.defaultProperties("worldType.overworld.beta_173")
+                            .bounds(0, 127, 64)
+            )
+    );
     public static final WorldType EMPTY = register(
             "minecraft:empty",
             new WorldTypeEmpty(
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/paradise/WorldTypeParadise.java b/game/core/src/main/java/net/minecraft/core/world/type/drift/WorldTypeDrift.java
similarity index 85%
rename from game/core/src/main/java/net/minecraft/core/world/type/paradise/WorldTypeParadise.java
rename to game/core/src/main/java/net/minecraft/core/world/type/drift/WorldTypeDrift.java
index 72c0684a7..f51eb13b0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/paradise/WorldTypeParadise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/drift/WorldTypeDrift.java
@@ -1,4 +1,4 @@
-package net.minecraft.core.world.type.paradise;
+package net.minecraft.core.world.type.drift;
 
 import net.minecraft.core.Global;
 import net.minecraft.core.block.Blocks;
@@ -9,13 +9,13 @@ import net.minecraft.core.world.biome.provider.BiomeProvider;
 import net.minecraft.core.world.biome.provider.BiomeProviderSingleBiome;
 import net.minecraft.core.world.config.season.SeasonConfig;
 import net.minecraft.core.world.generate.chunk.ChunkGenerator;
-import net.minecraft.core.world.generate.chunk.perlin.paradise.ChunkGeneratorParadise;
+import net.minecraft.core.world.generate.chunk.perlin.drift.ChunkGeneratorDrift;
 import net.minecraft.core.world.season.Seasons;
 import net.minecraft.core.world.type.WorldType;
 
-public class WorldTypeParadise
+public class WorldTypeDrift
         extends WorldType {
-    public WorldTypeParadise(Properties properties) {
+    public WorldTypeDrift(Properties properties) {
         super(properties);
     }
 
@@ -23,8 +23,8 @@ public class WorldTypeParadise
         return Properties.of(translationKey)
                 .brightnessRamp(createLightRamp())
                 .seasonConfig(SeasonConfig.builder()
-                        .withSeasonInCycle(Seasons.PARADISE_GOLD, 28)
-                        .withSeasonInCycle(Seasons.PARADISE_SILVER, 28)
+                        .withSeasonInCycle(Seasons.DRIFT_GOLD, 28)
+                        .withSeasonInCycle(Seasons.DRIFT_SILVER, 28)
                         .build()
                 )
                 .fillerBlock(Blocks.MARBLE)
@@ -52,12 +52,12 @@ public class WorldTypeParadise
 
     @Override
     public BiomeProvider createBiomeProvider(World world) {
-        return new BiomeProviderSingleBiome(Biomes.PARADISE_PARADISE, 0.5, 0.0, 0.0);
+        return new BiomeProviderSingleBiome(Biomes.DRIFT_DRIFT, 0.5, 0.0, 0.0);
     }
 
     @Override
     public ChunkGenerator createChunkGenerator(World world) {
-        return new ChunkGeneratorParadise(world);
+        return new ChunkGeneratorDrift(world);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java b/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
index 3365e982b..c4096ea8e 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
@@ -22,7 +22,7 @@ public class WorldTypeNether
                 .oceanBlock(Blocks.FLUID_LAVA_STILL)
                 .fillerBlock(Blocks.COBBLE_NETHERRACK)
                 .withCeiling()
-                .bounds(0, 255, 128 + 32);
+                .bounds(0, 255, 64 + 32);
     }
 
     private static float[] getLightRamp() {
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldB173.java
new file mode 100644
index 000000000..8736d2c1c
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworldB173.java
@@ -0,0 +1,27 @@
+package net.minecraft.core.world.type.overworld;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.biome.Biomes;
+import net.minecraft.core.world.biome.provider.BiomeProvider;
+import net.minecraft.core.world.biome.provider.BiomeProviderB173;
+import net.minecraft.core.world.biome.provider.BiomeProviderSingleBiome;
+import net.minecraft.core.world.generate.chunk.ChunkGenerator;
+import net.minecraft.core.world.generate.chunk.perlin.overworld.b173.ChunkGeneratorOverworldB173;
+import net.minecraft.core.world.generate.chunk.perlin.overworld.retro.ChunkGeneratorOverworldRetro;
+
+public class WorldTypeOverworldB173
+        extends WorldTypeOverworld {
+    public WorldTypeOverworldB173(Properties properties) {
+        super(properties);
+    }
+
+    @Override
+    public BiomeProvider createBiomeProvider(World world) {
+        return new BiomeProviderB173(world.getRandomSeed());
+    }
+
+    @Override
+    public ChunkGenerator createChunkGenerator(World world) {
+        return new ChunkGeneratorOverworldB173(world);
+    }
+}
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 88866f1df..4ccddd7a8 100644
--- a/game/core/src/main/resources/lang/en_US/biomes.lang
+++ b/game/core/src/main/resources/lang/en_US/biomes.lang
@@ -26,4 +26,5 @@ biome.nether.volcanic_islands=Volcanic Islands
 biome.nether.sulfur_pools=Sulfur Pools
 biome.nether.crystal_forest=Crystal Forest
 biome.nether.ash_plains=Ash Plains
-biome.nether.boneyard=Boneyard
\ No newline at end of file
+biome.nether.boneyard=Boneyard
+biome.drift.drift=Drift
\ No newline at end of file
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 1accede2c..62d7c905f 100644
--- a/game/core/src/main/resources/lang/en_US/strings.lang
+++ b/game/core/src/main/resources/lang/en_US/strings.lang
@@ -1,6 +1,6 @@
 dimension.overworld.name=the Overworld
 dimension.nether.name=the Nether
-dimension.paradise.name=Paradise
+dimension.drift.name=the Drift
 
 season.overworld.spring.name=Spring
 season.overworld.summer.name=Summer
@@ -8,8 +8,8 @@ season.overworld.fall.name=Fall
 season.overworld.winter.name=Winter
 season.overworld.hell.name=Hell
 season.overworld.winter.endless.name=Endless Winter
-season.paradise.gold.name=Gold
-season.paradise.silver.name=Silver
+season.drift.gold.name=Gold
+season.drift.silver.name=Silver
 season.null.name=No Season
 
 weather.overworld.clear.name=Clear
@@ -32,7 +32,7 @@ worldType.overworld.extended.desc=The intended experience for\nBTA, featuring la
 worldType.overworld.default.name=Default
 worldType.overworld.default.desc=A more vanilla-like experience.
 worldType.nether.default.name=Default
-worldType.paradise.default.name=Default
+worldType.drift.default.name=Default
 worldType.flat.name=Flat
 worldType.flat.desc=An infinite expanse of flat\ngrass.
 worldType.overworld.floating.name=Floating Islands
@@ -63,6 +63,8 @@ worldType.overworld.indev.name=Indev
 worldType.overworld.indev.desc=Terrain generation similar to\nIndev, but infinite.
 worldType.overworld.skyblock.name=Skyblock
 worldType.overworld.skyblock.desc=Hardcore survival on a tiny\nisland in the sky.
+worldType.overworld.beta_173.name=Beta 1.7.3
+worldType.overworld.beta_173.desc=Terrain generation as similar as possible to\n Minecraft Beta 1.7.3.
 
 disconnect.genericReason=%s
 disconnect.disconnected=Disconnected by Server
diff --git a/game/core/src/main/resources/lang/en_US/tile.lang b/game/core/src/main/resources/lang/en_US/tile.lang
index 04ef7794a..632881212 100644
--- a/game/core/src/main/resources/lang/en_US/tile.lang
+++ b/game/core/src/main/resources/lang/en_US/tile.lang
@@ -984,8 +984,8 @@ tile.glowstone.desc=Constantly emits a strong yellowish light.
 
 tile.portal.nether.name=Nether Portal
 tile.portal.nether.desc=A portal to the Nether.
-tile.portal.paradise.name=Paradise Portal
-tile.portal.paradise.desc=A portal to Paradise.
+tile.portal.drift.name=Drift Portal
+tile.portal.drift.desc=A portal to the Drift.
 
 tile.cake.name=Cake
 tile.cake.desc=I just can't cake it any more.
diff --git a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
index 9e6ac56f8..9050f318d 100644
--- a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -535,7 +535,7 @@ public class MinecraftServer
             {
                 continue;
             }
-            if (worldServer.dimension == Dimension.PARADISE && !propertyManager.getBooleanProperty("allow-paradise", false))
+            if (worldServer.dimension == Dimension.DRIFT && !propertyManager.getBooleanProperty("allow-drift", false))
             {
                 continue;
             }
@@ -744,7 +744,7 @@ public class MinecraftServer
             {
                 continue;
             }
-            if (worldServer.dimension == Dimension.PARADISE && !propertyManager.getBooleanProperty("allow-paradise", false))
+            if (worldServer.dimension == Dimension.DRIFT && !propertyManager.getBooleanProperty("allow-drift", false))
             {
                 continue;
             }
diff --git a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
index ae127c1be..5c6da3b7c 100644
--- a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
+++ b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
@@ -291,8 +291,8 @@ public class PlayerServer extends Player implements ContainerListener {
         {
             Dimension targetDim = ((BlockLogicPortal) Blocks.blocksList[portalID].getLogic()).targetDimension;
             boolean netherAllowed = mcServer.propertyManager.getBooleanProperty("allow-nether", true);
-            boolean paradiseAllowed = mcServer.propertyManager.getBooleanProperty("allow-paradise", false);
-            if ((netherAllowed && targetDim == Dimension.NETHER) || (paradiseAllowed && targetDim == Dimension.PARADISE) || (targetDim != Dimension.NETHER && targetDim != Dimension.PARADISE))
+            boolean driftAllowed = mcServer.propertyManager.getBooleanProperty("allow-drift", false);
+            if ((netherAllowed && targetDim == Dimension.NETHER) || (driftAllowed && targetDim == Dimension.DRIFT) || (targetDim != Dimension.NETHER && targetDim != Dimension.DRIFT))
             {
                 if (craftingInventory != inventorySlots)
                 {
diff --git a/gradle.properties b/gradle.properties
index b81e4aeec..cecfe8135 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,18 +1,7 @@
 org.gradle.parallel = true
 org.gradle.daemon = true
-org.gradle.caching = true
 
 bta.group = net.minecraft
 bta.version = 7.4
 bta.assetPackFormat = 4
-bta.buildChannel = BuildChannel.DEVELOPMENT
-
-# Protocol version scheme:
-# 2 byte value
-# 1st nibble: Major version
-# 2nd nibble: Minor version
-# 3rd nibble: 0 if release, 1 if prerelease, 2 if nightly/dev release
-# 4th nibble: Prerelease version or patch version
-# For example, 7.1_01 would be encoded as 0x7101
-# 7.1 prerelease 1 would be encoded as 0x7111
-bta.mpProtocolVersion = 0x7420
\ No newline at end of file
+bta.buildChannel = BuildChannel.DEVELOPMENT
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index afe96605a..b3d9e4852 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -5,7 +5,7 @@ lwjgl = "3.3.4"
 [libraries]
 jetbrains-annotations = { module = "org.jetbrains:annotations", version = "24.0.0" }
 gson = { module = "com.google.code.gson:gson", version = "2.10.1" }
-brigadier = { module = "com.github.Better-than-Adventure:bta-brigadier", version = "1.0.1"}
+brigadier = { module = "com.github.Better-than-Adventure:bta-brigadier", version = "1.0.2"}
 slf4j-api = { module = "org.slf4j:slf4j-api", version = "2.0.7" }
 log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" }
 log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" }
diff --git a/util/stellar/build.gradle.kts b/util/stellar/build.gradle.kts
index 27d57c62f..a8b5eebc0 100644
--- a/util/stellar/build.gradle.kts
+++ b/util/stellar/build.gradle.kts
@@ -5,14 +5,7 @@ plugins {
 repositories {
     mavenCentral()
     maven("https://libraries.minecraft.net/")
-    ivy {
-        url = uri("https://github.com/Better-than-Adventure")
-        patternLayout {
-            artifact("[organisation]/releases/download/[revision]/brigadier-[revision].jar")
-            m2Compatible
-        }
-        metadataSources { artifact() }
-    }
+    maven("https://jitpack.io")
 }
 
 dependencies {
