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 a0b3b198c..433dc9acd 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -312,7 +312,7 @@ public class Minecraft
      * Keep this as the only constructor in this class for now,
      * otherwise JVM class verification will fail and the game will crash when the fabric loader tries to run the game.
      */
-    public Minecraft(final @NotNull File mcDataDir, final GameWindow gameWindow, final boolean test) {
+    public Minecraft(final @NotNull File mcDataDir, final @NotNull GameWindow gameWindow) {
         Global.accessor = this;
         this.hasCrashed = false;
         this.timer = new Timer(Global.TICKS_PER_SECOND);
@@ -338,8 +338,6 @@ public class Minecraft
         this.textureManager = new TextureManager(this, this.texturePackList);
         this.font = new FontRendererDefault();
 
-        if (test) return;
-
         this.gameWindow = gameWindow;
         this.resolution = new ScaledResolution(this.gameWindow);
 
@@ -2435,7 +2433,7 @@ public class Minecraft
 
     public static void startMainThread(@Nullable String username, @Nullable String sessionId, @Nullable String uuid, @Nullable String server, @Nullable Integer port, @Nullable Integer width, @Nullable Integer height, @Nullable File mcDataDir) {
         GameWindow gameWindow = new GameWindowGLFW();
-        Minecraft mc = new Minecraft(mcDataDir == null ? getAppDir("minecraft-bta") : mcDataDir, gameWindow, false);
+        Minecraft mc = new Minecraft(mcDataDir == null ? getAppDir("minecraft-bta") : mcDataDir, gameWindow);
         mc.minecraftUri = "www.minecraft.net";
 
         username = username == null ? "Player" + System.currentTimeMillis() % 1000L : username;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFlagEditor.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFlagEditor.java
index 6c7fcb78b..799065300 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFlagEditor.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFlagEditor.java
@@ -117,11 +117,13 @@ public class ScreenFlagEditor
         this.flagSurface.colors = colors;
         this.drawOverlaySurface.colors = colors;
 
+        GLRenderer.pushFrame();
         GLRenderer.enableState(State.BLEND);
         GLRenderer.setBlendFunc(BlendFactor.ONE_MINUS_SRC_ALPHA, BlendFactor.SRC_COLOR);
         this.flagSurface.render(this.canvasX, this.canvasY);
         GLRenderer.disableState(State.BLEND);
         this.drawOverlaySurface.render(this.canvasX, this.canvasY);
+        GLRenderer.popFrame();
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java b/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java
index 367f70d98..7c8791428 100644
--- a/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java
@@ -21,6 +21,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.pos.TilePos;
 import org.joml.Math;
 
 public class ItemRenderer {
@@ -146,37 +147,32 @@ public class ItemRenderer {
         }
 
         if (this.mc.thePlayer.isInWall() && !this.mc.thePlayer.noPhysics) {
-            int blockX = MathHelper.floor(this.mc.thePlayer.x);
-            int blockY = MathHelper.floor(this.mc.thePlayer.y);
-            int blockZ = MathHelper.floor(this.mc.thePlayer.z);
+            TilePos blockPos = this.mc.activeCamera.getTilePos(partialTicks);
 
             TextureRegistry.worldAtlas.bind();
-
-            int id = this.mc.currentWorld.getBlockId(blockX, blockY, blockZ);
-            int meta = this.mc.currentWorld.getBlockMetadata(blockX, blockY, blockZ);
-            Block<?> block = Blocks.blocksList[id];
+            Block<?> block = this.mc.currentWorld.getBlockType(blockPos);
+            int meta = this.mc.currentWorld.getBlockData(blockPos);
             BlockModel<?> model = BlockModelDispatcher.getInstance().getDispatch(block);
-            if (this.mc.currentWorld.isBlockNormalCube(blockX, blockY, blockZ)) {
+            if (this.mc.currentWorld.isBlockNormalCube(blockPos)) {
                 renderInsideOfBlock(partialTicks, model.getOverlayTexture(meta));
             } else {
-                id = 0;
+                TilePos queryPos = new TilePos();
+                block = null;
                 for (int i = 0; i < 8; i++) {
                     float x0 = ((float) ((i >> 0) % 2) - 0.5F) * this.mc.thePlayer.bbWidth * 0.9F;
                     float y0 = ((float) ((i >> 1) % 2) - 0.5F) * this.mc.thePlayer.bbHeight * 0.2F;
                     float z0 = ((float) ((i >> 2) % 2) - 0.5F) * this.mc.thePlayer.bbWidth * 0.9F;
 
-                    int x1 = MathHelper.floor_float(blockX + x0);
-                    int y1 = MathHelper.floor_float(blockY + y0);
-                    int z1 = MathHelper.floor_float(blockZ + z0);
+                    queryPos.set(MathHelper.floor_float(blockPos.x() + x0), MathHelper.floor_float(blockPos.y() + y0), MathHelper.floor_float(blockPos.z() + z0));
 
-                    if (this.mc.currentWorld.isBlockNormalCube(x1, y1, z1)) {
-                        id = this.mc.currentWorld.getBlockId(x1, y1, z1);
-                        meta = this.mc.currentWorld.getBlockMetadata(x1, y1, z1);
+                    if (this.mc.currentWorld.isBlockNormalCube(queryPos)) {
+                        block = this.mc.currentWorld.getBlockType(queryPos);
+                        meta = this.mc.currentWorld.getBlockData(queryPos);
                         break;
                     }
                 }
-                if (Blocks.blocksList[id] != null) {
-                    model = BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[id]);
+                if (block != null) {
+                    model = BlockModelDispatcher.getInstance().getDispatch(block);
                     renderInsideOfBlock(partialTicks, model.getOverlayTexture(meta));
                 }
             }
@@ -197,6 +193,8 @@ public class ItemRenderer {
             brightness = 1.0f;
         }
         GLRenderer.pushFrame();
+        GLRenderer.projectionM4f().identity();
+        GLRenderer.viewM4f().identity();
         GLRenderer.setColor4f(brightness, brightness, brightness, 0.5f);
         final float x0 = -1F;
         final float x1 = 1.0F;
diff --git a/game/client/src/main/java/net/minecraft/client/render/LightingCache.java b/game/client/src/main/java/net/minecraft/client/render/LightingCache.java
index bcbc65d37..feb36419c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/LightingCache.java
+++ b/game/client/src/main/java/net/minecraft/client/render/LightingCache.java
@@ -45,15 +45,10 @@ final public class LightingCache {
     }
 
     private float calcBrightness(final @NotNull TilePos tilePos) {
-        final Block<?> block = this.access.getBlockType(tilePos);
-
-        if (this.block.emission >= 15) {
-            return 1.0f;
-        }
-        if (!this.mc.isAmbientOcclusionEnabled()) {
+        if (this.block.emission >= 15 || !this.mc.isAmbientOcclusionEnabled()) {
             return 1.0f;
         }
-        return 1.0f - block.getAmbientOcclusionStrength(this.access, tilePos);
+        return 1.0f - this.access.getBlockType(tilePos).getAmbientOcclusionStrength(this.access, tilePos);
     }
 
     public float getBrightness(int relX, int relY, int relZ) {
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 1c68fdc5e..7f7548571 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
@@ -697,6 +697,7 @@ public class WorldRenderer {
         GLRenderer.enableState(State.CULL_FACE);
         TextureRegistry.worldAtlas.bind();
 
+        Lighting.enableLight();
         Debug.change("water");
         this.lightmapHelper.enableLightmapRendering();
         GLRenderer.pushFrame();
@@ -708,6 +709,7 @@ public class WorldRenderer {
         this.mc.terrainRenderer.renderTranslucentTerrain(partialTicks);
         GLRenderer.popFrame();
         this.lightmapHelper.disableLightmapRendering();
+        Lighting.disable();
 
         Debug.change("weather");
         GLRenderer.setDepthMask(true);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
index db8742538..f77bac05a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
@@ -14,10 +14,16 @@ public class BlockColorCrystal extends BlockColorCustom{
         super(colorizer);
     }
     protected static ImprovedPerlinNoise crystalPerlinNoise = new ImprovedPerlinNoise(new Random(0));
+
+    @Override
+    public int getFallbackColor(int meta, int tintIndex) {
+        return 0xFFc40e26;
+    }
+
     @Override
     public int getWorldColor(@NotNull WorldSource source, @NotNull TilePosc tilePos, int tintIndex) {
 
-        int color = 0xc40e26;
+        int color = 0xFFc40e26;
 //        float offsetR = (float) (crystalPerlinNoise.getValue(x / 10f, z / 10f)) * 0.5f;
 //
 //        float r = ((color & 0xFF0000) >> 16) / 255F;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
index d1c569f3d..695e768c9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
@@ -15,6 +15,9 @@ import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
 import org.joml.Math;
+import org.joml.Vector3d;
+import org.joml.Vector3dc;
+import org.joml.Vector3f;
 import org.joml.primitives.AABBdc;
 
 public class BlockModelFluid<T extends BlockLogicFluid> extends BlockModelStandard<T> {
@@ -22,6 +25,14 @@ public class BlockModelFluid<T extends BlockLogicFluid> extends BlockModelStanda
         super(block);
     }
 
+    private final @NotNull Vector3d br = new Vector3d();
+    private final @NotNull Vector3d bl = new Vector3d();
+    private final @NotNull Vector3d tr = new Vector3d();
+
+    private final @NotNull Vector3d a = new Vector3d();
+    private final @NotNull Vector3d b = new Vector3d();
+    private final @NotNull Vector3d norm = new Vector3d();
+
     @Override
     public boolean render(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos) {
         tessellator.setColor1i(BlockColorDispatcher.getInstance().getDispatch(this.block).getWorldColor(worldSource, tilePos, 0));
@@ -68,7 +79,16 @@ public class BlockModelFluid<T extends BlockLogicFluid> extends BlockModelStanda
                 float cos = Math.cos(-rotation + Math.PI_OVER_2_f);
                 float sin = Math.sin(-rotation + Math.PI_OVER_2_f);
 
-                tessellator.setNormal(0, 1, 0);
+                this.br.set(x, (float) y + h, z);
+                this.bl.set(x, (float) y + hs, z + 1);
+                this.tr.set(x + 1, (float) y + hes, z + 1);
+
+                this.br.sub(this.bl, this.a);
+                this.tr.sub(this.bl, this.b);
+
+                this.b.cross(this.a, this.norm).normalize();
+
+                tessellator.setNormal(this.norm);
                 tessellator.addVertexWithUV(x, (float) y + h, z,
                     tex.getSubIconU(((-0.25) * cos - (-0.25) * sin) + 0.5),
                     tex.getSubIconV(((-0.25) * sin + (-0.25) * cos) + 0.5)
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java
index 8040e6dd7..c34c1d07c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java
@@ -89,9 +89,10 @@ public class BlockModelGeneric<T extends BlockLogic> extends BlockModel<T> {
         return this.staticModel.renderLayer();
     }
 
+    private final @NotNull TilePos queryPos = new TilePos();
     public boolean cullSide(@NotNull WorldSource worldSource, @NotNull TilePosc blockPos, @Nullable Direction direction) {
         if (direction != null) {
-            TilePos shifted = blockPos.add(direction, new TilePos());
+            TilePos shifted = blockPos.add(direction, this.queryPos);
             if (this.forceCullSelf) {
                 return worldSource.getBlockType(shifted) == this.block || worldSource.isBlockOpaqueCube(shifted);
             } else {
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java
index 632d6311f..40213daea 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java
@@ -89,7 +89,7 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
                             continue;
                         }
 
-                        hasRenderedBlock |= renderBlock(tessellator, this.world, model, pos);
+                        hasRenderedBlock |= renderBlock(tessellator, chunkCache, model, pos);
                     }
                 }
             }
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/RenderList.java b/game/client/src/main/java/net/minecraft/client/render/terrain/RenderList.java
index 185e3bde5..cea334730 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/RenderList.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/RenderList.java
@@ -11,6 +11,7 @@ import java.util.Set;
 import com.mojang.logging.CategorizedLogger;
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.render.terrain.VertexBuffer.Entry;
+import net.minecraft.core.Global;
 import org.lwjgl.BufferUtils;
 
 /**
@@ -56,8 +57,12 @@ public class RenderList {
             this.sizeBuffer.clear();
 
             for (Entry entry : this.visibleEntries) {
-                this.posBuffer.put(entry.position / vertexSize);
-                this.sizeBuffer.put(entry.size / vertexSize);
+                int pos = (int) (entry.position / vertexSize);
+                int size = (int) (entry.size / vertexSize);
+                assert pos >= 0 : "Entry pos must be positive!";
+                assert size >= 0 : "Entry size must be positive!";
+                this.posBuffer.put(pos);
+                this.sizeBuffer.put(size);
             }
 
             this.posBuffer.flip();
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexBuffer.java b/game/client/src/main/java/net/minecraft/client/render/terrain/VertexBuffer.java
index c0a63d84d..144115d11 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexBuffer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/VertexBuffer.java
@@ -64,7 +64,7 @@ public class VertexBuffer {
 			Entry entry = this.entries.get(i);
 			Entry nextEntry = this.entries.get(i + 1);
 			
-			int availableSpace = nextEntry.position - (entry.position + entry.size);
+			long availableSpace = nextEntry.position - (entry.position + entry.size);
 			if(availableSpace > bytes) {
 				return insertAtIndex(vertexData, i + 1);
 			}
@@ -75,8 +75,8 @@ public class VertexBuffer {
 	}
 	
 	private Entry insertAtIndex(VertexData vertexData, int listIndex) {
-		int pos = 0;
-		int bytes = vertexData.buffer.position();
+		long pos = 0;
+		long bytes = vertexData.buffer.position();
 		
 		if(listIndex > 0) {
 			Entry prev = this.entries.get(listIndex - 1);
@@ -103,6 +103,8 @@ public class VertexBuffer {
 		}
 		
 		vertexData.buffer.flip();
+
+		assert pos >= 0: "Entry pos must be positive!";
 		
 		glBindBuffer(GL_ARRAY_BUFFER, this.vbo);
 		glBufferSubData(GL_ARRAY_BUFFER, pos, vertexData.buffer);
@@ -166,12 +168,12 @@ public class VertexBuffer {
 	 */
 	public class Entry {
 		
-		public final int position;
-		public final int size;
+		public final long position;
+		public final long size;
 		
 		private final int hashCode = VertexBuffer.this.entryHashCounter++;
 		
-		public Entry(int position, int size) {
+		public Entry(long position, long size) {
 			this.position = position;
 			this.size = size;
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorNormal.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorNormal.java
index 809c5500b..d1fd47c7e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorNormal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorNormal.java
@@ -1,5 +1,15 @@
 package net.minecraft.client.render.tessellator;
 
+import org.jetbrains.annotations.NotNull;
+import org.joml.Vector3dc;
+import org.joml.Vector3fc;
+
 public interface TessellatorNormal extends Tessellator{
     void setNormal(float x, float y, float z);
+    default void setNormal(@NotNull Vector3dc normal) {
+        setNormal((float) normal.x(), (float) normal.y(), (float) normal.z());
+    }
+    default void setNormal(@NotNull Vector3fc normal) {
+        setNormal(normal.x(), normal.y(), normal.z());
+    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java b/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java
index 664f8ff47..7c4dbf8f5 100644
--- a/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java
+++ b/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java
@@ -18,8 +18,8 @@ public class OpenGLLoggerCallback extends GLDebugMessageCallback {
     @Override
     public void invoke(int source, int type, int id, int severity, int length, long message, long userParam) {
         if (type == GL43.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) { // Only log deprecated errors once, due to their known reporting frequency, helps not make 100MB+ log files
-            if (didReport.getOrDefault(id, false)) return;
-            didReport.put(id, true);
+            if (this.didReport.getOrDefault(id, false)) return;
+            this.didReport.put(id, true);
             LOGGER.warn("Disabling repeated logging of next error, due to known hyper frequency");
         }
         String msg = MemoryUtil.memASCII(message, length);
diff --git a/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java b/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java
index 255686b42..286ceb6fe 100644
--- a/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java
+++ b/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java
@@ -43,6 +43,10 @@ public class StaticBlockModelMojang implements StaticBlockModel {
 
     protected final @NotNull CompiledBlockModelMojangData compiled;
 
+    private final @NotNull Vector3d vertPos = new Vector3d();
+    private final @NotNull Vector3f faceVec = new Vector3f();
+    private final @NotNull Vector2f vertUV = new Vector2f();
+
     public StaticBlockModelMojang(@NotNull BlockModelMojangData data) {
         this.compiled = new CompiledBlockModelMojangData(data);
     }
@@ -90,18 +94,16 @@ public class StaticBlockModelMojang implements StaticBlockModel {
 
     @Override
     public boolean renderAttached(@NotNull BlockModelGeneric<? extends BlockLogic> sourceModel, @NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc blockPos, int rotX, int rotY, int rotZ, double xOff, double yOff, double zOff, boolean uvlock, boolean cullFaces, @Nullable IconCoordinate overrideTexture) {
-        if (this.compiled.elements.length == 0) return false;
         boolean didRender = false;
-        LIGHTING_CACHE.setupCache(sourceModel.block, worldSource, blockPos);
         byte cullCache = 0;
 
-        BlockColor color = BlockColorDispatcher.getInstance().getDispatch(sourceModel.block);
+        @Nullable BlockColor color = null;
         for (int i = 0; i < this.compiled.elements.length; i++) {
             final C_Element element = this.compiled.elements[i];
             for (int face = 0; face < element.faces; face++) {
                 Direction cullDir = element.cullfaces[face];
                 if (cullFaces && cullDir != null) {
-                    cullDir = Direction.rotateZ(Direction.rotateY(Direction.rotateX(element.cullfaces[face], rotX), rotY), rotZ);
+                    cullDir = Direction.rotateZ(Direction.rotateY(Direction.rotateX(cullDir, rotX), rotY), rotZ);
                     if ((cullCache & (1 << cullDir.getId())) != 0) {
                         continue;
                     }
@@ -115,8 +117,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
 
                 final float minBrightness = element.lightEmission / 15f;
 
-                Vector3f q = new Vector3f();
-                final Vector3f top = q.set(element.faceUps[face]);
+                final Vector3f top = this.faceVec.set(element.faceUps[face]);
                 if (rotX != 0) { top.rotateX(rotX * org.joml.Math.PI_OVER_2_f); }
                 if (rotY != 0) { top.rotateY(rotY * org.joml.Math.PI_OVER_2_f); }
                 if (rotZ != 0) { top.rotateZ(rotZ * org.joml.Math.PI_OVER_2_f); }
@@ -126,7 +127,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 float topP;
                 float botP;
 
-                final Vector3f left = q.set(element.faceLefts[face]);
+                final Vector3f left = this.faceVec.set(element.faceLefts[face]);
                 if (rotX != 0) { left.rotateX(rotX * org.joml.Math.PI_OVER_2_f); }
                 if (rotY != 0) { left.rotateY(rotY * org.joml.Math.PI_OVER_2_f); }
                 if (rotZ != 0) { left.rotateZ(rotZ * org.joml.Math.PI_OVER_2_f); }
@@ -237,6 +238,9 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 final float g;
                 final float b;
                 if (element.tintIndices[face] >= 0) {
+                    if (color == null) {
+                        color = BlockColorDispatcher.getInstance().getDispatch(sourceModel.block);
+                    }
                     int c = color.getWorldColor(worldSource, blockPos, element.tintIndices[face]);
                     r = Color.redFromInt(c) / 255f;
                     g = Color.greenFromInt(c) / 255f;
@@ -256,6 +260,8 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 final int lightmapCoordBottomRight;
                 final int lightmapCoordTopRight;
 
+                LIGHTING_CACHE.setupCache(sourceModel.block, worldSource, blockPos);
+
                 if (useAO) {
                     final int dirX2;
                     final int dirY2;
@@ -408,7 +414,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
 
                 final int offset = face * 4;
 
-                Vector3f norm = q.set(element.faceNormals[face]);
+                Vector3f norm = this.faceVec.set(element.faceNormals[face]);
                 if (rotX != 0) { norm.rotateX(rotX * org.joml.Math.PI_OVER_2_f); }
                 if (rotY != 0) { norm.rotateY(rotY * org.joml.Math.PI_OVER_2_f); }
                 if (rotZ != 0) { norm.rotateZ(rotZ * org.joml.Math.PI_OVER_2_f); }
@@ -419,9 +425,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                     tessellator.setNormal(0, 1, 0);
                 }
 
-                Vector3d v = new Vector3d();
-
-                Vector3d posTL = v.set(element.vertexPoses[offset + VERTEX_TOP_LEFT]);
+                Vector3d posTL = this.vertPos.set(element.vertexPoses[offset + VERTEX_TOP_LEFT]);
                 if (rotX != 0 || rotY != 0 || rotZ != 0) {
                     posTL.sub(0.5, 0.5, 0.5)
                         .rotateX(rotX * org.joml.Math.PI_OVER_2)
@@ -430,7 +434,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                         .add(0.5, 0.5, 0.5);
                 }
                 Vector2fc uvsTL = element.vertexUvs[offset + VERTEX_TOP_LEFT];
-                if (uvlock) uvsTL = rotateUV(uvsTL, rotX, rotY, rotZ, element.directions[face], new Vector2f());
+                if (uvlock) uvsTL = rotateUV(uvsTL, rotX, rotY, rotZ, element.directions[face], this.vertUV);
                 tessellator.setColorOpaque3f(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
                 tessellator.setLightmapCoord1i(lightmapCoordTopLeft);
                 tessellator.addVertexWithUV(
@@ -440,7 +444,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                     coordinate.getSubIconU(uvsTL.x()),
                     coordinate.getSubIconV(uvsTL.y()));
 
-                Vector3d posBL = v.set(element.vertexPoses[offset + VERTEX_BOTTOM_LEFT]);
+                Vector3d posBL = this.vertPos.set(element.vertexPoses[offset + VERTEX_BOTTOM_LEFT]);
                 if (rotX != 0 || rotY != 0 || rotZ != 0) {
                     posBL.sub(0.5, 0.5, 0.5)
                         .rotateX(rotX * org.joml.Math.PI_OVER_2)
@@ -449,7 +453,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                         .add(0.5, 0.5, 0.5);
                 }
                 Vector2fc uvsBL = element.vertexUvs[offset + VERTEX_BOTTOM_LEFT];
-                if (uvlock) uvsBL = rotateUV(uvsBL, rotX, rotY, rotZ, element.directions[face], new Vector2f());
+                if (uvlock) uvsBL = rotateUV(uvsBL, rotX, rotY, rotZ, element.directions[face], this.vertUV);
                 tessellator.setColorOpaque3f(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
                 tessellator.setLightmapCoord1i(lightmapCoordBottomLeft);
                 tessellator.addVertexWithUV(
@@ -459,7 +463,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                     coordinate.getSubIconU(uvsBL.x()),
                     coordinate.getSubIconV(uvsBL.y()));
 
-                Vector3d posBR = v.set(element.vertexPoses[offset + VERTEX_BOTTOM_RIGHT]);
+                Vector3d posBR = this.vertPos.set(element.vertexPoses[offset + VERTEX_BOTTOM_RIGHT]);
                 if (rotX != 0 || rotY != 0 || rotZ != 0) {
                     posBR.sub(0.5, 0.5, 0.5)
                         .rotateX(rotX * org.joml.Math.PI_OVER_2)
@@ -468,7 +472,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                         .add(0.5, 0.5, 0.5);
                 }
                 Vector2fc uvsBR = element.vertexUvs[offset + VERTEX_BOTTOM_RIGHT];
-                if (uvlock) uvsBR = rotateUV(uvsBR, rotX, rotY, rotZ, element.directions[face], new Vector2f());
+                if (uvlock) uvsBR = rotateUV(uvsBR, rotX, rotY, rotZ, element.directions[face], this.vertUV);
                 tessellator.setColorOpaque3f(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
                 tessellator.setLightmapCoord1i(lightmapCoordBottomRight);
                 tessellator.addVertexWithUV(
@@ -478,7 +482,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                     coordinate.getSubIconU(uvsBR.x()),
                     coordinate.getSubIconV(uvsBR.y()));
 
-                Vector3d posTR = v.set(element.vertexPoses[offset + VERTEX_TOP_RIGHT]);
+                Vector3d posTR = this.vertPos.set(element.vertexPoses[offset + VERTEX_TOP_RIGHT]);
                 if (rotX != 0 || rotY != 0 || rotZ != 0) {
                     posTR.sub(0.5, 0.5, 0.5)
                         .rotateX(rotX * org.joml.Math.PI_OVER_2)
@@ -487,7 +491,7 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                         .add(0.5, 0.5, 0.5);
                 }
                 Vector2fc uvsTR = element.vertexUvs[offset + VERTEX_TOP_RIGHT];
-                if (uvlock) uvsTR = rotateUV(uvsTR, rotX, rotY, rotZ, element.directions[face], new Vector2f());
+                if (uvlock) uvsTR = rotateUV(uvsTR, rotX, rotY, rotZ, element.directions[face], this.vertUV);
                 tessellator.setColorOpaque3f(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
                 tessellator.setLightmapCoord1i(lightmapCoordTopRight);
                 tessellator.addVertexWithUV(
diff --git a/game/client/src/main/resources/shaders/color.fsh b/game/client/src/main/resources/shaders/color.fsh
index b2645ee5e..7f42b383b 100644
--- a/game/client/src/main/resources/shaders/color.fsh
+++ b/game/client/src/main/resources/shaders/color.fsh
@@ -2,10 +2,15 @@
 
 out vec4 FragColor;
 
+uniform float uAlphaTest;
+
 in vec4 Color;
 
 uniform vec4 uColor;
 
 void main() {
     FragColor = Color * uColor;
+    if (FragColor.a < uAlphaTest) {
+        discard;
+    }
 }
diff --git a/game/client/src/main/resources/shaders/interface.fsh b/game/client/src/main/resources/shaders/interface.fsh
index d06927a62..6c9cabe98 100644
--- a/game/client/src/main/resources/shaders/interface.fsh
+++ b/game/client/src/main/resources/shaders/interface.fsh
@@ -2,6 +2,8 @@
 
 out vec4 FragColor;
 
+uniform float uAlphaTest;
+
 in vec4 Color;
 in vec2 TexCoord;
 
@@ -10,4 +12,7 @@ uniform sampler2D colortex;
 
 void main() {
     FragColor = texture(colortex, TexCoord) * Color * uColor;
+    if (FragColor.a < uAlphaTest) {
+        discard;
+    }
 }
diff --git a/game/client/src/test/java/TestItemModelDispatcher.java b/game/client/src/test/java/TestItemModelDispatcher.java
index c779d6c07..07d8bcba2 100644
--- a/game/client/src/test/java/TestItemModelDispatcher.java
+++ b/game/client/src/test/java/TestItemModelDispatcher.java
@@ -21,7 +21,8 @@ public class TestItemModelDispatcher {
         Colors.loadDummyColors();
 
         // Map model requires mc font reference
-        new Minecraft(Minecraft.getAppDir("minecraft-bta"), null,true);
+        //noinspection DataFlowIssue
+        new Minecraft(Minecraft.getAppDir("minecraft-bta"), null);
 
         for (Map.Entry<NamespaceID, Item> e : Item.itemsMap.entrySet()) {
             Assertions.assertTrue(ItemModelDispatcher.getInstance().hasDispatch(e.getValue()), () -> "Item '" + e.getKey() + "' is not assigned a item model!");
diff --git a/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java b/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
index ce265fc71..7a3bc79af 100644
--- a/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
+++ b/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
@@ -1,5 +1,6 @@
 package net.minecraft.core.world;
 
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.TileEntity;
@@ -14,13 +15,12 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 
 public class BlocksContainer implements MutableWorldSource {
     public final @NotNull World world;
-    private final @NotNull Map<@NotNull TilePos, @NotNull BlockEntry> blockEntryMap = new HashMap<>();
+    private final @NotNull Map<@NotNull TilePos, @NotNull BlockEntry> blockEntryMap = new Object2ObjectOpenHashMap<>();
     private @Nullable Entity lightRefEntity = null;
     public float partialTick = 1f;
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
index 6b2860e00..15a3f0922 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
@@ -90,12 +90,12 @@ public class Chunk {
         return (y * CHUNK_SIZE_Z * CHUNK_SIZE_X) + (z * CHUNK_SIZE_X) + x;
     }
 
-    public @Nullable ChunkSection getSection(final int index) {
-        if (index < 0 || index >= CHUNK_SECTIONS) return null;
+    public @NotNull ChunkSection getSection(final int index) {
+        assert index >= 0 && index < CHUNK_SECTIONS;
         return this.sections[index];
     }
 
-    public @Nullable ChunkSection getSection(final @NotNull ChunkTilePosc chunkTilePos) {
+    public @NotNull ChunkSection getSection(final @NotNull ChunkTilePosc chunkTilePos) {
         return this.getSection(chunkTilePos.getSectionIndex());
     }
 
@@ -247,8 +247,7 @@ public class Chunk {
         if (!tilePos.inBounds()) {
             return 0;
         }
-
-        return Objects.requireNonNull(this.getSection(tilePos)).getBlockId(new ChunkSectionTilePos(tilePos));
+        return this.getSection(tilePos).getBlockId(new ChunkSectionTilePos(tilePos));
     }
 
     @Deprecated
@@ -279,14 +278,14 @@ public class Chunk {
             return false;
         }
 
-        final @NotNull ChunkSection section = Objects.requireNonNull(this.getSection(tilePos));
+        final @NotNull ChunkSection section = this.getSection(tilePos);
         final int heightValue = this.getHeightValue(tilePos.x(), tilePos.z());
 
         final int currentId = section.getBlockId(new ChunkSectionTilePos(tilePos));
         final int currentData = section.getData(new ChunkSectionTilePos(tilePos));
 
-        final @NotNull Block<?> currentBlock = Objects.requireNonNull(Blocks.getBlock(currentId));
-        final @NotNull Block<?> newBlock = Objects.requireNonNull(Blocks.getBlock(id));
+        final @NotNull Block<?> currentBlock = Blocks.getBlock(currentId);
+        final @NotNull Block<?> newBlock = Blocks.getBlock(id);
 
         if (currentId == id && currentData == data) {
             return false;
@@ -341,7 +340,7 @@ public class Chunk {
             return 0;
         }
 
-        return Objects.requireNonNull(this.getSection(tilePos)).getData(new ChunkSectionTilePos(tilePos));
+        return this.getSection(tilePos).getData(new ChunkSectionTilePos(tilePos));
     }
 
     @Deprecated
@@ -354,7 +353,7 @@ public class Chunk {
             return false;
         }
 
-        Objects.requireNonNull(this.getSection(tilePos)).setData(new ChunkSectionTilePos(tilePos), value);
+        this.getSection(tilePos).setData(new ChunkSectionTilePos(tilePos), value);
         this.isModified = true;
 
         return true;
@@ -370,7 +369,7 @@ public class Chunk {
             return null;
         }
 
-        return Objects.requireNonNull(this.getSection(tilePos)).getBiome(new ChunkSectionTilePos(tilePos));
+        return this.getSection(tilePos).getBiome(new ChunkSectionTilePos(tilePos));
     }
 
     @Deprecated
@@ -383,7 +382,7 @@ public class Chunk {
             return false;
         }
 
-        Objects.requireNonNull(this.getSection(tilePos)).setBiome(new ChunkSectionTilePos(tilePos), biome);
+        this.getSection(tilePos).setBiome(new ChunkSectionTilePos(tilePos), biome);
         this.isModified = true;
 
         return true;
@@ -495,7 +494,7 @@ public class Chunk {
             return 0;
         }
 
-        return Objects.requireNonNull(this.getSection(tilePos)).getBrightness(lightLayer, new ChunkSectionTilePos(tilePos));
+        return this.getSection(tilePos).getBrightness(lightLayer, new ChunkSectionTilePos(tilePos));
     }
 
     @Deprecated
@@ -508,7 +507,7 @@ public class Chunk {
             return;
         }
 
-        Objects.requireNonNull(this.getSection(tilePos)).setBrightness(lightLayer, new ChunkSectionTilePos(tilePos), value);
+        this.getSection(tilePos).setBrightness(lightLayer, new ChunkSectionTilePos(tilePos), value);
         this.isModified = true;
     }
 
@@ -522,7 +521,7 @@ public class Chunk {
             return 0;
         }
 
-        final int lightValue = Objects.requireNonNull(this.getSection(tilePos)).getRawBrightness(new ChunkSectionTilePos(tilePos), subtractedSkyLight);
+        final int lightValue = this.getSection(tilePos).getRawBrightness(new ChunkSectionTilePos(tilePos), subtractedSkyLight);
         if (lightValue > 0) {
             Chunk.isLit = true;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
index 739fdc602..77e360966 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
@@ -4,12 +4,12 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
-import net.minecraft.core.block.material.Materials;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.pos.ChunkPos;
+import net.minecraft.core.world.pos.ChunkPosc;
 import net.minecraft.core.world.pos.ChunkTilePos;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
@@ -17,17 +17,18 @@ import net.minecraft.core.world.season.SeasonManager;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Objects;
-
 public class ChunkCache
     implements WorldSource {
     private final @NotNull ChunkPos origin;
-    private final @NotNull Chunk @NotNull [] @NotNull [] chunkArray;
+    private final @NotNull Chunk @NotNull []  chunkArray;
     private final @NotNull World world;
 
     private final int widthX;
     private final int widthZ;
 
+    private final @NotNull TilePos queryTilePos = new TilePos();
+    private final @NotNull ChunkTilePos queryChunkTilePos = new ChunkTilePos();
+
     public ChunkCache(final @NotNull World world, final @NotNull TilePos min, final @NotNull TilePos max, final boolean priority) {
         this.world = world;
         this.origin = new ChunkPos(min);
@@ -35,10 +36,11 @@ public class ChunkCache
         final @NotNull ChunkPos chunkMax = new ChunkPos(max);
         this.widthX = (chunkMax.x - this.origin.x) + 1;
         this.widthZ = (chunkMax.z - this.origin.z) + 1;
-        this.chunkArray = new Chunk[this.widthX][this.widthZ];
+        this.chunkArray = new Chunk[this.widthX * this.widthZ];
         for (int x = 0; x < this.widthX; x++) {
             for (int z = 0; z < this.widthZ; z++) {
-                this.chunkArray[x][z] = this.world.getChunk(new ChunkPos(x + this.origin.x, z + this.origin.z), priority);
+                int index = z * this.widthX + x;
+                this.chunkArray[index] = this.world.getChunk(new ChunkPos(x + this.origin.x, z + this.origin.z), priority);
             }
         }
     }
@@ -57,6 +59,27 @@ public class ChunkCache
         return true;
     }
 
+    public @NotNull Chunk getChunk(@NotNull ChunkPosc chunkPos) {
+        int index = (chunkPos.z() - this.origin.z()) * this.widthX + (chunkPos.x()) - this.origin.x();
+        return this.chunkArray[index];
+    }
+
+    public @NotNull Chunk getChunk(@NotNull TilePosc tilePos) {
+        int index = ((tilePos.z() >> Chunk.CHUNK_SHIFT_X) - this.origin.z()) * this.widthX + (tilePos.x() >> Chunk.CHUNK_SHIFT_Z) - this.origin.x();
+        return this.chunkArray[index];
+    }
+
+    public boolean isChunkLoaded(int chunkX, int chunkZ) {
+        return chunkX >= this.origin.x() && chunkZ >= this.origin.z() && chunkX < (this.origin.x() + this.widthX) && chunkZ < (this.origin.z() + this.widthZ);
+    }
+    public boolean isChunkLoaded(@NotNull ChunkPosc chunkPos) {
+        return isChunkLoaded(chunkPos.x(), chunkPos.z());
+    }
+
+    public boolean isChunkLoaded(@NotNull TilePosc tilePos) {
+        return isChunkLoaded(tilePos.x() >> Chunk.CHUNK_SHIFT_X, tilePos.z() >> Chunk.CHUNK_SHIFT_Z);
+    }
+
     @Override
     public int getHeightBlocks() {
         return this.world.getHeightBlocks();
@@ -67,35 +90,25 @@ public class ChunkCache
         if (tilePos.y() < 0 || tilePos.y() >= this.getHeightBlocks()) {
             return Blocks.AIR;
         }
-
-        final @NotNull ChunkPos cachePos = new ChunkPos(tilePos).sub(this.origin.x, this.origin.z, new ChunkPos());
-        if (cachePos.x < 0 || cachePos.x >= this.chunkArray.length || cachePos.z < 0 || cachePos.z >= this.chunkArray[cachePos.x].length) {
+        if (!isChunkLoaded(tilePos)) {
             return Blocks.AIR;
         }
-
-        final @NotNull Chunk chunk = this.chunkArray[cachePos.x][cachePos.z];
-        return chunk.getBlock(new ChunkTilePos(tilePos));
+        return getChunk(tilePos).getBlock(this.queryChunkTilePos.set(tilePos));
     }
 
     @Override
     public @Nullable TileEntity getTileEntity(final @NotNull TilePosc tilePos) {
-        final @NotNull ChunkPos cachePos = new ChunkPos(tilePos).sub(this.origin.x, this.origin.z, new ChunkPos());
-        return this.chunkArray[cachePos.x][cachePos.z].getTileEntity(new ChunkTilePos(tilePos));
+        return getChunk(tilePos).getTileEntity(this.queryChunkTilePos.set(tilePos));
     }
 
     public boolean getBlockLitInteriorSurface(final @NotNull TilePosc tilePos) {
         if (!tilePos.inBounds(this)) {
             return true;
         } else {
-            return Block.getIsLitInteriorSurface(this.world, tilePos);
+            return Block.getIsLitInteriorSurface(this, tilePos);
         }
     }
 
-    @Deprecated
-    public boolean getBlockLitInteriorSurface(final int x, final int y, final int z) {
-        return this.getBlockLitInteriorSurface(new TilePos(x, y, z));
-    }
-
     @Override
     public float getBrightness(final @NotNull TilePosc tilePos, final int lightEmission) {
         final int lightValue = this.getBlockLightValue(tilePos);
@@ -104,24 +117,23 @@ public class ChunkCache
 
     @Override
     public int getLightmapCoord(final @NotNull TilePosc tilePos, final int lightEmission) {
-        int skyLight = this.world.getSavedLightValue(LightLayer.Sky, tilePos);
-        int blockLight = Math.max(this.world.getSavedLightValue(LightLayer.Block, tilePos), lightEmission);
+        int skyLight = getSavedLightValue(LightLayer.Sky, tilePos);
+        int blockLight = Math.max(getSavedLightValue(LightLayer.Block, tilePos), lightEmission);
 
-        TilePos queryPos = new TilePos();
         if (this.getBlockLitInteriorSurface(tilePos)) {
-            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.up(queryPos)));
-            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.down(queryPos)));
-            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.east(queryPos)));
-            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.west(queryPos)));
-            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.south(queryPos)));
-            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.north(queryPos)));
-
-            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.up(queryPos)));
-            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.down(queryPos)));
-            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.east(queryPos)));
-            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.west(queryPos)));
-            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.south(queryPos)));
-            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.north(queryPos)));
+            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, tilePos.up(this.queryTilePos)));
+            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, tilePos.down(this.queryTilePos)));
+            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, tilePos.east(this.queryTilePos)));
+            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, tilePos.west(this.queryTilePos)));
+            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, tilePos.south(this.queryTilePos)));
+            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, tilePos.north(this.queryTilePos)));
+
+            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, tilePos.up(this.queryTilePos)));
+            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, tilePos.down(this.queryTilePos)));
+            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, tilePos.east(this.queryTilePos)));
+            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, tilePos.west(this.queryTilePos)));
+            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, tilePos.south(this.queryTilePos)));
+            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, tilePos.north(this.queryTilePos)));
         }
 
         return this.getLightmapCoord(skyLight, blockLight);
@@ -141,11 +153,6 @@ public class ChunkCache
         return this.getBlockLightValue_do(tilePos, true);
     }
 
-    @Deprecated
-    public int getLightValue(final int x, final int y, final int z) {
-        return this.getBlockLightValue(new TilePos(x, y, z));
-    }
-
     @Deprecated
     private int getBlockLightValue_do(final @NotNull TilePosc tilePos, final boolean first) {
         if (tilePos.x() < World.MIN_BLOCK_X || tilePos.z() < World.MIN_BLOCK_Z || tilePos.x() >= World.MAX_BLOCK_X || tilePos.z() > World.MAX_BLOCK_Z) {
@@ -153,13 +160,12 @@ public class ChunkCache
         }
 
         if (first) {
-            TilePos queryPos = new TilePos();
             if (this.getBlockLitInteriorSurface(tilePos)) {
-                final int lightUp = this.getBlockLightValue_do(tilePos.up(queryPos), false);
-                final int lightEast = this.getBlockLightValue_do(tilePos.east(queryPos), false);
-                final int lightWest = this.getBlockLightValue_do(tilePos.west(queryPos), false);
-                final int lightSouth = this.getBlockLightValue_do(tilePos.south(queryPos), false);
-                final int lightNorth = this.getBlockLightValue_do(tilePos.north(queryPos), false);
+                final int lightUp = this.getBlockLightValue_do(tilePos.up(this.queryTilePos), false);
+                final int lightEast = this.getBlockLightValue_do(tilePos.east(this.queryTilePos), false);
+                final int lightWest = this.getBlockLightValue_do(tilePos.west(this.queryTilePos), false);
+                final int lightSouth = this.getBlockLightValue_do(tilePos.south(this.queryTilePos), false);
+                final int lightNorth = this.getBlockLightValue_do(tilePos.north(this.queryTilePos), false);
                 return Math.max(lightUp, Math.max(lightEast, Math.max(lightWest, Math.max(lightSouth, lightNorth))));
             }
         }
@@ -175,8 +181,7 @@ public class ChunkCache
             }
             return brightness;
         } else {
-            final @NotNull ChunkPos cachePos = new ChunkPos(tilePos).sub(this.origin.x, this.origin.z, new ChunkPos());
-            return this.chunkArray[cachePos.x][cachePos.z].getRawBrightness(new ChunkTilePos(tilePos), this.world.skyDarken);
+            return getChunk(tilePos).getRawBrightness(this.queryChunkTilePos.set(tilePos), this.world.skyDarken);
         }
     }
 
@@ -185,8 +190,7 @@ public class ChunkCache
         if (tilePos.y() < 0 || tilePos.y() >= this.getHeightBlocks()) {
             return 0;
         } else {
-            final @NotNull ChunkPos cachePos = new ChunkPos(tilePos).sub(this.origin.x, this.origin.z, new ChunkPos());
-            return this.chunkArray[cachePos.x][cachePos.z].getBlockData(new ChunkTilePos(tilePos));
+            return getChunk(tilePos).getBlockData(this.queryChunkTilePos.set(tilePos));
         }
     }
 
@@ -233,7 +237,13 @@ public class ChunkCache
 
     @Override
     public int getSavedLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePosc tilePos) {
-        return this.world.getSavedLightValue(lightLayer, tilePos);
+        if (tilePos.y() < 0 || tilePos.y() >= this.getHeightBlocks()) {
+            return lightLayer.defaultLightLevel;
+        } else if (!this.isChunkLoaded(tilePos)) {
+            return 0;
+        } else {
+            return this.getChunk(tilePos).getBrightness(lightLayer, this.queryChunkTilePos.set(tilePos));
+        }
     }
 
     @Override
