diff --git a/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java b/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java
index 12e03ff40..627376011 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java
@@ -2,7 +2,6 @@ package net.minecraft.client.gui;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.item.model.ItemModel;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.renderer.GLRenderer;
@@ -15,6 +14,7 @@ import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.inventory.slot.Slot;
 import net.minecraft.client.gui.guidebook.SlotGuidebook;
+import net.minecraft.core.util.helper.LightIndexHelper;
 
 public class ItemElement extends Gui {
     Minecraft mc;
@@ -58,7 +58,7 @@ public class ItemElement extends Gui {
             GLRenderer.enableState(State.DEPTH_TEST);
             if (itemStack != null) {
                 final ItemModel itemModel = ItemModelDispatcher.getInstance().getDispatch(itemStack.getItem());
-                itemModel.renderGui(GLRenderer.getTessellator(), null, itemStack, x, y, discovered ? LightmapHelper.getLightmapCoord(15, 15) : LightmapHelper.getLightmapCoord(0, 0), 1f);
+                itemModel.renderGui(GLRenderer.getTessellator(), null, itemStack, x, y, discovered ? LightIndexHelper.lightIndex2i(15, 15) : LightIndexHelper.lightIndex2i(0, 0), 1f);
                 if (slot instanceof SlotGuidebook slotGuidebook) {
                     if (slotGuidebook.recipe instanceof RecipeEntryTrommel recipeEntryTrommel && slotGuidebook.item != null && slotGuidebook.isOutput) {
                         final WeightedRandomBag<WeightedRandomLootObject> loot = recipeEntryTrommel.getOutput();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
index 106f1b9ce..e832d4503 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
@@ -11,7 +11,6 @@ import net.minecraft.client.gui.server.ScreenSelectServer;
 import net.minecraft.client.holiday.Holidays;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.renderer.BlendFactor;
 import net.minecraft.client.render.renderer.CullFace;
@@ -26,6 +25,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.joml.Math;
@@ -344,7 +344,7 @@ public class ScreenMainMenu extends Screen {
         }
 
         GLRenderer.pushFrame();
-        GLRenderer.setShader(Shaders.TERRAIN);
+        GLRenderer.setShader(Shaders.ITEM);
         final int delta = this.mc.gameWindow.getWidthPixels() / this.mc.resolution.getScaledWidthScreenCoords();
         int var3 = 120 * delta;
         GLRenderer.projectionM4f().identity().perspective(70.0F, (float) this.mc.gameWindow.getWidthPixels() / (float) var3, 0.05F, 100.0F);
@@ -386,8 +386,8 @@ public class ScreenMainMenu extends Screen {
             TextureRegistry.worldAtlas.bind();
             GL41.glActiveTexture(GL41.GL_TEXTURE2);
             TextureRegistry.worldAtlas.layerTextureMap.get("emissive").bind();
-//        GL41.glActiveTexture(GL41.GL_TEXTURE3);
-//        TextureRegistry.worldAtlas.layerTextureMap.get("maskColor").bind();
+            GL41.glActiveTexture(GL41.GL_TEXTURE3);
+            TextureRegistry.worldAtlas.layerTextureMap.get("maskColor").bind();
             GL41.glActiveTexture(GL41.GL_TEXTURE0);
             if (renderPass == 0) {
                 this.mc.textureManager.loadTexture("/title/black.png").bind();
@@ -412,7 +412,7 @@ public class ScreenMainMenu extends Screen {
                         GLRenderer.modelM4f().translate(x, y, z);
                         GLRenderer.modelM4f().scale(scale, scale, scale);
                         TessellatorGeneral t = GLRenderer.getTessellator();
-                        BlockModelDispatcher.getInstance().getDispatch(BLOCKS_TO_DRAW[this.indexToDraw]).renderStandalone(t, 0, LightmapHelper.getLightmapCoord(15, 15));
+                        BlockModelDispatcher.getInstance().getDispatch(BLOCKS_TO_DRAW[this.indexToDraw]).renderStandalone(t, 0, LightIndexHelper.lightIndex2i(15, 15));
                         GLRenderer.popFrame();
                     }
                 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenStats.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenStats.java
index 055f1240d..56a48dd6d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenStats.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenStats.java
@@ -1,7 +1,6 @@
 package net.minecraft.client.gui;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.renderer.Shaders;
@@ -12,6 +11,7 @@ import net.minecraft.core.lang.I18n;
 import net.minecraft.core.item.Item;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.core.sound.SoundCategory;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Mouse;
@@ -94,7 +94,7 @@ public class ScreenStats extends Screen {
         renderBackgroundIcon(x + 1, y + 1);
         Lighting.enableInventoryLight();
         Item item = Item.itemsList[itemID];
-        ItemModelDispatcher.getInstance().getDispatch(item).renderGui(GLRenderer.getTessellator(), null, item.getDefaultStack(), x + 2, y + 2, LightmapHelper.getLightmapCoord(15, 15), 1f);
+        ItemModelDispatcher.getInstance().getDispatch(item).renderGui(GLRenderer.getTessellator(), null, item.getDefaultStack(), x + 2, y + 2, LightIndexHelper.lightIndex2i(15, 15), 1f);
         Lighting.disable();
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java b/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
index e0a5ada27..ca52ae79e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
@@ -29,6 +29,7 @@ import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.Color;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -888,7 +889,7 @@ public class ScreenAchievements extends Screen
             GLRenderer.modelM4f().translate((float) (achViewX + 3 * zoom), (float) (achViewY + 3 * zoom), 0);
             GLRenderer.modelM4f().scale((float) zoom, (float) zoom, 1);
 //            ItemModelDispatcher.getInstance().getDispatch(achievementItem).renderItemIntoGui(GLRenderer.getTessellator(), mc.font, mc.textureManager, achievementItem.getDefaultStack(), 0, 0, 1.0f);
-            ItemModelDispatcher.getInstance().getDispatch(achievementItem).renderGui(GLRenderer.getTessellator(), null, achievementItem.getDefaultStack(), 0, 0, LightmapHelper.getLightmapCoord(15, 15), 1f);
+            ItemModelDispatcher.getInstance().getDispatch(achievementItem).renderGui(GLRenderer.getTessellator(), null, achievementItem.getDefaultStack(), 0, 0, LightIndexHelper.lightIndex2i(15, 15), 1f);
 
             GLRenderer.globalSetLightEnabled(false);
             GLRenderer.popFrame();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/ScreenGuidebook.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/ScreenGuidebook.java
index abfd30032..56c233566 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/ScreenGuidebook.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/ScreenGuidebook.java
@@ -9,7 +9,6 @@ import net.minecraft.client.gui.guidebook.search.GuidebookSectionSearch;
 import net.minecraft.client.input.controller.ControllerInput;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.entity.EntityRendererItem;
 import net.minecraft.client.render.font.FontRenderer;
@@ -20,6 +19,7 @@ import net.minecraft.core.achievement.Achievements;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
@@ -566,7 +566,7 @@ public class ScreenGuidebook
                 GLRenderer.setColor4f(1, 1, 1, 1);
 
                 GLRenderer.enableState(State.DEPTH_TEST);
-                ItemModelDispatcher.getInstance().getDispatch(icon).renderGui(GLRenderer.getTessellator(), null, icon, this.x + iconOffset + xo, this.y + 4, LightmapHelper.getLightmapCoord(15, 15), 1f);
+                ItemModelDispatcher.getInstance().getDispatch(icon).renderGui(GLRenderer.getTessellator(), null, icon, this.x + iconOffset + xo, this.y + 4, LightIndexHelper.lightIndex2i(15, 15), 1f);
                 GLRenderer.disableState(State.DEPTH_TEST);
 
                 Lighting.disable();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
index 5982bc4c6..c887c7b46 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
@@ -12,12 +12,14 @@ import net.minecraft.client.gui.Gui;
 import net.minecraft.client.gui.HeldItemTooltipElement;
 import net.minecraft.client.gui.ScreenPhotoMode;
 import net.minecraft.client.option.GameSettings;
+import net.minecraft.client.render.OpenGLHelper;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.renderer.BlendFactor;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.renderer.Shaders;
 import net.minecraft.client.render.renderer.State;
+import net.minecraft.client.render.tessellator.TessellatorTerrainImpl;
 import net.minecraft.core.block.BlockLogicPortal;
 import net.minecraft.core.enums.ChatVisibility;
 import net.minecraft.core.enums.HumanArmorShape;
@@ -193,10 +195,15 @@ public class HudIngame extends Gui {
 
                 this.debugOffsetRight += space;
 
-                drawDebugScreenLineRight(GL41.glGetString(GL41.GL_VENDOR));
-                drawDebugScreenLineRight(GL41.glGetString(GL41.GL_RENDERER));
-                drawDebugScreenLineRight(GL41.glGetString(GL41.GL_VERSION));
+                drawDebugScreenLineRight(OpenGLHelper.vendor);
+                drawDebugScreenLineRight(OpenGLHelper.renderer);
+                drawDebugScreenLineRight(OpenGLHelper.version);
                 drawDebugScreenLineRight(String.format("OpenGL %s.%s", GL41.glGetInteger(GL41.GL_MAJOR_VERSION), GL41.glGetInteger(GL41.GL_MINOR_VERSION)));
+                long availableVRam = OpenGLHelper.availableVRam();
+                long totalVRam = OpenGLHelper.totalVRam();
+                if (totalVRam != -1 || availableVRam != -1) {
+                    drawDebugScreenLineRight(String.format("Available Video Memory (%sMB) of %sMB", (availableVRam / 1024), (totalVRam / 1024)));
+                }
                 drawDebugScreenLineRight("Resolution: " + this.mc.gameWindow.getWidthPixels() + "x" + this.mc.gameWindow.getHeightPixels());
                 drawDebugScreenLineRight("Render Resolution: " + this.mc.renderer.getRenderWidth() + "x" + this.mc.renderer.getRenderHeight());
 
@@ -210,7 +217,7 @@ public class HudIngame extends Gui {
                     int playerZ = MathHelper.floor(this.mc.thePlayer.z);
 
 
-                    List<RenderRegion> allRegions = terrainRenderer.regionBuffer.getAllRegions();
+                    List<RenderRegion<TessellatorTerrainImpl.TerrainVertexConfig>> allRegions = terrainRenderer.regionBuffer.getAllRegions();
                     int totalEntries = 0;
                     int visibleEntries = 0;
                     for (int i = 0; i < allRegions.size(); i++) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorDurability.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorDurability.java
index 06a5c0a1b..00bf0254f 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorDurability.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorDurability.java
@@ -4,12 +4,12 @@ import net.minecraft.client.gui.Gui;
 import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.gui.hud.component.layout.Layout;
 import net.minecraft.client.option.GameSettings;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
+import net.minecraft.core.util.helper.LightIndexHelper;
 
 public class HudComponentArmorDurability
     extends HudComponentMovable {
@@ -45,7 +45,7 @@ public class HudComponentArmorDurability
             if (stack != null) {
                 int xx = x + 2;
                 int yy = y + 48 - i * 16;
-                ItemModelDispatcher.getInstance().getDispatch(stack).renderGui(GLRenderer.getTessellator(), null, stack, xx, yy, LightmapHelper.getLightmapCoord(15, 15), partialTick);
+                ItemModelDispatcher.getInstance().getDispatch(stack).renderGui(GLRenderer.getTessellator(), null, stack, xx, yy, LightIndexHelper.lightIndex2i(15, 15), partialTick);
 //                glDisable(GL_LIGHTING);
 
                 if (stack.isItemStackDamageable()) {
@@ -70,7 +70,7 @@ public class HudComponentArmorDurability
 
             int xx = x + 2;
             int yy = y + 48 - i * 16;
-            ItemModelDispatcher.getInstance().getDispatch(stack).renderGui(GLRenderer.getTessellator(), null, stack, xx, yy, LightmapHelper.getLightmapCoord(15, 15), 0.0f);
+            ItemModelDispatcher.getInstance().getDispatch(stack).renderGui(GLRenderer.getTessellator(), null, stack, xx, yy, LightIndexHelper.lightIndex2i(15, 15), 0.0f);
 //            glDisable(GL_LIGHTING);
 
             if (stack.isItemStackDamageable()) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHeldItemCount.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHeldItemCount.java
index 6c76c10c4..9faa2a7ee 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHeldItemCount.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHeldItemCount.java
@@ -5,12 +5,12 @@ import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.gui.hud.component.layout.Layout;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.renderer.State;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.helper.LightIndexHelper;
 
 import java.awt.Color;
 
@@ -72,7 +72,7 @@ public class HudComponentHeldItemCount
                 GLRenderer.enableState(State.DEPTH_TEST);
                 GLRenderer.disableState(State.BLEND);
                 Lighting.enableInventoryLight();
-                ItemModelDispatcher.getInstance().getDispatch(heldItemStack).renderGui(GLRenderer.getTessellator(), null, heldItemStack, xx, yy, LightmapHelper.getLightmapCoord(15, 15), partialTick);
+                ItemModelDispatcher.getInstance().getDispatch(heldItemStack).renderGui(GLRenderer.getTessellator(), null, heldItemStack, xx, yy, LightIndexHelper.lightIndex2i(15, 15), partialTick);
                 Lighting.disable();
             }
         }
@@ -94,7 +94,7 @@ public class HudComponentHeldItemCount
         GLRenderer.enableState(State.DEPTH_TEST);
         GLRenderer.disableState(State.BLEND);
         Lighting.enableInventoryLight();
-        ItemModelDispatcher.getInstance().getDispatch(heldItemStack).renderGui(GLRenderer.getTessellator(), null, heldItemStack, xx, yy, LightmapHelper.getLightmapCoord(15, 15), 0.0f);
+        ItemModelDispatcher.getInstance().getDispatch(heldItemStack).renderGui(GLRenderer.getTessellator(), null, heldItemStack, xx, yy, LightIndexHelper.lightIndex2i(15, 15), 0.0f);
         Lighting.disable();
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java
index 546d10460..612ca2ed0 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java
@@ -6,7 +6,6 @@ import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.gui.hud.component.layout.Layout;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.Scissor;
 import net.minecraft.client.render.item.model.ItemModel;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
@@ -17,6 +16,7 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.inventory.container.ContainerInventory;
+import net.minecraft.core.util.helper.LightIndexHelper;
 
 import static net.minecraft.client.Minecraft.HOTBAR_SWAP_ANIMATION_LENGTH_TICKS;
 
@@ -194,7 +194,7 @@ public class HudComponentHotbar
             GLRenderer.modelM4f().translate(-(x + 8), -(y + 12), 0.0F);
         }
 //        itemModel.renderItemIntoGui(GLRenderer.getTessellator(), mc.font, mc.textureManager, itemstack, x, y, 1.0f);
-        itemModel.renderGui(GLRenderer.getTessellator(), null, itemstack, x, y, LightmapHelper.getLightmapCoord(15, 15), partialTick);
+        itemModel.renderGui(GLRenderer.getTessellator(), null, itemstack, x, y, LightIndexHelper.lightIndex2i(15, 15), partialTick);
         if (animProgress > 0.0F) {
             GLRenderer.popFrame();
         }
@@ -204,7 +204,7 @@ public class HudComponentHotbar
     private void renderItem(Minecraft mc, ItemStack itemStack, int x, int y) {
         ItemModel itemModel = ItemModelDispatcher.getInstance().getDispatch(itemStack.getItem());
 //        itemModel.renderItemIntoGui(GLRenderer.getTessellator(), mc.font, mc.textureManager, itemStack, x, y, 1.0f);
-        itemModel.renderGui(GLRenderer.getTessellator(), null, itemStack, x, y, LightmapHelper.getLightmapCoord(15, 15), 1f);
+        itemModel.renderGui(GLRenderer.getTessellator(), null, itemStack, x, y, LightIndexHelper.lightIndex2i(15, 15), 1f);
         itemModel.renderItemOverlayIntoGUI(GLRenderer.getTessellator(), mc.font, mc.textureManager, itemStack, x, y, null, 1.0f);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java b/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
index 95f0b5379..b07d41795 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
@@ -12,6 +12,7 @@ import net.minecraft.core.Global;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL41;
 
@@ -173,7 +174,7 @@ public class GuiElementToastsHud extends Gui {
 
         GLRenderer.enableState(State.DEPTH_TEST);
         ItemStack icon = toast.getIcon(duration);
-        if (icon != null) ItemModelDispatcher.getInstance().getDispatch(icon).renderGui(GLRenderer.getTessellator(), null, icon, x + 8, y + 8, LightmapHelper.getLightmapCoord(15, 15), 1.0f);
+        if (icon != null) ItemModelDispatcher.getInstance().getDispatch(icon).renderGui(GLRenderer.getTessellator(), null, icon, x + 8, y + 8, LightIndexHelper.lightIndex2i(15, 15), 1.0f);
         GLRenderer.disableState(State.DEPTH_TEST);
     }
 
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 bd72be525..242c1cace 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
@@ -315,9 +315,9 @@ public abstract class PlayerController {
         final int prevStackSize = stack.stackSize;
         final @Nullable ItemStack newItemStack = stack.useItem(world, player);
         if (newItemStack != stack || newItemStack.stackSize != prevStackSize) {
-            player.inventory.setCurrentItem(newItemStack);
+            player.inventory.setItem(player.inventory.getCurrentSlot(), newItemStack);
             if (newItemStack == null || newItemStack.stackSize <= 0) {
-                player.inventory.setCurrentItem(null);
+                player.inventory.setItem(player.inventory.getCurrentSlot(), null);
             }
 
             return true;
diff --git a/game/client/src/main/java/net/minecraft/client/render/CameraSorter.java b/game/client/src/main/java/net/minecraft/client/render/CameraSorter.java
deleted file mode 100644
index 82cfc3648..000000000
--- a/game/client/src/main/java/net/minecraft/client/render/CameraSorter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package net.minecraft.client.render;
-
-import net.minecraft.client.render.camera.ICamera;
-import net.minecraft.client.render.terrain.ChunkRenderer;
-
-import java.util.Comparator;
-
-public class CameraSorter
-    implements Comparator<ChunkRenderer>
-{
-
-    public CameraSorter(ICamera camera)
-    {
-        posX = -camera.getX();
-        posY = -camera.getY();
-        posZ = -camera.getZ();
-    }
-
-    public int sortByDistanceToEntity(ChunkRenderer a, ChunkRenderer b)
-    {
-        double dx1 = (double)a.xm + posX;
-        double dy1 = (double)a.ym + posY;
-        double dz1 = (double)a.zm + posZ;
-        double dx2 = (double)b.xm + posX;
-        double dy2 = (double)b.ym + posY;
-        double dz2 = (double)b.zm + posZ;
-        return (int)(((dx1 * dx1 + dy1 * dy1 + dz1 * dz1) - (dx2 * dx2 + dy2 * dy2 + dz2 * dz2)) * 1024D);
-    }
-
-    @Override
-    public int compare(ChunkRenderer o1, ChunkRenderer o2)
-    {
-        return sortByDistanceToEntity(o1, o2);
-    }
-
-    private final double posX;
-    private final double posY;
-    private final double posZ;
-}
diff --git a/game/client/src/main/java/net/minecraft/client/render/EntityRendererDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/EntityRendererDispatcher.java
index dcf353d2f..e78da2c76 100644
--- a/game/client/src/main/java/net/minecraft/client/render/EntityRendererDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/EntityRendererDispatcher.java
@@ -141,7 +141,7 @@ public final class EntityRendererDispatcher {
         final double lerpPosZ = entity.zo + (entity.z - entity.zo) * (double) partialTick;
         final float lerpYaw = entity.yRotO + (entity.yRot - entity.yRotO) * partialTick;
 
-        GLRenderer.setLightmapCoord1i(entity.getLightmap(partialTick));
+        GLRenderer.setLightmapCoord1i(entity.getLightIndex(partialTick));
         GLRenderer.setColor3f(1f, 1f, 1f);
         renderEntityWithPosYaw(tessellator, entity, lerpPosX - renderPosX, lerpPosY - renderPosY, lerpPosZ - renderPosZ, lerpYaw, partialTick);
     }
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 7c8791428..c6d75ba27 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
@@ -50,8 +50,8 @@ public class ItemRenderer {
         ItemStack itemstack = this.itemToRender;
         if (itemstack != null) {
             GLRenderer.setColor4f(1f, 1f, 1f, 1f);
-            GLRenderer.setLightmapCoord1i(this.mc.thePlayer.getLightmap(partialTick));
-            ItemModelDispatcher.getInstance().getDispatch(itemstack.getItem()).renderFirstPerson(GLRenderer.getTessellator(), this, player, itemstack, player.getLightmap(partialTick), partialTick);
+            GLRenderer.setLightmapCoord1i(this.mc.thePlayer.getLightIndex(partialTick));
+            ItemModelDispatcher.getInstance().getDispatch(itemstack.getItem()).renderFirstPerson(GLRenderer.getTessellator(), this, player, itemstack, player.getLightIndex(partialTick), partialTick);
         } else {
 
             GLRenderer.pushFrame();
@@ -60,7 +60,7 @@ public class ItemRenderer {
             GLRenderer.enableState(State.DEPTH_TEST);
             GLRenderer.setDepthFunc(CompareFunc.LESS);
             float brightness = 1.0f;
-            GLRenderer.setLightmapCoord1i(this.mc.thePlayer.getLightmap(partialTick));
+            GLRenderer.setLightmapCoord1i(this.mc.thePlayer.getLightIndex(partialTick));
             GLRenderer.setColor4f(brightness, brightness, brightness, 1.0f);
             EntityRenderer<? extends Entity> render = EntityRendererDispatcher.instance.getRenderer(this.mc.thePlayer);
             MobRendererPlayer playerRenderer = (MobRendererPlayer) render;
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 feb36419c..3f7e15b42 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
@@ -2,6 +2,7 @@ package net.minecraft.client.render;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.core.block.Block;
+import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
@@ -19,12 +20,12 @@ final public class LightingCache {
     private int opacityCached = 0; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE];
     private int opacityValue = 0; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE];
 
-    private int lightmapCoordCached = 0; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE];
-    private final int[] lightmapCoordValue = new int[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE];
+    private int lightIndexCached = 0; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE];
+    private final byte[] lightIndexValue = new byte[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE];
 
     private final @NotNull TilePos offset = new TilePos(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
 
-    private @NotNull Block<?> block;
+    private @NotNull Block<?> block = Blocks.AIR;
     private WorldSource access;
     private final @NotNull TilePos queryPos = new TilePos();
 
@@ -39,7 +40,7 @@ final public class LightingCache {
             this.access = source;
             this.brightnessCached = 0;
             this.opacityCached = 0;
-            this.lightmapCoordCached = 0;
+            this.lightIndexCached = 0;
             this.offset.set(tilePos);
         }
     }
@@ -71,14 +72,14 @@ final public class LightingCache {
         return bitGet(this.opacityValue, index);
     }
 
-    public int getLightmapCoord(int relX, int relY, int relZ) {
+    public byte getLightIndex(int relX, int relY, int relZ) {
         int index = (relX + CACHE_RANGE) * CACHE_SIZE * CACHE_SIZE + (relY + CACHE_RANGE) * CACHE_SIZE + (relZ + CACHE_RANGE);
-        if (!bitGet(this.lightmapCoordCached, index)) {
+        if (!bitGet(this.lightIndexCached, index)) {
             int lightEmission = this.block.emission;
-            this.lightmapCoordValue[index] = this.access.getLightmapCoord(this.offset.add(relX, relY, relZ, this.queryPos), lightEmission);
-            this.lightmapCoordCached = bitSet(this.lightmapCoordCached, index);
+            this.lightIndexValue[index] = this.access.getLightIndex(this.offset.add(relX, relY, relZ, this.queryPos), lightEmission);
+            this.lightIndexCached = bitSet(this.lightIndexCached, index);
         }
-        return this.lightmapCoordValue[index];
+        return this.lightIndexValue[index];
     }
 
     private static boolean bitGet(int value, int index) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/LightmapHelper.java b/game/client/src/main/java/net/minecraft/client/render/LightmapHelper.java
index 7689e475a..c1b375e69 100644
--- a/game/client/src/main/java/net/minecraft/client/render/LightmapHelper.java
+++ b/game/client/src/main/java/net/minecraft/client/render/LightmapHelper.java
@@ -15,6 +15,7 @@ import net.minecraft.client.util.helper.Buffer;
 import net.minecraft.core.util.helper.Color;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL41;
 import org.slf4j.Logger;
 
@@ -160,7 +161,7 @@ public class LightmapHelper {
 		}
 	}
 	
-	public void generateColorizedLightmap(World world, float partialTicks) {
+	public void generateColorizedLightmap(@NotNull World world, float partialTicks) {
 		float ambientBrightness = world.getAmbientBrightness(partialTicks);
 		float brightness = GameSettings.BRIGHTNESS.value - 0.5f;
 
@@ -204,7 +205,7 @@ public class LightmapHelper {
 		}
 	}
 	
-	public void generateCustomLightmap(World world) {
+	public void generateCustomLightmap(@NotNull World world) {
 		float ambientBrightness = (world.getAmbientBrightness(1.0f) - 0.2f) / 0.8f;
 		float brightness = GameSettings.BRIGHTNESS.value;
 		
@@ -248,7 +249,7 @@ public class LightmapHelper {
 //		}
 	}
 
-	public void setLightmapTextureData(int[] data) {
+	public void setLightmapTextureData(int @NotNull [] data) {
 		OpenGLHelper.checkError("pre set lightmap data");
 
 		Buffer.checkBufferSize(16 * 16 * 4);
@@ -296,69 +297,10 @@ public class LightmapHelper {
 		return color * (1.0f - gamma) + color2 * gamma;
 	}
 
-	public float getBrightnessRemoveMinLight(World world, int i) {
+	public float getBrightnessRemoveMinLight(@NotNull World world, int i) {
 		float brightness = world.worldType.getBrightnessRamp()[i];
 		float min = 0.05f;
 
 		return (brightness - min) / (1.0f - min);
 	}
-
-	public static int getLightmapCoord(int skylight, int blocklight) {
-		return skylight << 20 | blocklight << 4;
-	}
-
-	public static int getLightmapCoord(float skylight, float blocklight) {
-		return getLightmapCoord((int) (0xF * skylight), (int) (0xF * blocklight));
-	}
-	
-	public static int getOverbrightLightmapCoord(int skylight) {
-		return getLightmapCoord(skylight, 15);
-	}
-	
-	public static int max(int lightmapCoord1, int lightmapCoord2) {
-		int sky1 = lightmapCoord1 >> 16;
-		int sky2 = lightmapCoord2 >> 16;
-		
-		int block1 = lightmapCoord1 & 0xFFFF;
-		int block2 = lightmapCoord2 & 0xFFFF;
-		
-		return Math.max(sky1, sky2) << 16 | Math.max(block1, block2);
-	}
-	
-	public static int avg(int lmc0, int lmc1) {
-		int sky0 = lmc0 >> 16;
-		int sky1 = lmc1 >> 16;
-		
-		int block0 = lmc0 & 0xFFFF;
-		int block1 = lmc1 & 0xFFFF;
-		
-		int sky = (sky0 + sky1) >> 1;
-		int block = (block0 + block1) >> 1;
-		
-		return sky << 16 | block;
-	}
-	
-	public static int avg(int lmc0, int lmc1, int lmc2, int lmc3) {
-//		int lmc01 = (lmc0 + lmc1) >> 1;
-//		int lmc23 = (lmc2 + lmc3) >> 1;
-//		return (lmc01 + lmc23) >> 1;
-		return avg(avg(lmc0, lmc1), avg(lmc2, lmc3));
-	}
-	
-	public static int setBlocklightValue(int lightmapCoord, int blocklight) {
-		return lightmapCoord & 0xFFFF0000 | blocklight << 4;
-	}
-
-	public static int getBlockLightFromCoord(int lightmapCoord) {
-		return  ((lightmapCoord) & 0xFFFF) >> 4;
-	}
-	
-	public static int setSkylightValue(int lightmapCoord, int skylight) {
-		return lightmapCoord & 0x0000FFFF | skylight << 20;
-	}
-
-	public static int getSkyLightFromCoord(int lightmapCoord) {
-		return  (lightmapCoord & 0xFFFF0000) >> 20;
-	}
-
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/OpenGLHelper.java b/game/client/src/main/java/net/minecraft/client/render/OpenGLHelper.java
index 131e4ddf2..d27048aa6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/OpenGLHelper.java
+++ b/game/client/src/main/java/net/minecraft/client/render/OpenGLHelper.java
@@ -6,8 +6,12 @@ import net.minecraft.core.Global;
 import net.minecraft.core.enums.EnumOS;
 import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.ARBFramebufferObject;
+import org.lwjgl.opengl.ATIMeminfo;
 import org.lwjgl.opengl.GL41;
 import org.lwjgl.opengl.GLCapabilities;
+import org.lwjgl.opengl.NVXGPUMemoryInfo;
+import org.lwjgl.system.MemoryStack;
+import org.lwjgl.system.MemoryUtil;
 import org.slf4j.Logger;
 
 import java.util.HashSet;
@@ -21,18 +25,24 @@ public class OpenGLHelper {
     public static int[] versionPairs = new int[] {4, 6, 4, 3, 4, 1};
 
     public static boolean contextCreated = false;
-    public static boolean gl46 = false;
-    public static boolean gl43 = false;
+    public static GLCapabilities capabilities;
 
     public static @NotNull String version = "Unknown";
     public static @NotNull String vendor = "Unknown";
     public static @NotNull String renderer = "Unknown";
 
+    public static int major = 0;
+    public static int minor = 0;
+
+    private static int ATI_STARTING_FREE_AMOUNT = 0;
+
     public static void testCapabilities(@NotNull GLCapabilities capabilities) {
         contextCreated = true;
         LOGGER.info("");
         LOGGER.info("=== GPU VENDOR INFO ===");
-        LOGGER.info("OpenGL {}.{}", GL41.glGetInteger(GL41.GL_MAJOR_VERSION), GL41.glGetInteger(GL41.GL_MINOR_VERSION));
+        major = GL41.glGetInteger(GL41.GL_MAJOR_VERSION);
+        minor = GL41.glGetInteger(GL41.GL_MINOR_VERSION);
+        LOGGER.info("OpenGL {}.{}", major, minor);
 
         version = Objects.requireNonNullElse(GL41.glGetString(GL41.GL_VERSION), "Query Failure");
         vendor = Objects.requireNonNullElse(GL41.glGetString(GL41.GL_VENDOR), "Query Failure");
@@ -44,20 +54,52 @@ public class OpenGLHelper {
 
         LOGGER.info("");
 
-        LOGGER.info("GL_ARB_framebuffer_object: {}", capabilities.GL_ARB_framebuffer_object);
-        LOGGER.info("GL_ARB_occlusion_query: {}", capabilities.GL_ARB_occlusion_query);
-        LOGGER.info("GL_NV_fog_distance: {}", capabilities.GL_NV_fog_distance);
-
-        gl43 = capabilities.OpenGL43;;
-        gl46 = capabilities.OpenGL46;
+        OpenGLHelper.capabilities = capabilities;
 
         if (!capabilities.OpenGL41) {
             if (Minecraft.getOs() == EnumOS.macos) {
-                LOGGER.warn("BTA Requires OpenGL4.1 but only {} was found! If you're on MacOS this is probably just Apple misreporting the GLVersion number and not actually due to a lack of support.", GL41.glGetString(GL41.GL_VERSION));
+                LOGGER.warn("BTA Requires OpenGL4.1 but only {} was found! If you're on MacOS this is probably just Apple misreporting the GLVersion number and not actually due to a lack of support.", version);
             } else {
-                LOGGER.error("BTA Requires OpenGL4.1 but only {} was found!", GL41.glGetString(GL41.GL_VERSION));
+                LOGGER.error("BTA Requires OpenGL4.1 but only {} was found!", version);
+            }
+        }
+
+        if (capabilities.GL_ATI_meminfo) {
+            try(var stack = MemoryStack.stackPush()) {
+                var intBuff = stack.mallocInt(4);
+                GL41.glGetIntegerv(ATIMeminfo.GL_VBO_FREE_MEMORY_ATI, intBuff);
+                ATI_STARTING_FREE_AMOUNT = intBuff.get(0);
+            }
+
+        }
+    }
+
+    /**
+     * @return Total amount of VRam (or VBO space) the GPU has in KB
+     */
+    public static long totalVRam() {
+        if (capabilities.GL_NVX_gpu_memory_info) {
+            return GL41.glGetInteger(NVXGPUMemoryInfo.GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX);
+        } else if (capabilities.GL_ATI_meminfo) {
+            return ATI_STARTING_FREE_AMOUNT;
+        }
+        return -1;
+    }
+
+    /**
+     * @return Amount of Available VRam (or VBO space) in KB
+     */
+    public static long availableVRam() {
+        if (capabilities.GL_NVX_gpu_memory_info) { // https://registry.khronos.org/OpenGL/extensions/NVX/NVX_gpu_memory_info.txt
+            return GL41.glGetInteger(NVXGPUMemoryInfo.GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX);
+        } else if (capabilities.GL_ATI_meminfo) { // Unsure if implemented correctly, ATI's extension kinda sucks https://registry.khronos.org/OpenGL/extensions/ATI/ATI_meminfo.txt
+            try(var stack = MemoryStack.stackPush()) {
+                var intBuff = stack.mallocInt(4);
+                GL41.glGetIntegerv(ATIMeminfo.GL_VBO_FREE_MEMORY_ATI, intBuff);
+                return intBuff.get(0);
             }
         }
+        return -1;
     }
 
     public static void checkError(String info) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java b/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java
index 6f3fa2e70..4084cc71b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java
+++ b/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java
@@ -22,6 +22,7 @@ import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
 import org.joml.primitives.AABBdc;
+import org.lwjgl.opengl.GL41;
 
 import java.util.List;
 import java.util.Random;
@@ -87,7 +88,14 @@ public final class ParticleEngine {
      */
     public void renderParticles(@NotNull ICamera camera, float partialTick) {
         GLRenderer.pushFrame();
+        GLRenderer.setColor4f(1f, 1f, 1f, 1f);
         GLRenderer.setShader(Shaders.PARTICLE);
+        GL41.glActiveTexture(GL41.GL_TEXTURE2);
+        TextureRegistry.worldAtlas.layerTextureMap.get("emissive").bind();
+        GL41.glActiveTexture(GL41.GL_TEXTURE3);
+        TextureRegistry.worldAtlas.layerTextureMap.get("maskColor").bind();
+        GL41.glActiveTexture(GL41.GL_TEXTURE0);
+        TextureRegistry.worldAtlas.bind();
         GLRenderer.enableState(State.BLEND);
         GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA);
         GLRenderer.enableState(State.DEPTH_TEST);
@@ -103,7 +111,6 @@ public final class ParticleEngine {
             if (this.particles[tt].isEmpty()) {
                 continue;
             }
-            TextureRegistry.worldAtlas.bind();
             tessellator.setTranslation(-xOff, -yOff, -zOff);
             tessellator.startDrawingParticles();
             for (int i = 0; i < this.particles[tt].size(); i++) {
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 f96016852..66a3c52f8 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
@@ -264,7 +264,7 @@ public class RenderGlobal
         this.zMaxChunk = this.zChunks;
 
         for (ChunkRenderer cr : this.dirtyChunks) {
-            cr.dirty = false;
+            cr.setDirty(false);
         }
 
         this.dirtyChunks.clear();
@@ -277,7 +277,7 @@ public class RenderGlobal
                     this.chunkRenderers[index] = this.mc.terrainRenderer.createChunkRenderer(this.world, this.renderableTileEntities, x * RENDER_CHUNK_SIZE, y * RENDER_CHUNK_SIZE, z * RENDER_CHUNK_SIZE, RENDER_CHUNK_SIZE);
                     this.chunkRenderers[index].visible = true;
                     this.chunkRenderers[index].id = count++;
-                    this.chunkRenderers[index].setDirty();
+                    this.chunkRenderers[index].setDirty(true);
                     this.dirtyChunks.add(this.chunkRenderers[index]);
                     id += ChunkRenderer.MAX_RENDER_PASSES + 1;
                 }
@@ -606,9 +606,9 @@ public class RenderGlobal
                     }
 
                     ChunkRenderer renderer = this.chunkRenderers[(z * this.yChunks + y) * this.xChunks + x];
-                    boolean wasDirty = renderer.dirty;
+                    boolean wasDirty = renderer.isDirty();
                     renderer.setPos(xx, yy, zz);
-                    if (!wasDirty && renderer.dirty) {
+                    if (!wasDirty && renderer.isDirty()) {
                         this.dirtyChunks.add(renderer);
                     }
                 }
@@ -624,7 +624,7 @@ public class RenderGlobal
         for (int i = 0; i < 10; i++) {
             this.chunkFixOffs = (this.chunkFixOffs + 1) % this.chunkRenderers.length;
             ChunkRenderer chunkRenderer = this.chunkRenderers[this.chunkFixOffs];
-            if (chunkRenderer.dirty && !this.dirtyChunks.contains(chunkRenderer)) {
+            if (chunkRenderer.isDirty() && !this.dirtyChunks.contains(chunkRenderer)) {
                 this.dirtyChunks.add(chunkRenderer);
             }
         }
@@ -1125,7 +1125,7 @@ public class RenderGlobal
             }
             for (ChunkRenderer renderer : this.nearChunks) {
                 if (renderer.rebuild(true)) {
-                    renderer.dirty = false;
+                    renderer.setDirty(false);
                     this.dirtyChunks.remove(renderer);
                 }
             }
@@ -1141,7 +1141,7 @@ public class RenderGlobal
                 break;
             }
             if (chunkx.rebuild(false)) {
-                chunkx.dirty = false;
+                chunkx.setDirty(false);
                 this.dirtyChunks.remove(chunkx);
             }
         }
@@ -1169,7 +1169,7 @@ public class RenderGlobal
             tessellator.setTranslation(-x, -y, -z);
             tessellator.lockColor();
             // Make sure it's active to prevent crash if a model doesnt enable it
-            tessellator.setLightmapCoord1i(LightmapHelper.getLightmapCoord(15, 0));
+            tessellator.setLightmapCoord2i(15, 0);
             BlockModelDispatcher.getInstance()
                 .getDispatch(block)
                 .renderWithOverrideTexture(
@@ -1783,9 +1783,9 @@ public class RenderGlobal
                     int p = (zz * this.yChunks + yy) * this.xChunks + xx;
 
                     ChunkRenderer renderer = this.chunkRenderers[p];
-                    if (!renderer.dirty) {
+                    if (!renderer.isDirty()) {
                         this.dirtyChunks.add(renderer);
-                        renderer.setDirty();
+                        renderer.setDirty(true);
                     }
                 }
             }
@@ -1864,9 +1864,9 @@ public class RenderGlobal
         }
         if (seasonChanged) {
             for (ChunkRenderer chunkRenderer : this.chunkRenderers) {
-                if (/*chunkRenderer.skyLit && */!chunkRenderer.dirty) {
+                if (/*chunkRenderer.skyLit && */!chunkRenderer.isDirty()) {
                     this.dirtyChunks.add(chunkRenderer);
-                    chunkRenderer.setDirty();
+                    chunkRenderer.setDirty(true);
                 }
             }
         }
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 7f7548571..6aaf4e042 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
@@ -649,8 +649,8 @@ public class WorldRenderer {
         GLRenderer.setDepthFunc(CompareFunc.LESS_EQUAL);
         GL41.glActiveTexture(GL41.GL_TEXTURE2);
         TextureRegistry.worldAtlas.layerTextureMap.get("emissive").bind();
-//        GL41.glActiveTexture(GL41.GL_TEXTURE3);
-//        TextureRegistry.worldAtlas.layerTextureMap.get("maskColor").bind();
+        GL41.glActiveTexture(GL41.GL_TEXTURE3);
+        TextureRegistry.worldAtlas.layerTextureMap.get("maskColor").bind();
         GL41.glActiveTexture(GL41.GL_TEXTURE0);
         Lighting.enableLight();
         GLRenderer.setShader(Shaders.TERRAIN);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModel.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModel.java
index d16c5cbda..1ae54ebbe 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModel.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModel.java
@@ -24,7 +24,7 @@ public abstract class BlockModel<T extends BlockLogic> {
     public abstract boolean render(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos);
     public abstract boolean renderNoCulling(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos);
     public abstract boolean renderWithOverrideTexture(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos, IconCoordinate overrideTexture);
-    public abstract void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord);
+    public abstract void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex);
 
     public abstract boolean shouldItemRender3d();
     public abstract @NotNull DisplayPos getItemDisplayPos(@NotNull String id);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrossedSquares.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrossedSquares.java
index 16b5112a7..b510836da 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrossedSquares.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrossedSquares.java
@@ -16,7 +16,7 @@ public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelSt
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         // Used for the rendering for the block inside the jar
         final float yOffset = 0.0F;
 
@@ -32,7 +32,7 @@ public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelSt
         tessellator.offsetTranslation(-0.5, -0.5, -0.5);
         tessellator.startDrawingQuads();
         tessellator.setColor1i(getStandaloneTintColor(metadata));
-        tessellator.setLightmapCoord1i(lightmapCoord);
+        tessellator.setLightmapCoord1i(lightIndex);
 
         double xd = 0;
         double yd = 0;
@@ -67,7 +67,7 @@ public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelSt
 
     @Override
     public boolean render(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos) {
-        tessellator.setLightmapCoord1i(this.block.getLightmapCoord(worldSource, tilePos));
+        tessellator.setLightmapCoord1i(this.block.getLightIndex(worldSource, tilePos));
 
         int color = BlockColorDispatcher.getInstance().getDispatch(this.block).getWorldColor(worldSource, tilePos, 0);
         float r = (float) (color >> 16 & 0xff) / 255F;
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 7684fd75a..babac5c11 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
@@ -267,10 +267,10 @@ public final class BlockModelDispatcher
         addDispatch(new BlockModelGeneric<>(Blocks.PUMICE_DRY, loadDataModel("minecraft:block/pumice")));
         addDispatch(new BlockModelGeneric<>(Blocks.PUMICE_WET, loadDataModel("minecraft:block/pumice_wet")));
 
-        addDispatch(new BlockModelGeneric<>(Blocks.MOSS_STONE, loadDataModel("minecraft:block/stone_mossy")));
-        addDispatch(new BlockModelGeneric<>(Blocks.MOSS_BASALT, loadDataModel("minecraft:block/basalt_mossy")));
-        addDispatch(new BlockModelGeneric<>(Blocks.MOSS_LIMESTONE, loadDataModel("minecraft:block/limestone_mossy")));
-        addDispatch(new BlockModelGeneric<>(Blocks.MOSS_GRANITE, loadDataModel("minecraft:block/granite_mossy")));
+        addDispatch(new BlockModelGeneric<>(Blocks.MOSS_STONE, loadDataModel("minecraft:block/moss/stone")));
+        addDispatch(new BlockModelGeneric<>(Blocks.MOSS_BASALT, loadDataModel("minecraft:block/moss/basalt")));
+        addDispatch(new BlockModelGeneric<>(Blocks.MOSS_LIMESTONE, loadDataModel("minecraft:block/moss/limestone")));
+        addDispatch(new BlockModelGeneric<>(Blocks.MOSS_GRANITE, loadDataModel("minecraft:block/moss/granite")));
 
         addDispatch(new BlockModelGeneric<>(Blocks.SAND, loadDataModel("minecraft:block/sand")));
         addDispatch(new BlockModelGeneric<>(Blocks.GRAVEL, loadDataModel("minecraft:block/gravel")));
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDoor.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDoor.java
index da9386924..2f7d22214 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDoor.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDoor.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.block.model;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
@@ -19,7 +18,7 @@ public class BlockModelDoor<T extends BlockLogicDoor> extends BlockModelStandard
 
     @Override
     public boolean render(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos) {
-        tessellator.setLightmapCoord1i(LightmapHelper.getLightmapCoord(15, 15));
+        tessellator.setLightmapCoord2i(15, 15);
         tessellator.setColorOpaque3f(1.0f, 1.0f, 1.0f);
 
         AABBdc bounds = this.block.getBoundsFromState(worldSource, tilePos);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelEmpty.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelEmpty.java
index c15c7c70e..46e414d49 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelEmpty.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelEmpty.java
@@ -21,7 +21,7 @@ public class BlockModelEmpty<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public void renderStandalone(@NotNull final TessellatorGeneral tessellator, final int metadata, final int lightmapCoord) {
+    public void renderStandalone(@NotNull final TessellatorGeneral tessellator, final int metadata, final byte lightIndex) {
 
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFence.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFence.java
index 4393cbb2e..367a8d321 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFence.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFence.java
@@ -74,7 +74,7 @@ public class BlockModelFence<T extends BlockLogicFence> extends BlockModelStanda
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         tessellator.offsetTranslation(-0.5, -0.5, -0.5);
         tessellator.startDrawingQuads();
         tessellator.setColor1i(getStandaloneTintColor(metadata));
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceGate.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceGate.java
index 32255f8bc..f0046ca14 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceGate.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceGate.java
@@ -156,7 +156,7 @@ public class BlockModelFenceGate<T extends BlockLogicFenceGate> extends BlockMod
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         tessellator.offsetTranslation(-0.5, -0.5, -0.5);
         tessellator.startDrawingQuads();
         tessellator.setColor1i(getStandaloneTintColor(metadata));
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
index 137361f9e..d3a361a8e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
@@ -36,7 +36,7 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
     @Override
     public boolean render(@NotNull TessellatorGeneral t, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos) {
         float brightness = 1.0f;
-        t.setLightmapCoord1i(this.block.getLightmapCoord(worldSource, tilePos));
+        t.setLightmapCoord1i(this.block.getLightIndex(worldSource, tilePos));
         t.setColorOpaque3f(brightness, brightness, brightness);
 
         TilePos queryPos = new TilePos();
@@ -327,7 +327,7 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         int color = getStandaloneTintColor(metadata);
         GLRenderer.modelM4f().rotateY(Math.toRadians(90));
         AABBd bounds = new AABBd(0, 0, 0, 1, 1, 1);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFire.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFire.java
index ebf152822..20231603c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFire.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFire.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.block.model;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.world.WorldClient;
@@ -32,7 +31,7 @@ public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T>
         if (renderBlocks.overrideBlockTexture != null) {
             tex = renderBlocks.overrideBlockTexture;
         }
-        tessellator.setLightmapCoord1i(LightmapHelper.getOverbrightLightmapCoord(worldSource.getSavedLightValue(LightLayer.Sky, tilePos)));
+        tessellator.setLightmapCoord2i(worldSource.getSavedLightValue(LightLayer.Sky, tilePos), 15);
         double uMin = tex.getIconUMin();
         double uMax = tex.getIconUMax();
         double vMin = tex.getIconVMin();
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 695e768c9..1d7e5ed30 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
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.block.model;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
@@ -8,7 +7,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicFluid;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.material.Materials;
-import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePos;
@@ -16,8 +15,6 @@ 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> {
@@ -71,10 +68,10 @@ public class BlockModelFluid<T extends BlockLogicFluid> extends BlockModelStanda
             } else {
                 rotation = 0.0F;
             }
-            int light = this.block.getLightmapCoord(worldSource, tilePos);
-            int lightUp = this.block.getLightmapCoord(worldSource, tilePos.up(queryPos));
+            byte light = this.block.getLightIndex(worldSource, tilePos);
+            byte lightUp = this.block.getLightIndex(worldSource, tilePos.up(queryPos));
 
-            tessellator.setLightmapCoord1i(LightmapHelper.max(light, lightUp));
+            tessellator.setLightmapCoord1i(LightIndexHelper.max(light, lightUp));
             if (tex.namespaceId.toString().contains("_flowing")) {
                 float cos = Math.cos(-rotation + Math.PI_OVER_2_f);
                 float sin = Math.sin(-rotation + Math.PI_OVER_2_f);
@@ -115,7 +112,7 @@ public class BlockModelFluid<T extends BlockLogicFluid> extends BlockModelStanda
 
         }
         if (renderBlocks.renderAllFaces || flag1) {
-            tessellator.setLightmapCoord1i(this.block.getLightmapCoord(worldSource, tilePos.down(queryPos)));
+            tessellator.setLightmapCoord1i(this.block.getLightIndex(worldSource, tilePos.down(queryPos)));
             tessellator.setNormal(0, -1, 0);
             renderBlocks.renderBottomFace(tessellator, bounds, x, y + yOff, z, getBlockTextureFromSideAndMetadata(Side.TOP, 0));
             didRender = true;
@@ -179,7 +176,7 @@ public class BlockModelFluid<T extends BlockLogicFluid> extends BlockModelStanda
             double v1 = texture.getSubIconV(0.5F - f13 / 2);
             double v2 = texture.getSubIconV(0.5F - f15 / 2);
             double v3 = texture.getSubIconV(0.5F);
-            tessellator.setLightmapCoord1i(this.block.getLightmapCoord(worldSource, posB));
+            tessellator.setLightmapCoord1i(this.block.getLightIndex(worldSource, posB));
             switch (side) {
                 case 0 -> tessellator.setNormal(0, 0, -1);
                 case 1 -> tessellator.setNormal(0, 0, 1);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFullyRotatable.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFullyRotatable.java
index 878664f2f..d8b60d364 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFullyRotatable.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFullyRotatable.java
@@ -64,8 +64,8 @@ public class BlockModelFullyRotatable<T extends BlockLogic> extends BlockModelSt
 
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
-        super.renderStandalone(tessellator, 1, lightmapCoord);
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
+        super.renderStandalone(tessellator, 1, lightIndex);
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLayer.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLayer.java
index c0b1680e4..d3c22d0e8 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLayer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLayer.java
@@ -16,9 +16,9 @@ public class BlockModelLayer<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         tessellator.offsetTranslation(0, 0.25, 0);
-        super.renderStandalone(tessellator, metadata, lightmapCoord);
+        super.renderStandalone(tessellator, metadata, lightIndex);
         tessellator.offsetTranslation(0, -0.25, 0);
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeaves.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeaves.java
index 9ddaa60b5..bb19203f6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeaves.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeaves.java
@@ -33,10 +33,10 @@ public class BlockModelLeaves<T extends BlockLogic> extends BlockModelStandard<T
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         boolean invTint = renderBlocks.useInventoryTint;
         renderBlocks.useInventoryTint = !this.canBeRetro || !isRetro();
-        super.renderStandalone(tessellator, metadata, lightmapCoord);
+        super.renderStandalone(tessellator, metadata, lightIndex);
         renderBlocks.useInventoryTint = invTint;
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRail.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRail.java
index f1625b7fa..deb393612 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRail.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRail.java
@@ -31,7 +31,7 @@ public class BlockModelRail<T extends BlockLogicRail> extends BlockModelStandard
         }
         RailDirection railDirection = this.block.getLogic().getRailDirection(worldSource, tilePos);
         float brightness = 1.0f;
-        tessellator.setLightmapCoord1i(this.block.getLightmapCoord(worldSource, tilePos));
+        tessellator.setLightmapCoord1i(this.block.getLightIndex(worldSource, tilePos));
         if (icon == null) {
             return false;
         }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairs.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairs.java
index cbee89718..81fe3ee8d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairs.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairs.java
@@ -63,7 +63,7 @@ public class BlockModelStairs<T extends BlockLogicStairs> extends BlockModelStan
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         tessellator.offsetTranslation(-0.5, -0.5, -0.5);
         tessellator.startDrawingQuads();
         tessellator.setColor1i(getStandaloneTintColor(metadata));
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
index adae8ffdd..666176f6e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
@@ -73,16 +73,16 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T> {
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         AABBdc bounds = getBlockBoundsForItemRender();
         tessellator.offsetTranslation(-0.5, -0.5, -0.5);
-        renderBlockWithBounds(tessellator, bounds, metadata, lightmapCoord, getStandaloneTintColor(metadata));
+        renderBlockWithBounds(tessellator, bounds, metadata, lightIndex, getStandaloneTintColor(metadata));
         tessellator.offsetTranslation(0.5F, 0.5, 0.5F);
     }
 
-    public final void renderBlockWithBounds(@NotNull TessellatorGeneral tessellator, @NotNull AABBdc bounds, int metadata, int lightmapCoord, int color) {
+    public final void renderBlockWithBounds(@NotNull TessellatorGeneral tessellator, @NotNull AABBdc bounds, int metadata, byte lightIndex, int color) {
         tessellator.startDrawingQuads();
-        tessellator.setLightmapCoord1i(lightmapCoord);
+        tessellator.setLightmapCoord1i(lightIndex);
         tessellator.setColor1i(color);
 
         tessellator.setNormal(0.0f, -1.0f, 0.0f);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTrapDoor.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTrapDoor.java
index 13dbccce2..14cf408fd 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTrapDoor.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTrapDoor.java
@@ -69,9 +69,9 @@ public class BlockModelTrapDoor<T extends BlockLogic> extends BlockModelStandard
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         tessellator.offsetTranslation(0, 0.25, 0);
-        super.renderStandalone(tessellator, metadata, lightmapCoord);
+        super.renderStandalone(tessellator, metadata, lightIndex);
         tessellator.offsetTranslation(0, -0.25, 0);
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelVeryRotatable.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelVeryRotatable.java
index 0310391f4..470553f46 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelVeryRotatable.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelVeryRotatable.java
@@ -48,10 +48,10 @@ public class BlockModelVeryRotatable<T extends BlockLogic> extends BlockModelSta
 
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
         renderBlocks.uvRotateTop = 1;
         renderBlocks.uvRotateBottom = 1;
-        super.renderStandalone(tessellator, 3, lightmapCoord);
+        super.renderStandalone(tessellator, 3, lightIndex);
         renderBlocks.resetRenderBlocks();
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelWireRedstone.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelWireRedstone.java
index a6102efdf..1598a4d1e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelWireRedstone.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelWireRedstone.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.block.model;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
@@ -41,8 +40,7 @@ public class BlockModelWireRedstone<T extends BlockLogic> extends BlockModelStan
 
         TilePos queryPos = new TilePos();
 
-        int lmc = LightmapHelper.getLightmapCoord(worldSource.getSavedLightValue(LightLayer.Sky, tilePos), Math.max(worldSource.getSavedLightValue(LightLayer.Block, tilePos), meta & 0xF));
-        tessellator.setLightmapCoord1i(lmc);
+        tessellator.setLightmapCoord2i(worldSource.getSavedLightValue(LightLayer.Sky, tilePos), Math.max(worldSource.getSavedLightValue(LightLayer.Block, tilePos), meta & 0xF));
         tessellator.setColorOpaque3f(red, green, blue);
         boolean west = BlockLogicWireRedstone.shouldConnectTo(worldSource, tilePos.west(queryPos), Side.WEST) || !worldSource.isBlockNormalCube(tilePos.west(queryPos)) && BlockLogicWireRedstone.shouldConnectToDiagonal(worldSource, tilePos.add(-1, -1, 0, queryPos), Side.NONE, Side.BOTTOM);
         boolean east = BlockLogicWireRedstone.shouldConnectTo(worldSource, tilePos.east(queryPos), Side.EAST) || !worldSource.isBlockNormalCube(tilePos.east(queryPos)) && BlockLogicWireRedstone.shouldConnectToDiagonal(worldSource, tilePos.add(1, -1, 0, queryPos), Side.NONE, Side.BOTTOM);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java b/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
index ef1b1e6fb..3a8eb749c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
@@ -1,8 +1,8 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.LightingCache;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
@@ -44,10 +44,14 @@ public final class RenderBlocks {
     public float colorBlueBottomLeft;
     public float colorBlueBottomRight;
     public float colorBlueTopRight;
-    public int lightmapCoordTopLeft;
-    public int lightmapCoordBottomLeft;
-    public int lightmapCoordBottomRight;
-    public int lightmapCoordTopRight;
+    public float shadeTopLeft;
+    public float shadeBottomLeft;
+    public float shadeBottomRight;
+    public float shadeTopRight;
+    public int lightIndexTopLeft;
+    public int lightIndexBottomLeft;
+    public int lightIndexBottomRight;
+    public int lightIndexTopRight;
     public LightingCache cache = new LightingCache();
 
     public RenderBlocks() {
@@ -267,30 +271,30 @@ public final class RenderBlocks {
             boolean botLefT = this.cache.getOpacity(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ);
             boolean botRigT = this.cache.getOpacity(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ);
 
-            int lmcCen = this.cache.getLightmapCoord(dirX2, dirY2, dirZ2);
+            byte lmcCen = this.cache.getLightIndex(dirX2, dirY2, dirZ2);
 
-            int lmcTop = topT ? lmcCen : this.cache.getLightmapCoord(dirX2 + topX, dirY2 + topY, dirZ2 + topZ);
-            int lmcBot = botT ? lmcCen : this.cache.getLightmapCoord(dirX2 - topX, dirY2 - topY, dirZ2 - topZ);
-            int lmcLef = lefT ? lmcCen : this.cache.getLightmapCoord(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ);
-            int lmcRig = rigT ? lmcCen : this.cache.getLightmapCoord(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ);
+            byte lmcTop = topT ? lmcCen : this.cache.getLightIndex(dirX2 + topX, dirY2 + topY, dirZ2 + topZ);
+            byte lmcBot = botT ? lmcCen : this.cache.getLightIndex(dirX2 - topX, dirY2 - topY, dirZ2 - topZ);
+            byte lmcLef = lefT ? lmcCen : this.cache.getLightIndex(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ);
+            byte lmcRig = rigT ? lmcCen : this.cache.getLightIndex(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ);
 
-            int lmcTopLef = topT && lefT ? lmcLef : (topLefT ? lmcCen : this.cache.getLightmapCoord(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ));
-            int lmcBotLef = botT && lefT ? lmcLef : (botLefT ? lmcCen : this.cache.getLightmapCoord(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ));
-            int lmcTopRig = topT && rigT ? lmcRig : (topRigT ? lmcCen : this.cache.getLightmapCoord(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ));
-            int lmcBotRig = botT && rigT ? lmcRig : (botRigT ? lmcCen : this.cache.getLightmapCoord(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ));
+            byte lmcTopLef = topT && lefT ? lmcLef : (topLefT ? lmcCen : this.cache.getLightIndex(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ));
+            byte lmcBotLef = botT && lefT ? lmcLef : (botLefT ? lmcCen : this.cache.getLightIndex(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ));
+            byte lmcTopRig = topT && rigT ? lmcRig : (topRigT ? lmcCen : this.cache.getLightIndex(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ));
+            byte lmcBotRig = botT && rigT ? lmcRig : (botRigT ? lmcCen : this.cache.getLightIndex(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ));
 
-            this.lightmapCoordTopLeft = LightmapHelper.avg(lmcCen, lmcLef, lmcTop, lmcTopLef);
-            this.lightmapCoordTopRight = LightmapHelper.avg(lmcCen, lmcRig, lmcTop, lmcTopRig);
-            this.lightmapCoordBottomLeft = LightmapHelper.avg(lmcCen, lmcLef, lmcBot, lmcBotLef);
-            this.lightmapCoordBottomRight = LightmapHelper.avg(lmcCen, lmcRig, lmcBot, lmcBotRig);
+            this.lightIndexTopLeft = LightIndexHelper.avg(lmcCen, lmcLef, lmcTop, lmcTopLef);
+            this.lightIndexTopRight = LightIndexHelper.avg(lmcCen, lmcRig, lmcTop, lmcTopRig);
+            this.lightIndexBottomLeft = LightIndexHelper.avg(lmcCen, lmcLef, lmcBot, lmcBotLef);
+            this.lightIndexBottomRight = LightIndexHelper.avg(lmcCen, lmcRig, lmcBot, lmcBotRig);
         } else {
             int lmc;
             if (!isFullCube) {
-                lmc = block.getLightmapCoord(worldSource, tilePos);
+                lmc = block.getLightIndex(worldSource, tilePos);
             } else {
-                lmc = block.getLightmapCoord(worldSource, tilePos.add(dirX, dirY, dirZ, new TilePos()));
+                lmc = block.getLightIndex(worldSource, tilePos.add(dirX, dirY, dirZ, new TilePos()));
             }
-            this.lightmapCoordTopLeft = this.lightmapCoordBottomLeft = this.lightmapCoordBottomRight = this.lightmapCoordTopRight = lmc;
+            this.lightIndexTopLeft = this.lightIndexBottomLeft = this.lightIndexBottomRight = this.lightIndexTopRight = lmc;
         }
 
         float lightTR;
@@ -363,21 +367,10 @@ public final class RenderBlocks {
         float lbl = lefP * bl + (1 - lefP) * br;
         float lbr = rigP * bl + (1 - rigP) * br;
         float ltr = rigP * tl + (1 - rigP) * tr;
-        this.colorRedTopLeft *= ltl;
-        this.colorGreenTopLeft *= ltl;
-        this.colorBlueTopLeft *= ltl;
-
-        this.colorRedBottomLeft *= lbl;
-        this.colorGreenBottomLeft *= lbl;
-        this.colorBlueBottomLeft *= lbl;
-
-        this.colorRedBottomRight *= lbr;
-        this.colorGreenBottomRight *= lbr;
-        this.colorBlueBottomRight *= lbr;
-
-        this.colorRedTopRight *= ltr;
-        this.colorGreenTopRight *= ltr;
-        this.colorBlueTopRight *= ltr;
+        this.shadeTopLeft = ltl;
+        this.shadeBottomLeft = lbl;
+        this.shadeBottomRight = lbr;
+        this.shadeTopRight = ltr;
     }
 
     public void renderBottomFace(@NotNull TessellatorGeneral tessellator, @NotNull AABBdc bounds, @NotNull TilePosc tilePos, @Nullable IconCoordinate tex) {
@@ -442,16 +435,20 @@ public final class RenderBlocks {
         double d15 = z + bounds.maxZ();
         tessellator.setNormal(0, -1, 0);
         if (this.enableAO) {
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexTopLeft);
+            tessellator.setShade1i((int) (this.shadeTopLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopLeft, this.colorGreenTopLeft, this.colorBlueTopLeft);
             tessellator.addVertexWithUV(d11, d13, d15, d8, d10);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomLeft);
+            tessellator.setShade1i((int) (this.shadeBottomLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomLeft, this.colorGreenBottomLeft, this.colorBlueBottomLeft);
             tessellator.addVertexWithUV(d11, d13, d14, d3, d5);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomRight);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomRight);
+            tessellator.setShade1i((int) (this.shadeBottomRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomRight, this.colorGreenBottomRight, this.colorBlueBottomRight);
             tessellator.addVertexWithUV(d12, d13, d14, d7, d9);
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopRight);
+            tessellator.setLightmapCoord1i(this.lightIndexTopRight);
+            tessellator.setShade1i((int) (this.shadeTopRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopRight, this.colorGreenTopRight, this.colorBlueTopRight);
             tessellator.addVertexWithUV(d12, d13, d15, d4, d6);
         } else {
@@ -525,16 +522,20 @@ public final class RenderBlocks {
         double d15 = z + bounds.maxZ();
         tessellator.setNormal(0, 1, 0);
         if (this.enableAO) {
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexTopLeft);
+            tessellator.setShade1i((int) (this.shadeTopLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopLeft, this.colorGreenTopLeft, this.colorBlueTopLeft);
             tessellator.addVertexWithUV(d12, d13, d15, d4, d6);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomLeft);
+            tessellator.setShade1i((int) (this.shadeBottomLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomLeft, this.colorGreenBottomLeft, this.colorBlueBottomLeft);
             tessellator.addVertexWithUV(d12, d13, d14, d7, d9);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomRight);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomRight);
+            tessellator.setShade1i((int) (this.shadeBottomRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomRight, this.colorGreenBottomRight, this.colorBlueBottomRight);
             tessellator.addVertexWithUV(d11, d13, d14, d3, d5);
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopRight);
+            tessellator.setLightmapCoord1i(this.lightIndexTopRight);
+            tessellator.setShade1i((int) (this.shadeTopRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopRight, this.colorGreenTopRight, this.colorBlueTopRight);
             tessellator.addVertexWithUV(d11, d13, d15, d8, d10);
         } else {
@@ -613,16 +614,20 @@ public final class RenderBlocks {
         double d16 = z + bounds.minZ();
         tessellator.setNormal(0, 0, -1);
         if (this.enableAO) {
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexTopLeft);
+            tessellator.setShade1i((int) (this.shadeTopLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopLeft, this.colorGreenTopLeft, this.colorBlueTopLeft);
             tessellator.addVertexWithUV(d12, d15, d16, d8, d10);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomLeft);
+            tessellator.setShade1i((int) (this.shadeBottomLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomLeft, this.colorGreenBottomLeft, this.colorBlueBottomLeft);
             tessellator.addVertexWithUV(d13, d15, d16, d3, d5);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomRight);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomRight);
+            tessellator.setShade1i((int) (this.shadeBottomRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomRight, this.colorGreenBottomRight, this.colorBlueBottomRight);
             tessellator.addVertexWithUV(d13, d14, d16, d9, d11);
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopRight);
+            tessellator.setLightmapCoord1i(this.lightIndexTopRight);
+            tessellator.setShade1i((int) (this.shadeTopRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopRight, this.colorGreenTopRight, this.colorBlueTopRight);
             tessellator.addVertexWithUV(d12, d14, d16, d4, d6);
         } else {
@@ -701,16 +706,20 @@ public final class RenderBlocks {
         double z0 = z + bounds.maxZ();
         tessellator.setNormal(0, 0, 1);
         if (this.enableAO) {
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexTopLeft);
+            tessellator.setShade1i((int) (this.shadeTopLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopLeft, this.colorGreenTopLeft, this.colorBlueTopLeft);
             tessellator.addVertexWithUV(x0, y1, z0, d3, d5);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomLeft);
+            tessellator.setShade1i((int) (this.shadeBottomLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomLeft, this.colorGreenBottomLeft, this.colorBlueBottomLeft);
             tessellator.addVertexWithUV(x0, y0, z0, d9, d11);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomRight);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomRight);
+            tessellator.setShade1i((int) (this.shadeBottomRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomRight, this.colorGreenBottomRight, this.colorBlueBottomRight);
             tessellator.addVertexWithUV(x1, y0, z0, d4, d6);
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopRight);
+            tessellator.setLightmapCoord1i(this.lightIndexTopRight);
+            tessellator.setShade1i((int) (this.shadeTopRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopRight, this.colorGreenTopRight, this.colorBlueTopRight);
             tessellator.addVertexWithUV(x1, y1, z0, d8, d10);
         } else {
@@ -789,16 +798,20 @@ public final class RenderBlocks {
         double d16 = z + bounds.maxZ();
         tessellator.setNormal(-1, 0, 0);
         if (this.enableAO) {
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexTopLeft);
+            tessellator.setShade1i((int) (this.shadeTopLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopLeft, this.colorGreenTopLeft, this.colorBlueTopLeft);
             tessellator.addVertexWithUV(d12, d14, d16, d8, d10);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomLeft);
+            tessellator.setShade1i((int) (this.shadeBottomLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomLeft, this.colorGreenBottomLeft, this.colorBlueBottomLeft);
             tessellator.addVertexWithUV(d12, d14, d15, d3, d5);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomRight);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomRight);
+            tessellator.setShade1i((int) (this.shadeBottomRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomRight, this.colorGreenBottomRight, this.colorBlueBottomRight);
             tessellator.addVertexWithUV(d12, d13, d15, d9, d11);
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopRight);
+            tessellator.setLightmapCoord1i(this.lightIndexTopRight);
+            tessellator.setShade1i((int) (this.shadeTopRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopRight, this.colorGreenTopRight, this.colorBlueTopRight);
             tessellator.addVertexWithUV(d12, d13, d16, d4, d6);
         } else {
@@ -878,16 +891,20 @@ public final class RenderBlocks {
 
         tessellator.setNormal(1, 0, 0);
         if (this.enableAO) {
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexTopLeft);
+            tessellator.setShade1i((int) (this.shadeTopLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopLeft, this.colorGreenTopLeft, this.colorBlueTopLeft);
             tessellator.addVertexWithUV(xMax, yMin, zMax, uMin2, vMax2);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomLeft);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomLeft);
+            tessellator.setShade1i((int) (this.shadeBottomLeft * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomLeft, this.colorGreenBottomLeft, this.colorBlueBottomLeft);
             tessellator.addVertexWithUV(xMax, yMin, zMin, uMax, vMax);
-            tessellator.setLightmapCoord1i(this.lightmapCoordBottomRight);
+            tessellator.setLightmapCoord1i(this.lightIndexBottomRight);
+            tessellator.setShade1i((int) (this.shadeBottomRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedBottomRight, this.colorGreenBottomRight, this.colorBlueBottomRight);
             tessellator.addVertexWithUV(xMax, yMax, zMin, uMax2, vMin2);
-            tessellator.setLightmapCoord1i(this.lightmapCoordTopRight);
+            tessellator.setLightmapCoord1i(this.lightIndexTopRight);
+            tessellator.setShade1i((int) (this.shadeTopRight * 0xFF));
             tessellator.setColorOpaque3f(this.colorRedTopRight, this.colorGreenTopRight, this.colorBlueTopRight);
             tessellator.addVertexWithUV(xMax, yMax, zMax, uMin, vMin);
         } else {
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 c34c1d07c..16fac720f 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
@@ -62,8 +62,8 @@ public class BlockModelGeneric<T extends BlockLogic> extends BlockModel<T> {
     }
 
     @Override
-    public void renderStandalone(final @NotNull TessellatorGeneral tessellator, final int metadata, final int lightmapCoord) {
-        getModelFromData(metadata).renderStandalone(this, tessellator, 0, 0, 0, metadata, lightmapCoord, BlockColorDispatcher.getInstance().getDispatch(this.block));
+    public void renderStandalone(final @NotNull TessellatorGeneral tessellator, final int metadata, final byte lightIndex) {
+        getModelFromData(metadata).renderStandalone(this, tessellator, 0, 0, 0, metadata, lightIndex, BlockColorDispatcher.getInstance().getDispatch(this.block));
     }
 
     public @NotNull StaticBlockModel getModel(@NotNull WorldSource source, @NotNull TilePosc tilePosc) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLamp.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLamp.java
index 0f10c01a3..1d713cfcf 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLamp.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLamp.java
@@ -21,8 +21,8 @@ public class BlockModelGenericLamp<T extends BlockLogic> extends BlockModelGener
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
-        this.activeModels[metadata & DyeColor.MASK_COLOR].renderStandalone(this, tessellator, 0, 0, 0, metadata, lightmapCoord, BlockColorDispatcher.getInstance().getDispatch(this.block));
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
+        this.activeModels[metadata & DyeColor.MASK_COLOR].renderStandalone(this, tessellator, 0, 0, 0, metadata, lightIndex, BlockColorDispatcher.getInstance().getDispatch(this.block));
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLeavesCacao.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLeavesCacao.java
index 2e3af8e99..8019babe2 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLeavesCacao.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLeavesCacao.java
@@ -24,9 +24,9 @@ public class BlockModelGenericLeavesCacao<T extends BlockLogic> extends BlockMod
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
-        super.renderStandalone(tessellator, metadata, lightmapCoord);
-        this.overlays[this.overlays.length - 1].renderStandalone(this, tessellator, 0, 0, 0, metadata, lightmapCoord, BlockColorDispatcher.getInstance().getDispatch(this.block));
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
+        super.renderStandalone(tessellator, metadata, lightIndex);
+        this.overlays[this.overlays.length - 1].renderStandalone(this, tessellator, 0, 0, 0, metadata, lightIndex, BlockColorDispatcher.getInstance().getDispatch(this.block));
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLeavesCherryFlowering.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLeavesCherryFlowering.java
index 48c0959a6..3e835ef06 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLeavesCherryFlowering.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLeavesCherryFlowering.java
@@ -23,9 +23,9 @@ public class BlockModelGenericLeavesCherryFlowering<T extends BlockLogic> extend
     }
 
     @Override
-    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, int lightmapCoord) {
-        super.renderStandalone(tessellator, metadata, lightmapCoord);
-        this.overlay.renderStandalone(this, tessellator, 0, 0, 0, metadata, lightmapCoord, BlockColorDispatcher.getInstance().getDispatch(this.block));
+    public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) {
+        super.renderStandalone(tessellator, metadata, lightIndex);
+        this.overlay.renderStandalone(this, tessellator, 0, 0, 0, metadata, lightIndex, BlockColorDispatcher.getInstance().getDispatch(this.block));
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/camera/ICamera.java b/game/client/src/main/java/net/minecraft/client/render/camera/ICamera.java
index c0a2d0f45..583ffbb1d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/camera/ICamera.java
+++ b/game/client/src/main/java/net/minecraft/client/render/camera/ICamera.java
@@ -50,6 +50,18 @@ public interface ICamera {
         return getPosition(1f);
     }
 
+    default @NotNull Vector3d getPosition(float partialTick, @NotNull Vector3d out) {
+        out.x = this.getX(partialTick);
+        out.y = this.getY(partialTick);
+        out.z = this.getZ(partialTick);
+
+        return out;
+    }
+
+    default @NotNull Vector3d getPosition(@NotNull Vector3d out) {
+        return this.getPosition(1.0f, out);
+    }
+
     double getXRot(float partialTick);
 
     default double getXRot() {
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java
index 6f760dfcb..865195a21 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java
@@ -8,6 +8,7 @@ import net.minecraft.client.render.renderer.Shaders;
 import net.minecraft.client.render.renderer.State;
 import net.minecraft.core.entity.EntityDispatcher;
 import net.minecraft.core.util.collection.NamespaceID;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import org.jetbrains.annotations.NotNull;
@@ -16,7 +17,6 @@ import org.joml.primitives.AABBdc;
 
 import net.minecraft.client.render.EntityRendererDispatcher;
 import net.minecraft.client.render.ImageParser;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
@@ -116,9 +116,9 @@ public abstract class EntityRenderer<T extends Entity> {
         GLRenderer.modelM4f().rotateY(Math.toRadians(-this.renderDispatcher.viewLerpYaw));
         GLRenderer.modelM4f().translate(0.0F, 0.0F, -0.3F + (float) (int) f12 * 0.02F);
         GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-        int lightmapCoord = entity.getLightmap(partialTick);
-        lightmapCoord = LightmapHelper.setBlocklightValue(lightmapCoord, 15);
-        GLRenderer.setLightmapCoord1i(lightmapCoord);
+        byte lightIndex = entity.getLightIndex(partialTick);
+        lightIndex = LightIndexHelper.setBlockLight(lightIndex, 15);
+        GLRenderer.setLightmapCoord1i(lightIndex);
         float f14 = 0.0F;
         int l = 0;
         tessellator.startDrawingQuads();
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFallingBlock.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFallingBlock.java
index b0c440bdb..fd943c5e1 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFallingBlock.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFallingBlock.java
@@ -2,7 +2,6 @@ package net.minecraft.client.render.entity;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.TileEntityRenderDispatcher;
-import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.renderer.BlendFactor;
 import net.minecraft.client.render.renderer.GLRenderer;
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java
index 11e8c3ac3..f548ab5cb 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java
@@ -37,7 +37,7 @@ public class EntityRendererItem extends EntityRenderer<EntityItem> {
             renderCount = 4;
         }
         GLRenderer.modelM4f().translate((float) x, (float) (y + bobbingOffset), (float) z);
-        ItemModelDispatcher.getInstance().getDispatch(item).renderItemEntity(tessellator, itemstack, GameSettings.ITEMS_3D.value, renderCount, entity.age, yw, entity.getLightmap(partialTick), partialTick);
+        ItemModelDispatcher.getInstance().getDispatch(item).renderItemEntity(tessellator, itemstack, GameSettings.ITEMS_3D.value, renderCount, entity.age, yw, entity.getLightIndex(partialTick), partialTick);
         GLRenderer.popFrame();
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererMinecart.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererMinecart.java
index 0c5c394ce..0ec356875 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererMinecart.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererMinecart.java
@@ -83,7 +83,7 @@ public class EntityRendererMinecart extends EntityRenderer<EntityMinecart> {
             GLRenderer.modelM4f().scale(scale, scale, scale);
             GLRenderer.modelM4f().translate(0.0F, 0.3125F, 0.0F);
             GLRenderer.modelM4f().rotateY(org.joml.Math.PI_OVER_2_f);
-            GLRenderer.setLightmapCoord1i(minecart.getLightmap(partialTick));
+            GLRenderer.setLightmapCoord1i(minecart.getLightIndex(partialTick));
 
             GLRenderer.pushFrame();
             if (doAFlip) {
@@ -97,13 +97,13 @@ public class EntityRendererMinecart extends EntityRenderer<EntityMinecart> {
                     } else {
                         block = Blocks.CHEST_PLANKS_OAK;
                     }
-                    BlockModelDispatcher.getInstance().getDispatch(block).renderStandalone(tessellator, minecart.getMeta(), minecart.getLightmap(partialTick));
+                    BlockModelDispatcher.getInstance().getDispatch(block).renderStandalone(tessellator, minecart.getMeta(), minecart.getLightIndex(partialTick));
                     break;
                 case EntityMinecart.FURNACE_CART:
                     if (minecart.getFuel() > 0) {
-                        BlockModelDispatcher.getInstance().getDispatch(Blocks.FURNACE_STONE_ACTIVE).renderStandalone(tessellator, 0, minecart.getLightmap(partialTick));
+                        BlockModelDispatcher.getInstance().getDispatch(Blocks.FURNACE_STONE_ACTIVE).renderStandalone(tessellator, 0, minecart.getLightIndex(partialTick));
                     } else {
-                        BlockModelDispatcher.getInstance().getDispatch(Blocks.FURNACE_STONE_IDLE).renderStandalone(tessellator, 0, minecart.getLightmap(partialTick));
+                        BlockModelDispatcher.getInstance().getDispatch(Blocks.FURNACE_STONE_IDLE).renderStandalone(tessellator, 0, minecart.getLightIndex(partialTick));
                     }
                     break;
             }
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererSprite.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererSprite.java
index 76e82e574..11e619e90 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererSprite.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererSprite.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.entity;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
@@ -41,7 +40,7 @@ public class EntityRendererSprite<T extends Entity> extends EntityRenderer<T> {
         if (this.fullBright) {
             GLRenderer.globalSetLightEnabled(false);
             GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-            GLRenderer.setLightmapCoord1i(LightmapHelper.getLightmapCoord(15, 15));
+            GLRenderer.setLightmapCoord2i(15, 15);
         }
         GLRenderer.modelM4f().scale(0.5F * this.scale, 0.5F * this.scale, 0.5F * this.scale);
         this.itemIconIndex.parentAtlas.bind();
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererTNT.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererTNT.java
index dedc841a1..217fd95f1 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererTNT.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererTNT.java
@@ -37,7 +37,7 @@ public class EntityRendererTNT extends EntityRenderer<EntityPrimedTNT> {
         float f3 = (1.0F - (((float) tnt.fuse - partialTick) + 1.0F) / 100F) * 0.8F;
         TextureRegistry.worldAtlas.bind();
         BlockModel<?> model = BlockModelDispatcher.getInstance().getDispatch(Blocks.TNT);
-        model.renderStandalone(tessellator, 0, tnt.getLightmap(partialTick));
+        model.renderStandalone(tessellator, 0, tnt.getLightIndex(partialTick));
         if ((tnt.fuse / 5) % 2 == 0) {
             GLRenderer.pushFrame();
             GLRenderer.setShader(Shaders.COLOR_WORLD);
@@ -45,7 +45,7 @@ public class EntityRendererTNT extends EntityRenderer<EntityPrimedTNT> {
             GLRenderer.enableState(State.BLEND);
             GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.DST_ALPHA);
             GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, f3);
-            model.renderStandalone(tessellator, 0, tnt.getLightmap(partialTick));
+            model.renderStandalone(tessellator, 0, tnt.getLightIndex(partialTick));
             GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F);
             GLRenderer.disableState(State.BLEND);
             GLRenderer.globalSetLightEnabled(true);
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererBiped.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererBiped.java
index 1a1f57bca..c07cb3fcc 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererBiped.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererBiped.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.entity;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
@@ -148,16 +147,14 @@ public abstract class MobRendererBiped<T extends Mob> extends MobRenderer<T> {
                     GLRenderer.modelM4f().scale(-1, 1, -1);
                     GLRenderer.modelM4f().scale(MobRenderer.ENTITY_RENDER_SCALE, MobRenderer.ENTITY_RENDER_SCALE, MobRenderer.ENTITY_RENDER_SCALE);
                     ItemModelDispatcher.getInstance().getDispatch(itemstack)
-                        .render(tessellator, entity, itemstack, DisplayPos.THIRD_PERSON_LEFT_HAND, true, 1,
-                            LightmapHelper.getLightmapCoord(GLRenderer.getLightmapSky(), GLRenderer.getLightmapBlock()), partialTick, true);
+                        .render(tessellator, entity, itemstack, DisplayPos.THIRD_PERSON_LEFT_HAND, true, 1, GLRenderer.getLightIndex(), partialTick, true);
                 } else {
 
                     if (model != null) model.translateToBone("rightItem");
                     GLRenderer.modelM4f().scale(-1, 1, 1);
                     GLRenderer.modelM4f().scale(MobRenderer.ENTITY_RENDER_SCALE, MobRenderer.ENTITY_RENDER_SCALE, MobRenderer.ENTITY_RENDER_SCALE);
                     ItemModelDispatcher.getInstance().getDispatch(itemstack)
-                        .render(tessellator, entity, itemstack, DisplayPos.THIRD_PERSON_RIGHT_HAND, true, 1,
-                            LightmapHelper.getLightmapCoord(GLRenderer.getLightmapSky(), GLRenderer.getLightmapBlock()), partialTick, false);
+                        .render(tessellator, entity, itemstack, DisplayPos.THIRD_PERSON_RIGHT_HAND, true, 1, GLRenderer.getLightIndex(), partialTick, false);
                 }
                 GLRenderer.popFrame();
             }
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererBipedArmored.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererBipedArmored.java
index 7dabe22d0..82a73993a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererBipedArmored.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererBipedArmored.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.entity;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.renderer.State;
@@ -109,7 +108,7 @@ public abstract class MobRendererBipedArmored<T extends Mob & IArmorWearing<Huma
                 GLRenderer.modelM4f().scale(0.6f, 0.6f, 0.6f);
                 GLRenderer.modelM4f().translate(0, 7 / 16f, 0);
                 ItemModelDispatcher.getInstance().getDispatch(stack).render(GLRenderer.getTessellator(), null, stack, DisplayPos.HEAD, true, 1,
-                    LightmapHelper.getLightmapCoord(GLRenderer.getLightmapSky(), GLRenderer.getLightmapBlock()), partialTick, true);
+                    GLRenderer.getLightIndex(), partialTick, true);
                 GLRenderer.disableState(State.CULL_FACE);
                 GLRenderer.popFrame();
             }
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSpider.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSpider.java
index 0a7269b45..64310d8da 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSpider.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSpider.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.entity;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.renderer.BlendFactor;
 import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.renderer.State;
@@ -21,7 +20,7 @@ public class MobRendererSpider extends MobRenderer<MobSpider> {
     protected @Nullable StaticEntityModel getAndSetupModelForLayer(@NotNull final MobSpider entity, final float brightness, final float partialTick, final int layer) {
         if (layer == 1) {
             bindTexture("/assets/minecraft/textures/entity/spider/eyes/" + entity.getTextureReference() + ".png");
-            GLRenderer.setLightmapCoord1i(LightmapHelper.getOverbrightLightmapCoord(15));
+            GLRenderer.setLightmapCoord2i(15, 15);
             GLRenderer.enableState(State.BLEND);
             GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA);
             GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, (1.0F - entity.getBrightness(partialTick)) * 0.5F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java
index 8c44b4b62..508c84db4 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java
@@ -126,7 +126,7 @@ public class MobRendererWolf extends MobRenderer<MobWolf> {
             getModel("main").translateToBone("mouthItem");
             GLRenderer.modelM4f().scale(MobRenderer.ENTITY_RENDER_SCALE, -MobRenderer.ENTITY_RENDER_SCALE, MobRenderer.ENTITY_RENDER_SCALE);
             GLRenderer.enableState(State.BLEND);
-            ItemModelDispatcher.getInstance().getDispatch(itemstack).render(GLRenderer.getTessellator(), entity, itemstack, DisplayPos.GROUND, GameSettings.ITEMS_3D.value, 1, entity.getLightmap(partialTick), partialTick, true);
+            ItemModelDispatcher.getInstance().getDispatch(itemstack).render(GLRenderer.getTessellator(), entity, itemstack, DisplayPos.GROUND, GameSettings.ITEMS_3D.value, 1, entity.getLightIndex(partialTick), partialTick, true);
             GLRenderer.disableState(State.BLEND);
             GLRenderer.popFrame();
         }
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java b/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java
index 52e2f3e1c..71e019730 100644
--- a/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java
+++ b/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java
@@ -14,6 +14,7 @@ import net.minecraft.client.render.tessellator.TessellatorFont;
 import net.minecraft.client.util.helper.Colors;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.util.helper.ChatAllowedCharacters;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -800,7 +801,7 @@ public class FontRendererDefault extends FontRenderer {
             GL41.glVertexAttribPointer(0, 3, GL41.GL_FLOAT, false, VERT_SIZE, 0);
             GL41.glVertexAttribPointer(1, 4, GL41.GL_UNSIGNED_BYTE, true, VERT_SIZE, Float.BYTES * 3);
             GL41.glVertexAttrib2f(2, 0f, 0f);
-            GL41.glVertexAttrib2f(3, 15.5f/16f, 15.5f/16f);
+            GL41.glVertexAttrib1f(3, LightIndexHelper.lightIndex2i(15, 15));
             GL41.glVertexAttrib3f(4, 0, -1f, 0);
 
             GL41.glEnableVertexAttribArray(0);
@@ -854,7 +855,7 @@ public class FontRendererDefault extends FontRenderer {
             if (this.vertexCount == 0) return;
 
             GL41.glBindVertexArray(this.vao);
-            GL41.glVertexAttrib2f(3, GLRenderer.getLightmapBlock(), GLRenderer.getLightmapSky());
+            GL41.glVertexAttrib1f(3, GLRenderer.getLightIndex());
 
             GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vbo);
             GL41.glBufferData(GL41.GL_ARRAY_BUFFER, this.data.flip(), GL41.GL_STREAM_DRAW);
@@ -872,7 +873,7 @@ public class FontRendererDefault extends FontRenderer {
             this.drawing = false;
 
             GL41.glBindVertexArray(this.vao);
-            GL41.glVertexAttrib2f(3, GLRenderer.getLightmapBlock(), GLRenderer.getLightmapSky());
+            GL41.glVertexAttrib1f(3, GLRenderer.getLightIndex());
 
             GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vbo);
             GL41.glBufferData(GL41.GL_ARRAY_BUFFER, this.data.flip(), GL41.GL_STATIC_DRAW);
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
index 7f99fffff..2e6d097dc 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
@@ -2,7 +2,6 @@ package net.minecraft.client.render.item.model;
 
 import net.minecraft.client.render.EntityRendererDispatcher;
 import net.minecraft.client.render.ItemRenderer;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.renderer.BlendFactor;
@@ -28,37 +27,37 @@ public abstract class ItemModel {
         this.item = item;
     }
 
-    public abstract void render(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, int lightmapCoord, float partialTick, boolean mirrorX); // TODO figure out if theres a way to not explicitly need to mirrorX in the model itself
+    public abstract void render(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, byte lightIndex, float partialTick, boolean mirrorX); // TODO figure out if theres a way to not explicitly need to mirrorX in the model itself
     public abstract void renderItemOverlayIntoGUI(@NotNull TessellatorGeneral tessellator, @NotNull FontRenderer fontRenderer, @NotNull TextureManager textureManager, @NotNull ItemStack itemstack, int x, int y, @Nullable String override, float alpha);
 
-    public void renderGui(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, int x, int y, int lightmapCoord, float partialTick) {
+    public void renderGui(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, int x, int y, byte lightIndex, float partialTick) {
         GLRenderer.pushFrame();
-        GLRenderer.setShader(Shaders.TERRAIN);
+        GLRenderer.setShader(Shaders.ITEM);
         GLRenderer.globalSetLightEnabled(false);
         GLRenderer.enableState(State.BLEND);
         GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA);
         GLRenderer.enableState(State.CULL_FACE);
         GLRenderer.modelM4f().translate(x + 8, y + 8, 0);
         GLRenderer.modelM4f().scale(16, -16, 1);
-        render(tessellator, holder, itemStack, DisplayPos.GUI, false, 1, LightmapHelper.getLightmapCoord(15, 15), partialTick, false);
+        render(tessellator, holder, itemStack, DisplayPos.GUI, false, 1, lightIndex, partialTick, false);
         GLRenderer.globalSetLightEnabled(true);
         GLRenderer.popFrame();
     }
 
-    public void renderItemEntity(@NotNull TessellatorGeneral tessellator, @NotNull ItemStack itemStack, boolean items3d, int clusterSize, int ticks, float yaw, int lightmap, float partialTick) {
+    public void renderItemEntity(@NotNull TessellatorGeneral tessellator, @NotNull ItemStack itemStack, boolean items3d, int clusterSize, int ticks, float yaw, byte lightIndex, float partialTick) {
         GLRenderer.enableState(State.BLEND);
         if (items3d) {
             GLRenderer.modelM4f().rotateY(Math.toRadians(yaw));
         } else {
             GLRenderer.modelM4f().rotateY(Math.toRadians(180F - EntityRendererDispatcher.instance.viewLerpYaw));
         }
-        render(tessellator, null, itemStack, DisplayPos.GROUND, items3d, clusterSize, lightmap, partialTick, false);
+        render(tessellator, null, itemStack, DisplayPos.GROUND, items3d, clusterSize, lightIndex, partialTick, false);
         GLRenderer.disableState(State.BLEND);
     }
 
-    public void renderFirstPerson(@NotNull TessellatorGeneral tessellator, @NotNull ItemRenderer itemRenderer, @NotNull Player player, @NotNull ItemStack itemStack, int lightmapCoord, float partialTick) {
+    public void renderFirstPerson(@NotNull TessellatorGeneral tessellator, @NotNull ItemRenderer itemRenderer, @NotNull Player player, @NotNull ItemStack itemStack, byte lightIndex, float partialTick) {
         GLRenderer.pushFrame();
-        GLRenderer.setShader(Shaders.TERRAIN);
+        GLRenderer.setShader(Shaders.ITEM);
         GLRenderer.enableState(State.BLEND);
         GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA);
         GLRenderer.enableState(State.CULL_FACE);
@@ -83,7 +82,7 @@ public abstract class ItemModel {
             GLRenderer.modelM4f().rotateY(Math.toRadians(-45));
 
             GLRenderer.setFrontFace(FrontFace.CW);
-            render(tessellator,player, itemStack, DisplayPos.FIRST_PERSON_LEFT_HAND, true, 1, lightmapCoord, partialTick, true);
+            render(tessellator,player, itemStack, DisplayPos.FIRST_PERSON_LEFT_HAND, true, 1, lightIndex, partialTick, true);
             GLRenderer.setFrontFace(FrontFace.CCW);
         } else {
             final float xOff = 9/16f;
@@ -100,7 +99,7 @@ public abstract class ItemModel {
             GLRenderer.modelM4f().rotateX(Math.toRadians(-animationProgress) * 80F);
             GLRenderer.modelM4f().rotateY(Math.toRadians(-45));
 
-            render(tessellator,player, itemStack, DisplayPos.FIRST_PERSON_RIGHT_HAND, true, 1, lightmapCoord, partialTick, false);
+            render(tessellator,player, itemStack, DisplayPos.FIRST_PERSON_RIGHT_HAND, true, 1, lightIndex, partialTick, false);
         }
         GLRenderer.popFrame();
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBlock.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBlock.java
index 92297b7da..1410f7417 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBlock.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBlock.java
@@ -18,7 +18,6 @@ import net.minecraft.core.item.block.ItemBlock;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.joml.Math;
-import org.lwjgl.opengl.GL41;
 import org.useless.dragonfly.DisplayPos;
 
 public class ItemModelBlock extends ItemModelStandard {
@@ -43,13 +42,13 @@ public class ItemModelBlock extends ItemModelStandard {
     }
 
     @Override
-    public void render(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, int lightmapCoord, float partialTick, boolean mirrorX) {
+    public void render(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, byte lightIndex, float partialTick, boolean mirrorX) {
         if (!this.blockModel.shouldItemRender3d()) {
-            super.render(tessellator, holder, itemStack, displayPosId, items3d, clusterSize, lightmapCoord, partialTick, mirrorX);
+            super.render(tessellator, holder, itemStack, displayPosId, items3d, clusterSize, lightIndex, partialTick, mirrorX);
             return;
         }
         random.setSeed(187L);
-        GLRenderer.setShader(Shaders.TERRAIN);
+        GLRenderer.setShader(Shaders.ITEM);
         DisplayPos displayPos = getDisplayPos(displayPosId);
         GLRenderer.modelM4f().translate(displayPos.tx, displayPos.ty, displayPos.tz);
         GLRenderer.modelM4f().rotateX(Math.toRadians(displayPos.rx));
@@ -66,47 +65,47 @@ public class ItemModelBlock extends ItemModelStandard {
                 rOffZ = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / displayPos.sz;
             }
             GLRenderer.modelM4f().translate(rOffX, rOffY, rOffZ);
-            renderSingle(tessellator, holder, itemStack, items3d, lightmapCoord, getColor(itemStack), partialTick, mirrorX);
+            renderSingle(tessellator, holder, itemStack, items3d, lightIndex, getColor(itemStack), partialTick, mirrorX);
             GLRenderer.modelM4f().translate(-rOffX, -rOffY, -rOffZ);
         }
     }
 
     @Override
-    protected void renderSingle(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, int lightmapCoord, int color, float partialTick, boolean mirrorX) {
+    protected void renderSingle(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, byte lightIndex, int color, float partialTick, boolean mirrorX) {
         if (!this.blockModel.shouldItemRender3d()) {
-            super.renderSingle(tessellator, holder, itemStack, items3d, lightmapCoord, color, partialTick, mirrorX);
+            super.renderSingle(tessellator, holder, itemStack, items3d, lightIndex, color, partialTick, mirrorX);
         } else {
             TextureRegistry.worldAtlas.bind();
-            this.blockModel.renderStandalone(tessellator, itemStack.getMetadata(), lightmapCoord);
+            this.blockModel.renderStandalone(tessellator, itemStack.getMetadata(), lightIndex);
         }
     }
 
     @Override
-    public void renderGui(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, int x, int y, int lightmapCoord, float partialTick) {
+    public void renderGui(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, int x, int y, byte lightIndex, float partialTick) {
         if (!this.blockModel.shouldItemRender3d()) {
-            super.renderGui(tessellator, holder, itemStack, x, y, lightmapCoord, partialTick);
+            super.renderGui(tessellator, holder, itemStack, x, y, lightIndex, partialTick);
             return;
         }
         GLRenderer.pushFrame();
-        GLRenderer.setShader(Shaders.TERRAIN);
+        GLRenderer.setShader(Shaders.ITEM);
         GLRenderer.enableState(State.BLEND);
         GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA);
         GLRenderer.enableState(State.CULL_FACE);
         GLRenderer.modelM4f().translate(x + 8, y + 8, 8);
         GLRenderer.modelM4f().scale(16f, -16f, 16f);
-        render(tessellator, holder, itemStack, DisplayPos.GUI, false, 1, lightmapCoord, partialTick, false);
+        render(tessellator, holder, itemStack, DisplayPos.GUI, false, 1, lightIndex, partialTick, false);
         GLRenderer.popFrame();
     }
 
     @Override
-    public void renderItemEntity(@NotNull TessellatorGeneral tessellator, @NotNull ItemStack itemStack, boolean items3d, int clusterSize, int ticks, float yaw, int lightmap, float partialTick) {
+    public void renderItemEntity(@NotNull TessellatorGeneral tessellator, @NotNull ItemStack itemStack, boolean items3d, int clusterSize, int ticks, float yaw, byte lightIndex, float partialTick) {
         if (!this.blockModel.shouldItemRender3d()) {
-            super.renderItemEntity(tessellator, itemStack, items3d, clusterSize, ticks, yaw, lightmap, partialTick);
+            super.renderItemEntity(tessellator, itemStack, items3d, clusterSize, ticks, yaw, lightIndex, partialTick);
             return;
         }
         GLRenderer.enableState(State.BLEND);
         GLRenderer.modelM4f().rotateY(Math.toRadians(yaw));
-        render(tessellator, null, itemStack, DisplayPos.GROUND, items3d, clusterSize, lightmap, partialTick, false);
+        render(tessellator, null, itemStack, DisplayPos.GROUND, items3d, clusterSize, lightIndex, partialTick, false);
         GLRenderer.disableState(State.BLEND);
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBow.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBow.java
index d7e1c3749..91db639ab 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBow.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBow.java
@@ -19,8 +19,8 @@ public class ItemModelBow extends ItemModelStandard {
     }
 
     @Override
-    protected void renderSingle(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, int lightmapCoord, int color, float partialTick, boolean mirrorX) {
-        super.renderSingle(tessellator, holder, itemStack, items3d, lightmapCoord, color, partialTick, mirrorX);
+    protected void renderSingle(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, byte lightIndex, int color, float partialTick, boolean mirrorX) {
+        super.renderSingle(tessellator, holder, itemStack, items3d, lightIndex, color, partialTick, mirrorX);
         Item nextArrow = null;
         if (holder instanceof Player player) {
             nextArrow = getNextArrow(player);
@@ -38,7 +38,7 @@ public class ItemModelBow extends ItemModelStandard {
             }
             GLRenderer.modelM4f().translate(0.0001f, 0.0001f, 0);
             GLRenderer.modelM4f().scale(1, 1, 0.999f);
-            renderCoordinate(tessellator, ItemModelDispatcher.getInstance().getDispatch(nextArrow).getIcon(holder, nextArrow.getDefaultStack()), lightmapCoord, color, items3d, mirrorX);
+            renderCoordinate(tessellator, ItemModelDispatcher.getInstance().getDispatch(nextArrow).getIcon(holder, nextArrow.getDefaultStack()), lightIndex, color, items3d, mirrorX);
             GLRenderer.popFrame();
         }
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelMap.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelMap.java
index 47d32d723..88dc401bf 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelMap.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelMap.java
@@ -32,7 +32,7 @@ public class ItemModelMap extends ItemModelStandard {
     }
 
     @Override
-    public void renderFirstPerson(@NotNull TessellatorGeneral tessellator, @NotNull ItemRenderer itemRenderer, @NotNull Player player, @NotNull ItemStack itemStack, int lightmapCoord, float partialTick) {
+    public void renderFirstPerson(@NotNull TessellatorGeneral tessellator, @NotNull ItemRenderer itemRenderer, @NotNull Player player, @NotNull ItemStack itemStack, byte lightIndex, float partialTick) {
         // The map renders very differently from any other item, so has its own custom first person render code
         if (ItemMap.hasInitialized(itemStack)) {
             GLRenderer.pushFrame();
@@ -118,7 +118,7 @@ public class ItemModelMap extends ItemModelStandard {
             }
             GLRenderer.popFrame();
         } else {
-            super.renderFirstPerson(tessellator, itemRenderer, player, itemStack, lightmapCoord, partialTick);
+            super.renderFirstPerson(tessellator, itemRenderer, player, itemStack, lightIndex, partialTick);
         }
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelNone.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelNone.java
index 2d01d27c5..f68209e11 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelNone.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelNone.java
@@ -16,7 +16,7 @@ public class ItemModelNone extends ItemModel{
 
 
     @Override
-    public void render(@NotNull final TessellatorGeneral tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, @NotNull final String displayPosId, final boolean items3d, final int clusterSize, int lightmapCoord, final float partialTick, final boolean mirrorX) {
+    public void render(@NotNull final TessellatorGeneral tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, @NotNull final String displayPosId, final boolean items3d, final int clusterSize, byte lightIndex, final float partialTick, final boolean mirrorX) {
 
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
index 85db19ea1..bc60db4a4 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.item.model;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.renderer.BlendFactor;
@@ -13,6 +12,7 @@ import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.useless.dragonfly.DisplayPos;
@@ -56,7 +56,7 @@ public class ItemModelStandard extends ItemModel{
     }
 
     @Override
-    public void render(@NotNull final TessellatorGeneral tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, @NotNull final String displayPosId, final boolean items3d, final int clusterSize, int lightmapCoord, final float partialTick, final boolean mirrorX) {
+    public void render(@NotNull final TessellatorGeneral tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, @NotNull final String displayPosId, final boolean items3d, final int clusterSize, byte lightIndex, final float partialTick, final boolean mirrorX) {
         random.setSeed(187L);
         final DisplayPos displayPos = getDisplayPos(displayPosId);
 
@@ -71,7 +71,7 @@ public class ItemModelStandard extends ItemModel{
                 final float offY = 0;
                 final float offZ = 0.1f * i;
                 GLRenderer.modelM4f().translate(offX, offY, offZ);
-                renderSingle(tessellator, holder, itemStack, true, lightmapCoord, getColor(itemStack), partialTick, mirrorX);
+                renderSingle(tessellator, holder, itemStack, true, lightIndex, getColor(itemStack), partialTick, mirrorX);
                 GLRenderer.modelM4f().translate(-offX, -offY, -offZ);
             }
         } else {
@@ -85,17 +85,17 @@ public class ItemModelStandard extends ItemModel{
                     rOffZ = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / displayPos.sz;
                 }
                 GLRenderer.modelM4f().translate(rOffX, rOffY, rOffZ);
-                renderSingle(tessellator, holder, itemStack, false, lightmapCoord, getColor(itemStack), partialTick, mirrorX);
+                renderSingle(tessellator, holder, itemStack, false, lightIndex, getColor(itemStack), partialTick, mirrorX);
                 GLRenderer.modelM4f().translate(-rOffX, -rOffY, -rOffZ);
             }
         }
     }
 
-    protected void renderSingle(@NotNull final TessellatorGeneral tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, final boolean items3d, int lightmapCoord, int color, final float partialTick, final boolean mirrorX) {
-        renderCoordinate(tessellator, getIcon(holder, itemStack), this.itemfullBright ? LightmapHelper.getLightmapCoord(15, 15) : lightmapCoord, color, items3d, mirrorX);
+    protected void renderSingle(@NotNull final TessellatorGeneral tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, final boolean items3d, byte lightIndex, int color, final float partialTick, final boolean mirrorX) {
+        renderCoordinate(tessellator, getIcon(holder, itemStack), this.itemfullBright ? LightIndexHelper.lightIndex2i(15, 15) : lightIndex, color, items3d, mirrorX);
     }
 
-    protected void renderCoordinate(@NotNull final TessellatorGeneral tessellator, @NotNull final IconCoordinate coordinate, int lightmap, int color, final boolean items3d, final boolean mirrorX) {
+    protected void renderCoordinate(@NotNull final TessellatorGeneral tessellator, @NotNull final IconCoordinate coordinate, byte lightIndex, int color, final boolean items3d, final boolean mirrorX) {
         final double cUMin = mirrorX ? coordinate.getIconUMax() : coordinate.getIconUMin();
         final double cUMax = mirrorX ? coordinate.getIconUMin() : coordinate.getIconUMax();
         final double cVMin = coordinate.getIconVMin();
@@ -108,7 +108,7 @@ public class ItemModelStandard extends ItemModel{
             final int pxW = coordinate.width;
 
             tessellator.startDrawingQuads();
-            tessellator.setLightmapCoord1i(lightmap);
+            tessellator.setLightmapCoord1i(lightIndex);
             tessellator.setColor1i(color);
             // front
             tessellator.setNormal(0, 0, -1);
@@ -172,7 +172,7 @@ public class ItemModelStandard extends ItemModel{
             tessellator.draw();
         } else {
             tessellator.startDrawingQuads();
-            tessellator.setLightmapCoord1i(lightmap);
+            tessellator.setLightmapCoord1i(lightIndex);
             tessellator.setColor1i(color);
             tessellator.setNormal(0, 1, 0);
             tessellator.addVertexWithUV(-0.5,  0.5, 0, cUMin, cVMin);
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java b/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java
index 9aa8f30be..f2cceb4e8 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java
@@ -2,13 +2,13 @@ package net.minecraft.client.render.particle;
 
 import it.unimi.dsi.fastutil.objects.ObjectArrayList;
 import net.minecraft.client.render.ParticleEngine;
-import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
+import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
-import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.world.World;
@@ -39,7 +39,7 @@ public class Particle {
     protected float rCol;
     protected float gCol;
     protected float bCol;
-    protected int cachedLightmapCoord;
+    protected byte cachedLightmapCoord;
 
     public double x = 0;
     public double y = 0;
@@ -93,7 +93,7 @@ public class Particle {
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
     }
 
     /**
@@ -119,7 +119,7 @@ public class Particle {
     }
 
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
@@ -279,7 +279,7 @@ public class Particle {
      */
     public void render(@NotNull TessellatorParticle t, float partialTick) {
         if (this.tex == null) return;
-        t.setLightmapCoord1i(getLightmap(partialTick));
+        t.setLightmapCoord1i(getLightIndex(partialTick));
         t.setColorOpaque3f(this.rCol, this.gCol, this.bCol);
         t.addParticle(
             MathHelper.lerp(this.xo, this.x, partialTick),
@@ -316,65 +316,30 @@ public class Particle {
         return calcBrightness(partialTick);
     }
 
-    public int calcLightmap(float partialTick) {
-        if (Global.accessor.isFullbrightEnabled()) return 15 << 20 | 15;
+    public byte calcLightIndex(float partialTick) {
+        if (Global.accessor.isFullbrightEnabled()) return LightIndexHelper.lightIndex2i(15, 15);
         TilePos blockPos = new TilePos(
             MathHelper.lerp(this.xo, this.x, partialTick),
             MathHelper.lerp(this.yo, this.y, partialTick),
             MathHelper.lerp(this.zo, this.z, partialTick));
 
-        final int skylight;
-        final int blocklight;
+        byte lightIndex = 0;
         if (this.world.getBlockLitInteriorSurface(blockPos)) {
             TilePos queryPos = new TilePos();
 
-            int bU = this.world.getSavedLightValue(LightLayer.Block, blockPos.up(queryPos));
-            final int bW = this.world.getSavedLightValue(LightLayer.Block, blockPos.west(queryPos));
-            final int bE = this.world.getSavedLightValue(LightLayer.Block, blockPos.east(queryPos));
-            final int bS = this.world.getSavedLightValue(LightLayer.Block, blockPos.south(queryPos));
-            final int bN = this.world.getSavedLightValue(LightLayer.Block, blockPos.north(queryPos));
-            if (bW > bU) {
-                bU = bW;
-            }
-            if (bE > bU) {
-                bU = bE;
-            }
-            if (bS > bU) {
-                bU = bS;
-            }
-            if (bN > bU) {
-                bU = bN;
-            }
-            blocklight = bU;
-
-            int sU = this.world.getSavedLightValue(LightLayer.Sky, blockPos.up(queryPos));
-            final int sW = this.world.getSavedLightValue(LightLayer.Sky, blockPos.west(queryPos));
-            final int sE = this.world.getSavedLightValue(LightLayer.Sky, blockPos.east(queryPos));
-            final int sS = this.world.getSavedLightValue(LightLayer.Sky, blockPos.south(queryPos));
-            final int sN = this.world.getSavedLightValue(LightLayer.Sky, blockPos.north(queryPos));
-            if (sW > sU) {
-                sU = sW;
-            }
-            if (sE > sU) {
-                sU = sE;
-            }
-            if (sS > sU) {
-                sU = sS;
-            }
-            if (sN > sU) {
-                sU = sN;
-            }
-            skylight = sU;
-
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.up(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.west(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.east(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.south(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.north(queryPos)));
         } else {
-            skylight = this.world.getSavedLightValue(LightLayer.Sky, blockPos);
-            blocklight = this.world.getSavedLightValue(LightLayer.Block, blockPos);
+            lightIndex = this.world.getSavedLightIndex(blockPos);
         }
 
-        return this.world.getLightmapCoord(skylight, blocklight);
+        return lightIndex;
     }
 
-    public int getLightmap(float partialTick) {
+    public byte getLightIndex(float partialTick) {
         return this.cachedLightmapCoord;
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java
index 014541f3c..7c01c1ae3 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java
@@ -45,7 +45,7 @@ public class ParticleArrowGolden extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAsh.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAsh.java
index 20397c62e..2ae163ce5 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAsh.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAsh.java
@@ -16,7 +16,7 @@ public class ParticleAsh extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java
index a61e89499..e03155d13 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java
@@ -6,7 +6,7 @@ import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
-import net.minecraft.core.enums.LightLayer;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
@@ -46,7 +46,7 @@ public class ParticleBlockBreaking extends Particle {
     @Override
     public void render(@NotNull TessellatorParticle t, float partialTick) {
         if (this.tex == null) return;
-        t.setLightmapCoord1i(getLightmap(partialTick));
+        t.setLightmapCoord1i(getLightIndex(partialTick));
         t.setColorOpaque3f(this.rCol, this.gCol, this.bCol);
         t.addParticle(
             MathHelper.lerp(this.xo, this.x, partialTick),
@@ -56,61 +56,26 @@ public class ParticleBlockBreaking extends Particle {
     }
 
     @Override
-    public int calcLightmap(float partialTick) {
-        if (Global.accessor.isFullbrightEnabled()) return 15 << 20 | 15;
+    public byte calcLightIndex(float partialTick) {
+        if (Global.accessor.isFullbrightEnabled()) return LightIndexHelper.lightIndex2i(15, 15);
         TilePos blockPos = new TilePos(
             MathHelper.lerp(this.xo, this.x, partialTick),
             MathHelper.lerp(this.yo, this.y, partialTick),
             MathHelper.lerp(this.zo, this.z, partialTick));
 
-        final int skylight;
-        final int blocklight;
-        if (this.world.getBlockLitInteriorSurface(blockPos) || blockPos.equals(this.initPos)) {
+        byte lightIndex = 0;
+        if (this.world.getBlockLitInteriorSurface(blockPos) || blockPos.equals(initPos)) {
             TilePos queryPos = new TilePos();
 
-            int bU = this.world.getSavedLightValue(LightLayer.Block, blockPos.up(queryPos));
-            final int bW = this.world.getSavedLightValue(LightLayer.Block, blockPos.west(queryPos));
-            final int bE = this.world.getSavedLightValue(LightLayer.Block, blockPos.east(queryPos));
-            final int bS = this.world.getSavedLightValue(LightLayer.Block, blockPos.south(queryPos));
-            final int bN = this.world.getSavedLightValue(LightLayer.Block, blockPos.north(queryPos));
-            if (bW > bU) {
-                bU = bW;
-            }
-            if (bE > bU) {
-                bU = bE;
-            }
-            if (bS > bU) {
-                bU = bS;
-            }
-            if (bN > bU) {
-                bU = bN;
-            }
-            blocklight = bU;
-
-            int sU = this.world.getSavedLightValue(LightLayer.Sky, blockPos.up(queryPos));
-            final int sW = this.world.getSavedLightValue(LightLayer.Sky, blockPos.west(queryPos));
-            final int sE = this.world.getSavedLightValue(LightLayer.Sky, blockPos.east(queryPos));
-            final int sS = this.world.getSavedLightValue(LightLayer.Sky, blockPos.south(queryPos));
-            final int sN = this.world.getSavedLightValue(LightLayer.Sky, blockPos.north(queryPos));
-            if (sW > sU) {
-                sU = sW;
-            }
-            if (sE > sU) {
-                sU = sE;
-            }
-            if (sS > sU) {
-                sU = sS;
-            }
-            if (sN > sU) {
-                sU = sN;
-            }
-            skylight = sU;
-
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.up(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.west(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.east(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.south(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.north(queryPos)));
         } else {
-            skylight = this.world.getSavedLightValue(LightLayer.Sky, blockPos);
-            blocklight = this.world.getSavedLightValue(LightLayer.Block, blockPos);
+            lightIndex = this.world.getSavedLightIndex(blockPos);
         }
 
-        return this.world.getLightmapCoord(skylight, blocklight);
+        return lightIndex;
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java
index fc9bb4af9..1587e0b04 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java
@@ -24,7 +24,7 @@ public class ParticleBubble extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleExplode.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleExplode.java
index 27ca2a5bc..e449080c7 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleExplode.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleExplode.java
@@ -16,7 +16,7 @@ public class ParticleExplode extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java
index 4cab8c024..aef5fb994 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java
@@ -5,6 +5,7 @@ import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.core.entity.animal.MobFireflyCluster;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
@@ -125,7 +126,7 @@ public class ParticleFirefly extends Particle {
         float x = (float) (this.xo + (this.x - this.xo) * partialTick);
         float y = (float) (this.yo + (this.y - this.yo) * partialTick);
         float z = (float) (this.zo + (this.z - this.zo) * partialTick);
-        t.setLightmapCoord1i(getLightmap(partialTick));
+        t.setLightmapCoord1i(getLightIndex(partialTick));
         t.setColorOpaque3f(this.rCol, this.gCol, this.bCol);
         t.addVertexWithUV(x + r, y - r, z / 10, u2, v2);
         t.addVertexWithUV(x + r, y + r, z / 10, u2, v0);
@@ -134,8 +135,8 @@ public class ParticleFirefly extends Particle {
     }
 
     @Override
-    public int calcLightmap(float partialTick) {
-        return LightmapHelper.setBlocklightValue(super.calcLightmap(partialTick), 15);
+    public byte calcLightIndex(float partialTick) {
+        return LightIndexHelper.setBlockLight(super.calcLightIndex(partialTick), 15);
     }
 
     public void tickGui() {
@@ -164,7 +165,7 @@ public class ParticleFirefly extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.sinTimer++;
         if (this.sinTimer > 100) {
             this.sinTimer = 0;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFlame.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFlame.java
index 19b708ded..a2fc5df57 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFlame.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFlame.java
@@ -4,6 +4,7 @@ import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
@@ -40,13 +41,13 @@ public class ParticleFlame extends Particle {
     }
 
     @Override
-    public int calcLightmap(float partialTick) {
-        return LightmapHelper.setBlocklightValue(super.calcLightmap(partialTick), 15);
+    public byte calcLightIndex(float partialTick) {
+        return LightIndexHelper.setBlockLight(super.calcLightIndex(partialTick), 15);
     }
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java
index 1a8f9e816..01c99d495 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java
@@ -1,11 +1,11 @@
 package net.minecraft.client.render.particle;
 
 import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.ParticleEngine;
 import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.Color;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
@@ -34,7 +34,7 @@ public class ParticleFluidDrip extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
@@ -61,7 +61,7 @@ public class ParticleFluidDrip extends Particle {
     @Override
     public void render(@NotNull TessellatorParticle t, float partialTick) {
         if (this.tex == null) return;
-        t.setLightmapCoord1i(getLightmap(partialTick));
+        t.setLightmapCoord1i(getLightIndex(partialTick));
         t.setColorOpaque3f(this.rCol, this.gCol, this.bCol);
         t.addParticle(
             MathHelper.lerp(this.xo, this.x, partialTick),
@@ -82,10 +82,10 @@ public class ParticleFluidDrip extends Particle {
     }
 
     @Override
-    public int calcLightmap(float partialTick) {
+    public byte calcLightIndex(float partialTick) {
         if (this.fullBright) {
-            return LightmapHelper.getOverbrightLightmapCoord(this.world.getSavedLightValue(LightLayer.Sky, new TilePos(this.x, this.y, this.z)));
+            return LightIndexHelper.lightIndex2i(this.world.getSavedLightValue(LightLayer.Sky, new TilePos(this.x, this.y, this.z)), 15);
         }
-        return super.calcLightmap(partialTick);
+        return super.calcLightIndex(partialTick);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFootstep.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFootstep.java
index f37a469dc..a92333e3c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFootstep.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFootstep.java
@@ -55,7 +55,7 @@ public class ParticleFootstep extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.life++;
         if (this.life == this.lifeTime) {
             this.remove();
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java
index eb7478e3d..3e3255b48 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java
@@ -41,7 +41,7 @@ public class ParticleHeart extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleItemBreaking.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleItemBreaking.java
index e7bdc13e4..7125f5740 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleItemBreaking.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleItemBreaking.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.particle;
 
-import net.minecraft.client.render.ParticleEngine;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.core.block.Blocks;
@@ -21,7 +20,7 @@ public class ParticleItemBreaking extends Particle {
     @Override
     public void render(@NotNull TessellatorParticle t, float partialTick) {
         if (this.tex == null) return;
-        t.setLightmapCoord1i(getLightmap(partialTick));
+        t.setLightmapCoord1i(getLightIndex(partialTick));
         t.setColorOpaque3f(this.rCol, this.gCol, this.bCol);
         t.addParticle(MathHelper.lerp(this.xo, this.x, partialTick),
             MathHelper.lerp(this.yo, this.y, partialTick),
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java
index b8aff2cfe..e126295de 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java
@@ -36,7 +36,7 @@ public class ParticleLava extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java
index 0a8577142..174fa6963 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java
@@ -39,7 +39,7 @@ public class ParticleLeaf extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         float windDirection = this.world.worldType.getWindManager().getWindDirection(this.world, (float) this.x, (float) this.y, (float) this.z);
         float windIntensity = this.world.worldType.getWindManager().getWindIntensity(this.world, (float) this.x, (float) this.y, (float) this.z) * 0.01f;
 
@@ -66,7 +66,7 @@ public class ParticleLeaf extends Particle {
     @Override
     public void render(@NotNull TessellatorParticle t, float partialTick) {
         if (this.tex == null) return;
-        t.setLightmapCoord1i(getLightmap(partialTick));
+        t.setLightmapCoord1i(getLightIndex(partialTick));
         t.setColorOpaque3f(this.rCol, this.gCol, this.bCol);
         t.addParticle(
             MathHelper.lerp(this.xo, this.x, partialTick),
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java
index dec30e89f..15338e4c7 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java
@@ -46,7 +46,7 @@ public class ParticleNote extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePickupAnimation.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePickupAnimation.java
index b2aa91c2f..b7afd1cbc 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePickupAnimation.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePickupAnimation.java
@@ -42,14 +42,14 @@ public class ParticlePickupAnimation extends Particle {
         xx -= xOff;
         yy -= yOff;
         zz -= zOff;
-        GLRenderer.setLightmapCoord1i(this.item.world.getLightmapCoord(tilePos, 0));
+        GLRenderer.setLightmapCoord1i(this.item.world.getLightIndex(tilePos, 0));
         GLRenderer.setColor4f(1f, 1f, 1f, 1f);
         EntityRendererDispatcher.instance.renderEntityWithPosYaw(t, this.item, (float) xx, (float) yy, (float) zz, this.item.yRot, partialTick);
     }
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.life++;
         if (this.life == this.lifeTime) {
             remove();
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java
index 6019c3626..eaaa968d6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java
@@ -54,7 +54,7 @@ public class ParticlePortal extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java
index 41d456651..a0adf6a45 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java
@@ -1,9 +1,9 @@
 package net.minecraft.client.render.particle;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.enums.LightLayer;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
@@ -53,9 +53,9 @@ public class ParticlePuffRGB extends Particle {
         int zTile = MathHelper.floor(this.z);
         int lmc;
         if (this.brightness >= 0) {
-            lmc = LightmapHelper.getLightmapCoord(this.world.getSavedLightValue(LightLayer.Sky, xTile, yTile, zTile), Math.max(this.world.getSavedLightValue(LightLayer.Block, xTile, yTile, zTile), this.brightness));
+            lmc = LightIndexHelper.lightIndex2i(this.world.getSavedLightValue(LightLayer.Sky, xTile, yTile, zTile), Math.max(this.world.getSavedLightValue(LightLayer.Block, xTile, yTile, zTile), this.brightness));
         } else {
-            lmc = getLightmap(partialTick);
+            lmc = getLightIndex(partialTick);
         }
         t.setLightmapCoord1i(lmc);
         t.setColorOpaque3f(this.rCol, this.gCol, this.bCol);
@@ -68,7 +68,7 @@ public class ParticlePuffRGB extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java
index 97c8ee12e..d3f35182f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java
@@ -6,6 +6,7 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.util.helper.Colors;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.Color;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
@@ -61,9 +62,9 @@ public class ParticleRedstoneDust extends Particle {
         int zTile = MathHelper.floor(this.z);
         int lmc;
         if (this.brightness >= 0) {
-            lmc = LightmapHelper.getLightmapCoord(this.world.getSavedLightValue(LightLayer.Sky, xTile, yTile, zTile), Math.max(this.world.getSavedLightValue(LightLayer.Block, xTile, yTile, zTile), this.brightness));
+            lmc = LightIndexHelper.lightIndex2i(this.world.getSavedLightValue(LightLayer.Sky, xTile, yTile, zTile), Math.max(this.world.getSavedLightValue(LightLayer.Block, xTile, yTile, zTile), this.brightness));
         } else {
-            lmc = getLightmap(partialTick);
+            lmc = getLightIndex(partialTick);
         }
         t.setLightmapCoord1i(lmc);
         t.setColorOpaque3f(this.rCol, this.gCol, this.bCol);
@@ -78,7 +79,7 @@ public class ParticleRedstoneDust extends Particle {
 
     @Override
     public void tick() {
-        this.cachedLightmapCoord = calcLightmap(1f);
+        this.cachedLightmapCoord = calcLightIndex(1f);
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSlimeChunk.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSlimeChunk.java
index edc08c51d..d83182881 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSlimeChunk.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSlimeChunk.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.particle;
 
-import net.minecraft.client.render.ParticleEngine;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.tessellator.TessellatorParticle;
 import net.minecraft.core.item.Item;
@@ -22,7 +21,7 @@ public class ParticleSlimeChunk extends Particle {
     public void render(@NotNull TessellatorParticle t, float partialTick) {
         if (this.tex == null) return;
         float br = 1.0f;
-        t.setLightmapCoord1i(getLightmap(partialTick));
+        t.setLightmapCoord1i(getLightIndex(partialTick));
         t.setColorOpaque3f(this.rCol * br, this.gCol * br, this.bCol * br);
         t.addParticle(MathHelper.lerp(this.xo, this.x, partialTick),
             MathHelper.lerp(this.yo, this.y, partialTick),
diff --git a/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java b/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java
index 25868a062..78e748be1 100644
--- a/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java
@@ -5,14 +5,20 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.FogManager;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.shader.Shader;
 import net.minecraft.client.render.tessellator.RenderBuffer;
 import net.minecraft.client.render.tessellator.TessellatorShader;
 import net.minecraft.client.render.uniform.UniformBlockManager;
 import net.minecraft.core.util.helper.Color;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import org.jetbrains.annotations.NotNull;
-import org.joml.*;
+import org.joml.Matrix4f;
+import org.joml.Matrix4fStack;
+import org.joml.Vector3dc;
+import org.joml.Vector3fc;
+import org.joml.Vector4dc;
+import org.joml.Vector4f;
+import org.joml.Vector4fc;
 import org.lwjgl.BufferUtils;
 import org.lwjgl.opengl.GL41;
 import org.slf4j.Logger;
@@ -112,10 +118,8 @@ public class GLRenderer {
     private float currentPolygonFactor = 0f;
     private float currentPolygonUnits = 0f;
 
-    private final float[] lightmapBlockStack = new float[RENDER_FRAMES_STACK_SIZE];
-    private final float[] lightmapSkyStack = new float[RENDER_FRAMES_STACK_SIZE];
-    private float currentLightmapBlock = 15.5f/16f;
-    private float currentLightmapSky = 15.5f/16f;
+    private final byte[] lightIndexStack = new byte[RENDER_FRAMES_STACK_SIZE];
+    private byte currentLightIndex = LightIndexHelper.lightIndex2i(15, 15);
 
     private final float[] alphaTestStack = new float[RENDER_FRAMES_STACK_SIZE];
     private float currentAlphaTest = 0.1f;
@@ -134,7 +138,6 @@ public class GLRenderer {
 
     }
 
-    private static final FloatBuffer lightBuf = BufferUtils.createFloatBuffer(8);
     private static final Matrix4f matBuf = new Matrix4f();
     public static void globalSetUniforms(@NotNull Shader shader) {
         shader.bind();
@@ -324,25 +327,20 @@ public class GLRenderer {
         return instance.currentPolygonUnits;
     }
 
-    public static void setLightmapCoord1i(int lightmapCoord) {
-        setLightmapCoord2i(LightmapHelper.getBlockLightFromCoord(lightmapCoord), LightmapHelper.getSkyLightFromCoord(lightmapCoord));
+    public static void setLightmapCoord1i(int lightIndex) {
+        instance.currentLightIndex = (byte) lightIndex;
     }
 
-    public static void setLightmapCoord2i(int blockLight, int skyLight) {
-        setLightmapCoord2f((blockLight + 0.5f) / 16f, (skyLight + 0.5f) / 16f);
+    public static void setLightmapCoord2i(int skyLight, int blockLight) {
+        setLightmapCoord1i(LightIndexHelper.lightIndex2i(skyLight, blockLight));
     }
 
-    public static void setLightmapCoord2f(float blockLight, float skyLight) {
-        instance.currentLightmapBlock = blockLight;
-        instance.currentLightmapSky = skyLight;
+    public static void setLightmapCoord2f(float skyLight, float blockLight) {
+        setLightmapCoord1i(LightIndexHelper.lightIndex2f(skyLight, blockLight));
     }
 
-    public static float getLightmapBlock() {
-        return instance.currentLightmapBlock;
-    }
-
-    public static float getLightmapSky() {
-        return instance.currentLightmapSky;
+    public static byte getLightIndex() {
+        return instance.currentLightIndex;
     }
 
     public static void setAlphaTest(float alphaTest) {
@@ -423,8 +421,7 @@ public class GLRenderer {
         instance.depthMaskStack[instance.stackIndex] = instance.currentDepthMask;
         instance.polygonFactorStack[instance.stackIndex] = instance.currentPolygonFactor;
         instance.polygonUnitsStack[instance.stackIndex] = instance.currentPolygonUnits;
-        instance.lightmapBlockStack[instance.stackIndex] = instance.currentLightmapBlock;
-        instance.lightmapSkyStack[instance.stackIndex] = instance.currentLightmapSky;
+        instance.lightIndexStack[instance.stackIndex] = instance.currentLightIndex;
         instance.alphaTestStack[instance.stackIndex] = instance.currentAlphaTest;
 
         if (DEBUG) {
@@ -524,8 +521,7 @@ public class GLRenderer {
             GL41.glPolygonOffset(instance.currentPolygonFactor, instance.currentPolygonUnits);
         }
 
-        instance.currentLightmapBlock = instance.lightmapBlockStack[instance.stackIndex];
-        instance.currentLightmapSky = instance.lightmapSkyStack[instance.stackIndex];
+        instance.currentLightIndex = instance.lightIndexStack[instance.stackIndex];
         instance.currentAlphaTest = instance.alphaTestStack[instance.stackIndex];
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/renderer/Shaders.java b/game/client/src/main/java/net/minecraft/client/render/renderer/Shaders.java
index 248d155e0..a7501c872 100644
--- a/game/client/src/main/java/net/minecraft/client/render/renderer/Shaders.java
+++ b/game/client/src/main/java/net/minecraft/client/render/renderer/Shaders.java
@@ -25,7 +25,8 @@ public final class Shaders {
     public static final @NotNull Shader WORLD = register("world", new Shader());
     public static final @NotNull Shader AURORA = register("aurora", new Shader());
     public static final @NotNull Shader ENTITY = register("entity", new Shader());
-    public static final @NotNull Shader TERRAIN = register("terrain", new Shader());
+    public static final @NotNull Shader TERRAIN = register("terrain", new ShaderGeometry());
+    public static final @NotNull Shader ITEM = register("item", new Shader());
     public static final @NotNull Shader INTERFACE = register("interface", new Shader());
     public static final @NotNull Shader COLOR = register("color", new Shader());
     public static final @NotNull Shader COLOR_WORLD = register("color_world", new Shader());
@@ -33,6 +34,7 @@ public final class Shaders {
     public static final @NotNull ShaderGeometry PARTICLE = register("particle", new ShaderGeometry());
     public static final @NotNull ShaderGeometry FONT = register("font", new ShaderGeometry());
     public static final @NotNull ShaderGeometry LINES = register("lines", new ShaderGeometry());
+    public static final @NotNull ShaderGeometry LOD = register("lod", new ShaderGeometry());
 
     public static @NotNull <T extends Shader> T register(@NotNull String id, @NotNull T shader) {
         if (!ALL_SHADERS.contains(shader)) ALL_SHADERS.add(shader);
@@ -51,7 +53,7 @@ public final class Shaders {
                 entry.getValue().uniformInt("colortex", 0);
                 entry.getValue().uniformInt("lighttex", 1);
                 entry.getValue().uniformInt("emmisivetex", 2);
-//                entry.getValue().uniformInt("colormasktex", 3);
+                entry.getValue().uniformInt("colormasktex", 3);
                 GL41.glUseProgram(0);
             } catch (Exception e) {
                 LOGGER.error("", e);
@@ -73,7 +75,7 @@ public final class Shaders {
                 entry.getValue().uniformInt("colortex", 0);
                 entry.getValue().uniformInt("lighttex", 1);
                 entry.getValue().uniformInt("emmisivetex", 2);
-//                entry.getValue().uniformInt("colormasktex", 3);
+                entry.getValue().uniformInt("colormasktex", 3);
                 GL41.glUseProgram(0);
             } catch (Exception e) {
                 LOGGER.error("", e);
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java
index 3a1a5a151..ccce9eb04 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java
@@ -3,15 +3,13 @@ package net.minecraft.client.render.terrain;
 import java.util.ArrayList;
 import java.util.List;
 
-import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.core.block.entity.TileEntity;
-import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Vector3i;
 import org.joml.primitives.AABBd;
 
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.camera.ICamera;
 import net.minecraft.client.render.culling.CameraFrustum;
 import net.minecraft.core.entity.Entity;
@@ -22,88 +20,73 @@ public abstract class ChunkRenderer {
     public static final int MAX_RENDER_PASSES = 2;
     public static int updates = 0;
 
-    public World world;
-    public int posX;
-    public int posY;
-    public int posZ;
-    public int sizeX;
-    public int sizeY;
-    public int sizeZ;
-    public int xRender;
-    public int yRender;
-    public int zRender;
-    public int xRenderOffs;
-    public int yRenderOffs;
-    public int zRenderOffs;
-    public boolean visible;
-    public boolean[] empty;
-    public int xm;
-    public int ym;
-    public int zm;
-    public float radius;
-    public boolean dirty;
-    public AABBd bb;
-    public int id;
-    public boolean skyLit;
-    protected boolean compiled;
-    public @NotNull List<@NotNull TileEntity> renderableBlockEntities;
+    public final boolean @NotNull [] empty = new boolean[MAX_RENDER_PASSES];
+
+    public boolean visible = false;
+    public int id = -1;
+
+    protected final @NotNull TilePos pos = new TilePos();
+    protected final @NotNull Vector3i size = new Vector3i();
+    protected final @NotNull List<@NotNull TileEntity> renderableBlockEntities = new ArrayList<>();
     protected final @NotNull List<@NotNull TileEntity> globalRenderableBlockEntities;
+    protected boolean compiled = false;
 
-    public ChunkRenderer(@NotNull World world, @NotNull List<@NotNull TileEntity> globalRenderableTileEntities, int x, int y, int z, int size) {
-        this.visible = false;
-        this.empty = new boolean[MAX_RENDER_PASSES];
-        this.compiled = false;
-        this.renderableBlockEntities = new ArrayList<>();
+    private final @NotNull Vector3i middlePos = new Vector3i();
+    private final @NotNull AABBd bb = new AABBd();
+
+    private @Nullable World world;
+    private boolean dirty = true;
+
+    public ChunkRenderer(
+        final @NotNull World world,
+        final @NotNull List<@NotNull TileEntity> globalRenderableTileEntities,
+        final int x, final int y, final int z,
+        final int size
+    ) {
         this.world = world;
         this.globalRenderableBlockEntities = globalRenderableTileEntities;
-        this.sizeX = this.sizeY = this.sizeZ = size;
-        this.radius = MathHelper.sqrt_float(this.sizeX * this.sizeX + this.sizeY * this.sizeY + this.sizeZ * this.sizeZ) / 2.0F;
-        this.posX = -999;
-        setPos(x, y, z);
-        this.dirty = false;
+        this.size.set(size);
+        this.setPosInner(x, y, z);
     }
 
-    public void setPos(int x, int y, int z) {
-        if (x != this.posX || y != this.posY || z != this.posZ) {
-            reset();
-            this.posX = x;
-            this.posY = y;
-            this.posZ = z;
-            this.xm = x + this.sizeX / 2;
-            this.ym = y + this.sizeY / 2;
-            this.zm = z + this.sizeZ / 2;
-            this.xRenderOffs = x & 0x3ff;
-            this.yRenderOffs = y;
-            this.zRenderOffs = z & 0x3ff;
-            this.xRender = x - this.xRenderOffs;
-            this.yRender = y - this.yRenderOffs;
-            this.zRender = z - this.zRenderOffs;
-            float f = 6F;
-            this.bb = new AABBd(x - f, y - f,  z - f, (x + this.sizeX) + f, (y + this.sizeY) + f, (z + this.sizeZ) + f);
-            setDirty();
-        }
+    public @NotNull World getWorld() {
+        assert this.world != null;
+        return this.world;
     }
 
-    public abstract boolean rebuild(boolean priority);
+    public void setPos(final int x, final int y, final int z) {
+        if (x != this.pos.x || y != this.pos.y || z != this.pos.z) {
+            this.reset();
+            this.setPosInner(x, y, z);
+            this.setDirty(true);
+        }
+    }
 
-    public boolean renderBlock(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull BlockModel<?> model, @NotNull TilePos tilePos) {
-        tessellator.setLightmapCoord1i(LightmapHelper.getLightmapCoord(15, 15));
-        tessellator.setColor4i(255, 255, 255, 255);
-        tessellator.setTextureUV(0.0, 0.0);
-        return model.render(tessellator, worldSource, tilePos);
+    private void setPosInner(final int x, final int y, final int z) {
+        this.pos.x = x;
+        this.pos.y = y;
+        this.pos.z = z;
+        this.middlePos.x = x + this.size.y / 2;
+        this.middlePos.y = y + this.size.y / 2;
+        this.middlePos.z = z + this.size.z / 2;
+        final float radius = 6F;
+        this.bb.setMin(x - radius, y - radius, z - radius);
+        this.bb.setMax((x + this.size.x) + radius, (y + this.size.y) + radius, (z + this.size.z) + radius);
     }
 
-    public float distanceToEntitySquared(Entity entity) {
-        float dx = (float) (entity.x - (double) this.xm);
-        float dy = (float) (entity.y - (double) this.ym);
-        float dz = (float) (entity.z - (double) this.zm);
+    public abstract boolean rebuild(boolean priority);
+
+    public float distanceToEntitySquared(final @NotNull Entity entity) {
+        final float dx = (float) (entity.x - this.middlePos.x);
+        final float dy = (float) (entity.y - this.middlePos.y);
+        final float dz = (float) (entity.z - this.middlePos.z);
         return dx * dx + dy * dy + dz * dz;
     }
 
-    public float distanceToCameraSquared(ICamera camera) {
-        float dx = (float) (camera.getX(1f) - this.xm);
-        float dy = (float) (camera.getY(1f) - this.ym);
-        float dz = (float) (camera.getZ(1f) - this.zm);
+    public float distanceToCameraSquared(final @NotNull ICamera camera) {
+        final float dx = (float) (camera.getX(1f) - this.middlePos.x);
+        final float dy = (float) (camera.getY(1f) - this.middlePos.y);
+        final float dz = (float) (camera.getZ(1f) - this.middlePos.z);
         return dx * dx + dy * dy + dz * dz;
     }
 
@@ -117,11 +100,11 @@ public abstract class ChunkRenderer {
     }
 
     public void delete() {
-        reset();
+        this.reset();
         this.world = null;
     }
 
-    public void cull(CameraFrustum frustum, float partialTick) {
+    public void cull(final @NotNull CameraFrustum frustum, final float partialTick) {
         this.visible = frustum.isVisible(this.bb, partialTick);
     }
 
@@ -133,7 +116,11 @@ public abstract class ChunkRenderer {
         }
     }
 
-    public void setDirty() {
-        this.dirty = true;
+    public void setDirty(final boolean dirty) {
+        this.dirty = dirty;
+    }
+
+    public boolean isDirty() {
+        return this.dirty;
     }
 }
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 40213daea..7b02ffd9b 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
@@ -2,6 +2,7 @@ package net.minecraft.client.render.terrain;
 
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 import net.minecraft.client.render.TileEntityRenderDispatcher;
@@ -9,21 +10,36 @@ import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.culling.CameraFrustum;
 import net.minecraft.client.render.terrain.VertexBuffer.Entry;
+import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.client.render.tessellator.TessellatorTerrainImpl;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.chunk.ChunkCache;
 import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ChunkRendererMultiDraw extends ChunkRenderer {
-    private static final @NotNull TessellatorTerrainImpl tessellatorTerrain = new TessellatorTerrainImpl(0x200000);
-    public final TerrainRendererMultiDraw terrainRenderer;
-    public final Entry[] renderListEntries;
-
-    public ChunkRendererMultiDraw(@NotNull TerrainRendererMultiDraw terrainRenderer, @NotNull World world, @NotNull List<@NotNull TileEntity> globalRenderableTileEntities, int x, int y, int z, int size) {
+    private static final @NotNull TessellatorTerrainImpl TESSELLATOR = new TessellatorTerrainImpl(0x200000);
+
+    public final @Nullable Entry<TessellatorTerrainImpl.TerrainVertexConfig> @NotNull [] renderListEntries;
+
+    private final @NotNull TerrainRendererMultiDraw terrainRenderer;
+    private final @NotNull TilePos min = new TilePos();
+    private final @NotNull TilePos max = new TilePos();
+    private final @NotNull TilePos cacheMin = new TilePos();
+    private final @NotNull TilePos cacheMax = new TilePos();
+
+    public ChunkRendererMultiDraw(
+        final @NotNull TerrainRendererMultiDraw terrainRenderer,
+        final @NotNull World world,
+        final @NotNull List<@NotNull TileEntity> globalRenderableTileEntities,
+        final int x, final int y, final int z,
+        final int size
+    ) {
         super(world, globalRenderableTileEntities, x, y, z, size);
 
         this.terrainRenderer = terrainRenderer;
@@ -31,24 +47,24 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
     }
 
     @Override
-    public boolean rebuild(boolean priority) {
-        if (!this.dirty) {
+    public boolean rebuild(final boolean priority) {
+        if (!this.isDirty()) {
             return false;
         }
 
-        final int minX = this.posX;
-        final int minY = this.posY;
-        final int minZ = this.posZ;
+        this.min.set(this.pos);
+        this.max.set(this.pos).add(this.size);
 
-        final int maxX = this.posX + this.sizeX;
-        final int maxY = this.posY + this.sizeY;
-        final int maxZ = this.posZ + this.sizeZ;
+        final int cacheRadius = 1;
+        this.cacheMin.set(this.min).sub(cacheRadius, cacheRadius, cacheRadius);
+        this.cacheMax.set(this.max).add(cacheRadius, cacheRadius, cacheRadius);
 
-        final int renderPassCount = this.terrainRenderer.MAX_RENDER_PASSES;
+        final int renderPassCount = TerrainRendererMultiDraw.MAX_RENDER_PASSES;
 
-        final int cacheRadius = 1;
-        final ChunkCache chunkCache = new ChunkCache(this.world, new TilePos(minX - cacheRadius, minY - cacheRadius, minZ - cacheRadius), new TilePos(maxX + cacheRadius, maxY + cacheRadius, maxZ + cacheRadius), priority);
-        if (!chunkCache.allLoaded()) return false;
+        final ChunkCache chunkCache = new ChunkCache(this.getWorld(), this.cacheMin, this.cacheMax, priority);
+        if (!chunkCache.allLoaded()) {
+            return false;
+        }
 
         this.terrainRenderer.chunkDeleted(this);
         Chunk.isLit = false;
@@ -57,23 +73,22 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
 
         updates++;
 
-        TessellatorTerrainImpl tessellator = tessellatorTerrain;
+        final @NotNull TilePos pos = new TilePos(0, 0, 0);
         for (int renderPass = 0; renderPass < renderPassCount; renderPass++) {
             boolean needsMoreRenderPasses = false;
             boolean hasRenderedBlock = false;
             boolean hasStartedDrawing = false;
 
-            TilePos pos = new TilePos(0, 0, 0);
-            for (pos.y = minY; pos.y < maxY; pos.y++) {
-                for (pos.z = minZ; pos.z < maxZ; pos.z++) {
-                    for (pos.x = minX; pos.x < maxX; pos.x++) {
+            for (pos.y = this.min.y; pos.y < this.max.y; pos.y++) {
+                for (pos.z = this.min.z; pos.z < this.max.z; pos.z++) {
+                    for (pos.x = this.min.x; pos.x < this.max.x; pos.x++) {
                         final @NotNull Block<?> block = chunkCache.getBlockType(pos);
                         if (!hasStartedDrawing) {
                             hasStartedDrawing = true;
-                            tessellator.startDrawingQuads();
+                            TESSELLATOR.startDrawingQuads();
 
-                            RenderRegion region = this.terrainRenderer.getRenderRegionAtBlockPos(this.posX, this.posZ);
-                            tessellator.setTranslation(-(region.posX << this.terrainRenderer.REGION_SIZE), 0.0, -(region.posZ << this.terrainRenderer.REGION_SIZE));
+                            final RenderRegion region = this.terrainRenderer.getRenderRegionAtBlockPos(this.pos.x, this.pos.z);
+                            TESSELLATOR.setTranslation(-(region.posX << TerrainRendererMultiDraw.REGION_SIZE), 0.0, -(region.posZ << TerrainRendererMultiDraw.REGION_SIZE));
                         }
                         if (renderPass == 0 && block.isEntityTile()) {
                             final TileEntity tileentity = chunkCache.getTileEntity(pos);
@@ -89,13 +104,13 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
                             continue;
                         }
 
-                        hasRenderedBlock |= renderBlock(tessellator, chunkCache, model, pos);
+                        hasRenderedBlock |= this.renderBlock(chunkCache, model, pos);
                     }
                 }
             }
             if (hasStartedDrawing) {
-                this.terrainRenderer.chunkRendered(this, tessellator, renderPass);
-                tessellator.setTranslation(0.0, 0.0, 0.0);
+                this.terrainRenderer.chunkRendered(this, TESSELLATOR, renderPass);
+                TESSELLATOR.setTranslation(0.0, 0.0, 0.0);
             } else {
                 hasRenderedBlock = false;
             }
@@ -108,19 +123,18 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
             }
         }
 
-        HashSet<TileEntity> newSpecialTileEntities = new HashSet<>(this.renderableBlockEntities);
+        final HashSet<TileEntity> newSpecialTileEntities = new HashSet<>(this.renderableBlockEntities);
         newSpecialTileEntities.removeAll(lastSpecialTileEntities);
         this.globalRenderableBlockEntities.addAll(newSpecialTileEntities);
         this.renderableBlockEntities.forEach(lastSpecialTileEntities::remove);
         this.globalRenderableBlockEntities.removeAll(lastSpecialTileEntities);
-        this.skyLit = Chunk.isLit;
         this.compiled = true;
         return true;
     }
 
     @Override
-    public void cull(CameraFrustum frustum, float partialTick) {
-        boolean wasVisible = this.visible;
+    public void cull(final @NotNull CameraFrustum frustum, final float partialTick) {
+        final boolean wasVisible = this.visible;
         super.cull(frustum, partialTick);
         if (wasVisible != this.visible) {
             this.terrainRenderer.chunkVisibilityChanged(this);
@@ -129,15 +143,20 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
 
     @Override
     public void reset() {
-        // TerrainRenderer is null during initialization
-        if (this.terrainRenderer != null) {
-            this.terrainRenderer.chunkDeleted(this);
-        }
+        this.terrainRenderer.chunkDeleted(this);
         super.reset();
     }
 
     @Override
     public String toString() {
-        return "[" + this.posX + "," + this.posY + "," + this.posZ + "]";
+        return "[" + this.pos.x + "," + this.pos.y + "," + this.pos.z + "]";
+    }
+
+    protected boolean renderBlock(final @NotNull WorldSource worldSource, final @NotNull BlockModel<?> model, final @NotNull TilePos tilePos) {
+        TESSELLATOR.setLightmapCoord2i(15, 15);
+        TESSELLATOR.setColor4i(255, 255, 255, 255);
+        TESSELLATOR.setTextureUV(0.0, 0.0);
+        TESSELLATOR.setShade1i(0xFF);
+        return model.render(TESSELLATOR, worldSource, tilePos);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/RegionBuffer.java b/game/client/src/main/java/net/minecraft/client/render/terrain/RegionBuffer.java
index 5b11603b8..a36419034 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/RegionBuffer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/RegionBuffer.java
@@ -3,6 +3,10 @@ package net.minecraft.client.render.terrain;
 import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import net.minecraft.client.render.tessellator.TessellatorTerrainImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.UnmodifiableView;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -10,62 +14,62 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class RegionBuffer {
-	
-	public final int regionSizeShift;
-	
-	private final Int2ObjectMap<RenderRegion> regionMap = new Int2ObjectOpenHashMap<>();
-	private final List<RenderRegion> regionList = new ArrayList<>();
-	private final List<RenderRegion> immutableRegionList = Collections.unmodifiableList(regionList);
-	
-	public RegionBuffer(int regionSizeShift) {
-		this.regionSizeShift = regionSizeShift;
-	}
-	
-	public RenderRegion getRegionAtBlockPos(int blockX, int blockZ) {
-		int x = blockX >> regionSizeShift;
-		int z = blockZ >> regionSizeShift;
-		return getRegion(x, z);
-	}
-	
-	public RenderRegion getRegion(int x, int z) {
-		int index = getIndex(x, z);
-		
-		RenderRegion region = regionMap.get(index);
-		if(region == null) {
-			region = new RenderRegion(x, z);
-			regionMap.put(index, region);
-			regionList.add(region);
-		}else {
-			if(region.posX != x || region.posZ != z) {
-				throw new RuntimeException(region + " != " + new RenderRegion(x, z));
-			}	
-		}
-		return region;
-	}
-	
-	public void remove(RenderRegion region) {
-		int index = getIndex(region.posX, region.posZ);
-		
-		RenderRegion existingRegion = regionMap.get(index);
-		if(existingRegion != region) {
-			throw new RuntimeException(region + " != " + existingRegion);
-		}
-		
-		regionMap.remove(index);
-		regionList.remove(region);
-	}
-	
-	public int getIndex(int x, int z) {
-		return ((x & 0xFFFF) << 16) | (z & 0xFFFF);
-	}
-	
-	public List<RenderRegion> getAllRegions() {
-		return immutableRegionList;
-	}
-	
-	public int size() {
-		return regionMap.size();
-	}
-	
+public class RegionBuffer<V extends VertexConfig<V>> {
+    private final @NotNull Int2ObjectMap<@NotNull RenderRegion<V>> regionMap = new Int2ObjectOpenHashMap<>();
+    private final @NotNull List<@NotNull RenderRegion<V>> regionList = new ArrayList<>();
+    private final @NotNull @UnmodifiableView List<@NotNull RenderRegion<V>> immutableRegionList = Collections.unmodifiableList(this.regionList);
+
+    private final int regionSizeShift;
+
+    public RegionBuffer(final int regionSizeShift) {
+        this.regionSizeShift = regionSizeShift;
+    }
+
+    public @NotNull RenderRegion<V> getRegionAtBlockPos(final int blockX, final int blockZ) {
+        final int x = blockX >> this.regionSizeShift;
+        final int z = blockZ >> this.regionSizeShift;
+        return this.getRegion(x, z);
+    }
+
+    public @NotNull RenderRegion<V> getRegion(final int x, final int z) {
+        final int index = this.getIndex(x, z);
+
+        @Nullable RenderRegion<V> region = this.regionMap.get(index);
+        if (region == null) { // can be null despite what IntelliJ says
+            region = new RenderRegion<>(x, z);
+            this.regionMap.put(index, region);
+            this.regionList.add(region);
+        } else {
+            if (region.posX != x || region.posZ != z) {
+                throw new RuntimeException(region + " != " + new RenderRegion<>(x, z));
+            }
+        }
+
+        return region;
+    }
+
+    public void remove(final @NotNull RenderRegion<V> region) {
+        final int index = this.getIndex(region.posX, region.posZ);
+
+        final @Nullable RenderRegion<V> existingRegion = this.regionMap.get(index);
+        if (existingRegion != region) {
+            throw new RuntimeException(region + " != " + existingRegion);
+        }
+
+        this.regionMap.remove(index);
+        this.regionList.remove(region);
+    }
+
+    public int getIndex(final int x, final int z) {
+        return ((x & 0xFFFF) << 16) | (z & 0xFFFF);
+    }
+
+    public @NotNull @UnmodifiableView List<@NotNull RenderRegion<V>> getAllRegions() {
+        return this.immutableRegionList;
+    }
+
+    public int size() {
+        return this.regionMap.size();
+    }
+
 }
\ No newline at end of file
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 cea334730..9325695f4 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
@@ -3,40 +3,37 @@ package net.minecraft.client.render.terrain;
 import static org.lwjgl.opengl.GL41.*;
 
 import java.nio.IntBuffer;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
 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.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.BufferUtils;
 
 /**
- * 		Can render a lot of objects with a single call
- * <br> All objects need to have the same {@link VertexConfigStandard}
+ * Can render a lot of objects with a single call
+ * <br> All objects need to have the same {@link VertexConfig}
  * <br> Entries can be toggled visible or invisible quickly
  */
-public class RenderList {
+public class RenderList<V extends VertexConfig<V>> {
     private static final CategorizedLogger LOGGER = LogUtils.getLogger();
 
-    public final VertexBuffer vertexBuffer;
+    private final @NotNull V vertexConfig;
+    private final @NotNull VertexBuffer vertexBuffer;
 
-    private VertexConfig<?> vertexConfig;
-    private boolean vertexConfigLocked = false;
+    private final @NotNull List<@NotNull Entry<V>> entryList = new ArrayList<>();
+    private final @NotNull Set<@NotNull Entry<V>> visibleEntries = new HashSet<>();
 
-    private IntBuffer posBuffer;
-    private IntBuffer sizeBuffer;
-
-    private final List<Entry> entryList = new ArrayList<>();
-    private final Set<Entry> visibleEntries = new HashSet<>();
+    private @NotNull IntBuffer sizeBuffer;
+    private @NotNull IntBuffer posBuffer;
 
     private boolean visibleEntriesUpdated = true;
 
-    public RenderList(VertexBuffer vertexBuffer, int capacity) {
+    public RenderList(final @NotNull VertexBuffer vertexBuffer, final @NotNull V vertexConfig, final int capacity) {
         this.vertexBuffer = vertexBuffer;
+        this.vertexConfig = vertexConfig;
         this.posBuffer = BufferUtils.createByteBuffer(capacity * 4).asIntBuffer();
         this.sizeBuffer = BufferUtils.createByteBuffer(capacity * 4).asIntBuffer();
     }
@@ -48,7 +45,7 @@ public class RenderList {
         }
 
         if (this.visibleEntriesUpdated) {
-            int vertexSize = this.vertexConfig.getVertexSize();
+            final int vertexSize = this.vertexConfig.getVertexSize();
 
             this.posBuffer = expandIfNecessary(this.posBuffer, this.visibleEntries.size());
             this.sizeBuffer = expandIfNecessary(this.sizeBuffer, this.visibleEntries.size());
@@ -56,9 +53,9 @@ public class RenderList {
             this.posBuffer.clear();
             this.sizeBuffer.clear();
 
-            for (Entry entry : this.visibleEntries) {
-                int pos = (int) (entry.position / vertexSize);
-                int size = (int) (entry.size / vertexSize);
+            for (final @NotNull Entry<V> entry : this.visibleEntries) {
+                final int pos = (int) (entry.position / vertexSize);
+                final 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);
@@ -77,21 +74,15 @@ public class RenderList {
         }
 
 //		System.out.println("Rendering " + visibleEntries.size() + " entries");
-        glMultiDrawArrays(this.vertexConfig.drawmode().cap, this.posBuffer, this.sizeBuffer);
+        glMultiDrawArrays(this.vertexConfig.drawMode().cap, this.posBuffer, this.sizeBuffer);
     }
 
-    public Entry add(VertexData vertexData, boolean visible) {
+    public @Nullable Entry<V> add(final @NotNull VertexData<V> vertexData, final boolean visible) {
         if (vertexData.vertexCount <= 0) {
             return null;
         }
 
-        if (this.entryList.isEmpty() && !this.vertexConfigLocked) {
-            this.vertexConfig = vertexData.config.copy();
-        } else {
-            VertexConfigStandard.compareThrow(this.vertexConfig, vertexData.config);
-        }
-
-        Entry entry = this.vertexBuffer.addVertexData(vertexData);
+        final @NotNull Entry<V> entry = Objects.requireNonNull(this.vertexBuffer.addVertexData(vertexData));
         this.entryList.add(entry);
 
         if (visible) {
@@ -102,10 +93,7 @@ public class RenderList {
         return entry;
     }
 
-    public void setVisible(Entry entry, boolean visible) {
-        if (entry == null) {
-            throw new NullPointerException();
-        }
+    public void setVisible(final @NotNull Entry<V> entry, final boolean visible) {
         if (visible) {
             if (this.visibleEntries.add(entry)) {
                 this.visibleEntriesUpdated = true;
@@ -117,18 +105,7 @@ public class RenderList {
         }
     }
 
-    public void lockVertexConfig(VertexConfigStandard vertexConfig) {
-        if (vertexConfig == null) {
-            throw new NullPointerException("VertexConfig cannot be null!");
-        }
-        if (!this.entryList.isEmpty() && !this.vertexConfig.equals(vertexConfig)) {
-            VertexConfigStandard.compareThrow(this.vertexConfig, vertexConfig);
-        }
-        this.vertexConfig = vertexConfig.copy();
-        this.vertexConfigLocked = true;
-    }
-
-    public boolean remove(Entry entry) {
+    public boolean remove(final @NotNull Entry<V> entry) {
         if (this.entryList.remove(entry)) {
             this.vertexBuffer.removeEntry(entry);
             this.visibleEntries.remove(entry);
@@ -146,17 +123,13 @@ public class RenderList {
         return this.visibleEntries.size();
     }
 
-    public VertexConfig<?> getVertexConfig() {
+    public @NotNull V getVertexConfig() {
         return this.vertexConfig;
     }
 
-    public boolean isVertexConfigLocked() {
-        return this.vertexConfigLocked;
-    }
-
-    public static IntBuffer expandIfNecessary(IntBuffer buffer, int requiredCapacity) {
+    private static @NotNull IntBuffer expandIfNecessary(final @NotNull IntBuffer buffer, final int requiredCapacity) {
         if (buffer.capacity() < requiredCapacity) {
-            int newCapacity = Math.max(buffer.capacity() * 2, requiredCapacity);
+            final int newCapacity = Math.max(buffer.capacity() * 2, requiredCapacity);
 
             LOGGER.warn("Expanding RenderList IntBuffer from {} to {} ints...", buffer.capacity(), newCapacity);
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/RenderRegion.java b/game/client/src/main/java/net/minecraft/client/render/terrain/RenderRegion.java
index 5a1d2f619..206e143a6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/RenderRegion.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/RenderRegion.java
@@ -1,30 +1,23 @@
 package net.minecraft.client.render.terrain;
 
-public class RenderRegion {
-	
-	public final int posX;
-	public final int posZ;
-	
-	public RenderList[] renderLists = new RenderList[2];
-	
-	public RenderRegion(int posX, int posZ) {
-		this.posX = posX;
-		this.posZ = posZ;
-	}
-	
-	public boolean hasRenderData() {
-		for(int i=0; i < renderLists.length; i++) {
-			RenderList renderList = renderLists[i];
-			if(renderList != null && renderList.size() > 0) {
-				return true;
-			}
-		}
-		return false;
-	}
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class RenderRegion<V extends VertexConfig<V>> {
+
+    public final int posX;
+    public final int posZ;
+
+    public final @Nullable RenderList<V> @NotNull [] renderLists = new RenderList[2];
+
+    public RenderRegion(final int posX, final int posZ) {
+        this.posX = posX;
+        this.posZ = posZ;
+    }
+
+    @Override
+    public String toString() {
+        return "[" + this.posX + "," + this.posZ + "]";
+    }
 
-	@Override
-	public String toString() {
-		return "[" + posX + "," + posZ + "]";
-	}
-	
 }
\ No newline at end of file
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRenderPass.java b/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRenderPass.java
deleted file mode 100644
index c9e75e2ac..000000000
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRenderPass.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package net.minecraft.client.render.terrain;
-
-public class TerrainRenderPass {
-
-}
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRenderer.java b/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRenderer.java
index bfafe0bfb..cff4b9765 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/TerrainRenderer.java
@@ -5,12 +5,13 @@ import java.util.List;
 import net.minecraft.client.Minecraft;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 
 public abstract class TerrainRenderer {
 	
-	public final Minecraft mc;
+	public final @NotNull Minecraft mc;
 	
-	public TerrainRenderer(Minecraft minecraft) {
+	public TerrainRenderer(final @NotNull Minecraft minecraft) {
 		this.mc = minecraft;
 	}
 	
@@ -18,6 +19,11 @@ public abstract class TerrainRenderer {
 	
 	public abstract void renderTranslucentTerrain(float partialTicks);
 	
-	public abstract ChunkRenderer createChunkRenderer(World world, List<TileEntity> globalRenderableTileEntities, int x, int y, int z, int size);
+	public abstract @NotNull ChunkRenderer createChunkRenderer(
+		@NotNull World world,
+		@NotNull List<@NotNull TileEntity> globalRenderableTileEntities,
+		int x, int y, int z,
+		int size
+	);
 
 }
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 084b46697..1fa6d23c5 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
@@ -10,92 +10,78 @@ import net.minecraft.client.render.tessellator.TessellatorTerrainImpl;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Vector3d;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 public class TerrainRendererMultiDraw extends TerrainRenderer {
 
-    public final int VERTEX_BUFFER_INITIAL_CAPACITY = 67108864;
+    public static final int VERTEX_BUFFER_INITIAL_CAPACITY = 67108864;
 
-    public final int RENDER_LIST_INITIAL_CAPACITY = 4096;
+    public static final int RENDER_LIST_INITIAL_CAPACITY = 4096;
 
     /**
      * Exponential Region Size
      * Lower Region Size: More Draw Calls, reduced FPS
      * Higher Region Size: More Visual Artifacts
      */
-    public final int REGION_SIZE = 9;
+    public static final int REGION_SIZE = 9;
 
-    public final int MAX_RENDER_PASSES = 2;
+    public static final int MAX_RENDER_PASSES = 2;
 
-    public VertexBuffer vertexBuffer;
-    public RegionBuffer regionBuffer;
+    public final @NotNull VertexBuffer vertexBuffer;
+    public final @NotNull RegionBuffer<TessellatorTerrainImpl.TerrainVertexConfig> regionBuffer;
 
-    private VertexConfig<?> terrainVertexConfig;
+    private final @NotNull TessellatorTerrainImpl.TerrainVertexConfig vertexConfig;
 
-    int[] drawCalls = new int[this.MAX_RENDER_PASSES];
+    private final int @NotNull [] drawCalls = new int[MAX_RENDER_PASSES];
 
-    private double renderPosX;
-    private double renderPosY;
-    private double renderPosZ;
+    private final @NotNull Vector3d renderPos = new Vector3d();
+    private final @NotNull Vector3d prevSort = new Vector3d();
+    private final @NotNull Vector3d d = new Vector3d();
 
-    private double prevSortX;
-    private double prevSortY;
-    private double prevSortZ;
-
-    public TerrainRendererMultiDraw(Minecraft minecraft) {
+    public TerrainRendererMultiDraw(final @NotNull Minecraft minecraft) {
         super(minecraft);
 
-        this.vertexBuffer = new VertexBuffer(this.VERTEX_BUFFER_INITIAL_CAPACITY);
-        this.regionBuffer = new RegionBuffer(this.REGION_SIZE);
+        this.vertexConfig = new TessellatorTerrainImpl.TerrainVertexConfig();
+
+        this.vertexBuffer = new VertexBuffer(VERTEX_BUFFER_INITIAL_CAPACITY);
+        this.regionBuffer = new RegionBuffer<>(REGION_SIZE);
     }
 
     @Override
-    public void renderSolidTerrain(float partialTicks) {
+    public void renderSolidTerrain(final float partialTicks) {
         Arrays.fill(this.drawCalls, 0);
 
-        ICamera camera = this.mc.activeCamera;
-        this.renderPosX = camera.getX(partialTicks);
-        this.renderPosY = camera.getY(partialTicks);
-        this.renderPosZ = camera.getZ(partialTicks);
-
-        double dX = this.renderPosX - this.prevSortX;
-        double dY = this.renderPosY - this.prevSortY;
-        double dZ = this.renderPosZ - this.prevSortZ;
+        final @NotNull ICamera camera = Objects.requireNonNull(this.mc.activeCamera);
+        camera.getPosition(partialTicks, this.renderPos);
 
-        if (dX * dX + dY * dY + dZ * dZ > 64) {
-            this.prevSortX = this.renderPosX;
-            this.prevSortY = this.renderPosY;
-            this.prevSortZ = this.renderPosZ;
+        this.d.set(this.renderPos).sub(this.prevSort);
 
-            int x = MathHelper.floor(this.renderPosX);
-            int y = MathHelper.floor(this.renderPosY);
-            int z = MathHelper.floor(this.renderPosZ);
+        if (this.d.dot(this.d) > 64) {
+            this.prevSort.set(this.renderPos);
 
-            this.mc.renderGlobal.resortChunks(x, y, z);
+            this.mc.renderGlobal.resortChunks(
+                MathHelper.floor(this.renderPos.x),
+                MathHelper.floor(this.renderPos.y),
+                MathHelper.floor(this.renderPos.z)
+            );
         }
 
-        if (this.terrainVertexConfig == null) {
-            return;
-        }
-
-        this.terrainVertexConfig.enable(this.vertexBuffer.getVao(), this.vertexBuffer.getVbo());
+        this.vertexConfig.enable(this.vertexBuffer.getVao(), this.vertexBuffer.getVbo());
 
-        List<RenderRegion> regions = this.regionBuffer.getAllRegions();
-        for (int i = 0; i < regions.size(); i++) {
-            RenderRegion region = regions.get(i);
-            // TODO Clear empty regions, but not like this
-//			if(!region.hasRenderData()) {
-//				regionBuffer.remove(region);
-//				i--;
-//				continue;
-//			}
+        final @NotNull List<@NotNull RenderRegion<TessellatorTerrainImpl.TerrainVertexConfig>> regions = this.regionBuffer.getAllRegions();
+        for (final @NotNull RenderRegion<TessellatorTerrainImpl.TerrainVertexConfig> region : regions) {
+            // TODO: Clear empty regions
 
-            RenderList renderList = region.renderLists[0];
+            final @Nullable RenderList<?> renderList = region.renderLists[0];
             if (renderList != null && renderList.size() > 0) {
                 GLRenderer.pushFrame();
-                GLRenderer.modelM4f().translate((float) ((region.posX << this.REGION_SIZE) - this.renderPosX), (float) -this.renderPosY, (float) ((region.posZ << this.REGION_SIZE) - this.renderPosZ));
+                GLRenderer.modelM4f().translate((float) ((region.posX << REGION_SIZE) - this.renderPos.x), (float) -this.renderPos.y, (float) ((region.posZ << REGION_SIZE) - this.renderPos.z));
                 GLRenderer.globalSetUniforms(Shaders.TERRAIN);
 
                 renderList.draw();
@@ -105,17 +91,16 @@ public class TerrainRendererMultiDraw extends TerrainRenderer {
             }
         }
 
-        this.terrainVertexConfig.disable();
+        this.vertexConfig.disable();
     }
 
-    public void renderAllLists(int renderPass) {
-        List<RenderRegion> regions = this.regionBuffer.getAllRegions();
-        for (int i = 0; i < regions.size(); i++) {
-            RenderRegion region = regions.get(i);
-            RenderList renderList = region.renderLists[renderPass];
+    public void renderAllLists(final int renderPass) {
+        final @NotNull List<@NotNull RenderRegion<TessellatorTerrainImpl.TerrainVertexConfig>> regions = this.regionBuffer.getAllRegions();
+        for (final @NotNull RenderRegion<TessellatorTerrainImpl.TerrainVertexConfig> region : regions) {
+            final @Nullable RenderList<TessellatorTerrainImpl.TerrainVertexConfig> renderList = region.renderLists[renderPass];
             if (renderList != null && renderList.size() > 0) {
                 GLRenderer.pushFrame();
-                GLRenderer.modelM4f().translate((float) ((region.posX << this.REGION_SIZE) - this.renderPosX), (float) -this.renderPosY, (float) ((region.posZ << this.REGION_SIZE) - this.renderPosZ));
+                GLRenderer.modelM4f().translate((float) ((region.posX << REGION_SIZE) - this.renderPos.x), (float) -this.renderPos.y, (float) ((region.posZ << REGION_SIZE) - this.renderPos.z));
                 GLRenderer.globalSetUniforms(Shaders.TERRAIN);
 
                 renderList.draw();
@@ -127,117 +112,102 @@ public class TerrainRendererMultiDraw extends TerrainRenderer {
     }
 
     @Override
-    public void renderTranslucentTerrain(float partialTicks) {
-        if (this.terrainVertexConfig == null) {
-            return;
-        }
-
-        this.terrainVertexConfig.enable(this.vertexBuffer.getVao(), this.vertexBuffer.getVbo());
+    public void renderTranslucentTerrain(final float partialTicks) {
+        this.vertexConfig.enable(this.vertexBuffer.getVao(), this.vertexBuffer.getVbo());
 
         if (GameSettings.TRANSPARENCY_DEPTH_CHECK.value) {
             GLRenderer.setColorMask(false, false, false, false);
         }
 
-        renderAllLists(1);
+        this.renderAllLists(1);
 
         if (GameSettings.TRANSPARENCY_DEPTH_CHECK.value) {
             GLRenderer.setColorMask(true, true, true, true);
             if (this.drawCalls[1] > 0) {
-                renderAllLists(1);
+                this.renderAllLists(1);
             }
         }
 
-        this.terrainVertexConfig.disable();
+        this.vertexConfig.disable();
     }
 
-    public void chunkRendered(ChunkRendererMultiDraw chunkRenderer, TessellatorTerrainImpl tessellator, final int renderPass) {
+    public void chunkRendered(final @NotNull ChunkRendererMultiDraw chunkRenderer, final @NotNull TessellatorTerrainImpl tessellator, final int renderPass) {
         tessellator.drawing = false;
-        VertexConfig<?> config = tessellator.data.config;
-
-        if (this.terrainVertexConfig == null) {
-            this.terrainVertexConfig = config.copy();
-        } else {
-            if (!this.terrainVertexConfig.equals(tessellator.data.config)) {
-                List<RenderRegion> allRegions = this.regionBuffer.getAllRegions();
-                for (int i = 0; i < allRegions.size(); i++) {
-                    RenderRegion region = allRegions.get(i);
-                    if (region.hasRenderData()) {
-                        VertexConfigStandard.compareThrow(tessellator.data.config, this.terrainVertexConfig);
-                    }
-                    this.regionBuffer.remove(region);
-                    i--;
-                }
-
-                this.terrainVertexConfig = config.copy();
-            }
-        }
 
-        RenderList renderList = getOrCreateRenderList(chunkRenderer, renderPass);
-        Entry entry = renderList.add(tessellator.data, chunkRenderer.visible);
+        final @NotNull RenderList<TessellatorTerrainImpl.TerrainVertexConfig> renderList = this.getOrCreateRenderList(chunkRenderer, renderPass);
+        final @Nullable Entry<TessellatorTerrainImpl.TerrainVertexConfig> entry = renderList.add(tessellator.data, chunkRenderer.visible);
         chunkRenderer.renderListEntries[renderPass] = entry;
     }
 
-    public void chunkVisibilityChanged(ChunkRendererMultiDraw chunkRenderer) {
-        RenderRegion region = getRenderRegionAtBlockPos(chunkRenderer.posX, chunkRenderer.posZ);
+    public void chunkVisibilityChanged(final @NotNull ChunkRendererMultiDraw chunkRenderer) {
+        final @NotNull RenderRegion<TessellatorTerrainImpl.TerrainVertexConfig> region = this.getRenderRegionAtBlockPos(chunkRenderer.pos.x, chunkRenderer.pos.z);
 
-        for (int renderPass = 0; renderPass < this.MAX_RENDER_PASSES; renderPass++) {
-            Entry entry = chunkRenderer.renderListEntries[renderPass];
-            if (entry == null) {
-                continue;
-            }
-            RenderList renderList = region.renderLists[renderPass];
-            if (renderList == null) {
-                throw new NullPointerException("Region " + region + " does not have a render list for render pass " + renderPass + "!");
+        for (int renderPass = 0; renderPass < MAX_RENDER_PASSES; renderPass++) {
+            final @Nullable Entry<TessellatorTerrainImpl.TerrainVertexConfig> entry = chunkRenderer.renderListEntries[renderPass];
+
+            if (entry != null) {
+                final @Nullable RenderList<TessellatorTerrainImpl.TerrainVertexConfig> renderList = region.renderLists[renderPass];
+                if (renderList == null) {
+                    throw new IllegalStateException("Region " + region + " does not have a render list for render pass " + renderPass + "!");
+                }
+
+                renderList.setVisible(entry, chunkRenderer.visible);
             }
-            renderList.setVisible(entry, chunkRenderer.visible);
         }
     }
 
-    public void chunkDeleted(ChunkRendererMultiDraw chunkRenderer) {
-        RenderRegion region = getRenderRegionAtBlockPos(chunkRenderer.posX, chunkRenderer.posZ);
-        for (int renderPass = 0; renderPass < this.MAX_RENDER_PASSES; renderPass++) {
-            Entry entry = chunkRenderer.renderListEntries[renderPass];
-            if (entry == null) {
-                continue;
-            }
-            RenderList renderList = region.renderLists[renderPass];
-            if (renderList == null) {
-                throw new NullPointerException("Region " + region + " does not have a render list for render pass " + renderPass + "!");
+    public void chunkDeleted(final @NotNull ChunkRendererMultiDraw chunkRenderer) {
+        final @NotNull RenderRegion<TessellatorTerrainImpl.@NotNull TerrainVertexConfig> region = this.getRenderRegionAtBlockPos(chunkRenderer.pos.x, chunkRenderer.pos.z);
+
+        for (int renderPass = 0; renderPass < MAX_RENDER_PASSES; renderPass++) {
+            final @Nullable Entry<TessellatorTerrainImpl.@NotNull TerrainVertexConfig> entry = chunkRenderer.renderListEntries[renderPass];
+            if (entry != null) {
+                final @Nullable RenderList<TessellatorTerrainImpl.@NotNull TerrainVertexConfig> renderList = region.renderLists[renderPass];
+                if (renderList == null) {
+                    throw new IllegalStateException("Region " + region + " does not have a render list for render pass " + renderPass + "!");
+                }
+
+                renderList.remove(entry);
+                chunkRenderer.renderListEntries[renderPass] = null;
             }
-            renderList.remove(entry);
-            chunkRenderer.renderListEntries[renderPass] = null;
         }
     }
 
-    public RenderList getOrCreateRenderList(ChunkRendererMultiDraw chunkRenderer, final int renderPass) {
-        return getOrCreateRenderList(chunkRenderer.posX, chunkRenderer.posZ, renderPass);
+    public @NotNull RenderList<TessellatorTerrainImpl.@NotNull TerrainVertexConfig> getOrCreateRenderList(final @NotNull ChunkRendererMultiDraw chunkRenderer, final int renderPass) {
+        return this.getOrCreateRenderList(chunkRenderer.pos.x, chunkRenderer.pos.z, renderPass);
     }
 
-    public RenderList getOrCreateRenderList(int posX, int posZ, final int renderPass) {
-        RenderRegion region = this.regionBuffer.getRegionAtBlockPos(posX, posZ);
-        RenderList renderList = region.renderLists[renderPass];
+    public @NotNull RenderList<TessellatorTerrainImpl.@NotNull TerrainVertexConfig> getOrCreateRenderList(final int posX, final int posZ, final int renderPass) {
+        final @NotNull RenderRegion<TessellatorTerrainImpl.TerrainVertexConfig> region = this.regionBuffer.getRegionAtBlockPos(posX, posZ);
+
+        @Nullable RenderList<TessellatorTerrainImpl.TerrainVertexConfig> renderList = region.renderLists[renderPass];
         if (renderList == null) {
-            renderList = new RenderList(this.vertexBuffer, this.RENDER_LIST_INITIAL_CAPACITY);
+            renderList = new RenderList<>(this.vertexBuffer, this.vertexConfig, RENDER_LIST_INITIAL_CAPACITY);
             region.renderLists[renderPass] = renderList;
         }
+
         return renderList;
     }
 
     @Override
-    public ChunkRenderer createChunkRenderer(World world, List<TileEntity> globalRenderableTileEntities, int x, int y, int z, int size) {
+    public @NotNull ChunkRenderer createChunkRenderer(
+        final @NotNull World world,
+        final @NotNull List<@NotNull TileEntity> globalRenderableTileEntities,
+        final int x, final int y, final int z,
+        final int size
+    ) {
         return new ChunkRendererMultiDraw(this, world, globalRenderableTileEntities, x, y, z, size);
     }
 
-    public RenderRegion getRenderRegionAtBlockPos(int blockX, int blockZ) {
+    public @NotNull RenderRegion<TessellatorTerrainImpl.TerrainVertexConfig> getRenderRegionAtBlockPos(final int blockX, final int blockZ) {
         return this.regionBuffer.getRegionAtBlockPos(blockX, blockZ);
     }
 
     public int getTotalDrawCalls() {
         int totalDrawCalls = 0;
-        for (int i = 0; i < this.drawCalls.length; i++) {
-            totalDrawCalls += this.drawCalls[i];
+        for (final int drawCall : this.drawCalls) {
+            totalDrawCalls += drawCall;
         }
         return totalDrawCalls;
     }
-
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexAttribute.java b/game/client/src/main/java/net/minecraft/client/render/terrain/VertexAttribute.java
deleted file mode 100644
index 6ca70afde..000000000
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexAttribute.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package net.minecraft.client.render.terrain;
-
-import java.nio.ByteBuffer;
-
-/**
- * Can be used by mods
- */
-public abstract class VertexAttribute {
-	
-	public final String name;
-	public final int id;
-	public final int type;
-	
-	public VertexAttribute(String name, int id, int type) {
-		this.name = name;
-		this.id = id;
-		this.type = type;
-	}
-	
-	public abstract void addVertex(ByteBuffer buffer);
-	
-	public abstract int getSize();
-	
-	public abstract int getTypeSize();
-	
-	public static int compare(VertexAttribute a1, VertexAttribute a2) {
-		if(a1 == a2) {
-			return 0;
-		}
-		
-		if(!a1.name.equals(a2.name)) return 1;
-		if(a1.id != a2.id) return 2;
-		if(a1.type != a2.type) return 3;
-		if(a1.getSize() != a2.getSize()) return 4;
-		
-		return 0;
-	}
-	
-
-}
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 144115d11..de715ee04 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
@@ -4,134 +4,145 @@ import static org.lwjgl.opengl.GL41.*;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 import com.mojang.logging.CategorizedLogger;
 import com.mojang.logging.LogUtils;
 
 import net.minecraft.client.render.OpenGLHelper;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL41;
 
 /**
- * 		A large buffer that contains vertex data
- * <br> Elements can have different vertex configurations
- * <br> When the buffer is full, it will automatically expand
+ * A large buffer that contains vertex data
+ * <br>
+ * Elements can have different vertex configurations
+ * <br>
+ * When the buffer is full, it will automatically expand
  */
 public class VertexBuffer {
-	public static final CategorizedLogger LOGGER = LogUtils.getLogger();
-	private int vbo;
-	private final int vao;
-	private long capacity;
-	
-	public List<Entry> entries = new ArrayList<>();
-	
-	private int entryHashCounter;
-	
-	public VertexBuffer(long initialCapacity) {
-		this.capacity = initialCapacity;
+    private static final @NotNull CategorizedLogger LOGGER = LogUtils.getLogger();
+
+    public final @NotNull List<@NotNull Entry<?>> entries = new ArrayList<>();
+
+    private int vbo;
+    private final int vao;
+    private long capacity;
+    private int entryHashCounter;
+
+    public VertexBuffer(final long initialCapacity) {
+        this.capacity = initialCapacity;
 
         this.vbo = glGenBuffers();
         this.vao = GL41.glGenVertexArrays();
-		glBindBuffer(GL_ARRAY_BUFFER, this.vbo);
-		glBufferData(GL_ARRAY_BUFFER, this.capacity, GL_STATIC_DRAW);
-		glBindBuffer(GL_ARRAY_BUFFER, 0);
-	}
-	
-	public Entry addVertexData(VertexData vertexData) {
-		if(vertexData.vertexCount <= 0) {
-			return null;
-		}
-		
-		// If the buffer is empty, just put it at the start
-		if(this.entries.isEmpty()) {
-			return insertAtIndex(vertexData, 0);
-		}
-		
-		int bytes = vertexData.buffer.position();
-		
-		// If there is a single element in the buffer, check if there is enough space in front of it
-		// If not put it behind the other element
-		if(this.entries.size() == 1) {
-			Entry entry = this.entries.get(0);
-			if(entry.position > bytes) {
-				return insertAtIndex(vertexData, 0);
-			}else {
-				return insertAtIndex(vertexData, 1);
-			}
-		}
-		
-		// Check between every single element for a large enough gap
-		for(int i = 0; i < this.entries.size() - 1; i++) {
-			Entry entry = this.entries.get(i);
-			Entry nextEntry = this.entries.get(i + 1);
-			
-			long availableSpace = nextEntry.position - (entry.position + entry.size);
-			if(availableSpace > bytes) {
-				return insertAtIndex(vertexData, i + 1);
-			}
-		}
-		
-		// Put it all the way at the end
-		return insertAtIndex(vertexData, this.entries.size());
-	}
-	
-	private Entry insertAtIndex(VertexData vertexData, int listIndex) {
-		long pos = 0;
-		long bytes = vertexData.buffer.position();
-		
-		if(listIndex > 0) {
-			Entry prev = this.entries.get(listIndex - 1);
-			pos = prev.position + prev.size;
-		}
-		
-		if(pos + bytes >= this.capacity) {
-			expandVBO();
-		}
-		
-		Entry entry = new Entry(pos, bytes);
-		
-		if(listIndex > 0) {
-			Entry previousEntry = this.entries.get(listIndex - 1);
-			if(previousEntry.position + previousEntry.size > pos) {
-				throw new RuntimeException("Entry collision: " + entry + " and " + previousEntry);
-			}
-		}
-		if(listIndex < this.entries.size() - 1) {
-			Entry nextEntry = this.entries.get(listIndex + 1);
-			if(nextEntry.position <= pos + bytes) {
-				throw new RuntimeException("Entry collision: " + entry + " and " + nextEntry);
-			}
-		}
-		
-		vertexData.buffer.flip();
-
-		assert pos >= 0: "Entry pos must be positive!";
-		
-		glBindBuffer(GL_ARRAY_BUFFER, this.vbo);
-		glBufferSubData(GL_ARRAY_BUFFER, pos, vertexData.buffer);
-		glBindBuffer(GL_ARRAY_BUFFER, 0);
+        glBindBuffer(GL_ARRAY_BUFFER, this.vbo);
+        glBufferData(GL_ARRAY_BUFFER, this.capacity, GL_STATIC_DRAW);
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
+    }
+
+    public <V extends VertexConfig<V>> @Nullable Entry<V> addVertexData(final @NotNull VertexData<V> vertexData) {
+        if (vertexData.vertexCount <= 0) {
+            return null;
+        }
+
+        // If the buffer is empty, just put it at the start
+        if (this.entries.isEmpty()) {
+            return this.insertAtIndex(vertexData, 0);
+        }
+
+        final int bytes = vertexData.getBuffer().position();
+
+        // If there is a single element in the buffer, check if there is enough space in front of it
+        // If not put it behind the other element
+        if (this.entries.size() == 1) {
+            final @Nullable Entry<?> entry = this.entries.get(0);
+            assert entry != null;
+            if (entry.position > bytes) {
+                return this.insertAtIndex(vertexData, 0);
+            } else {
+                return this.insertAtIndex(vertexData, 1);
+            }
+        }
+
+        // Check between every single element for a large enough gap
+        for (int i = 0; i < this.entries.size() - 1; i++) {
+            final @Nullable Entry<?> entry = this.entries.get(i);
+            final @Nullable Entry<?> nextEntry = this.entries.get(i + 1);
+            assert entry != null;
+            assert nextEntry != null;
+
+            final long availableSpace = nextEntry.position - (entry.position + entry.size);
+            if (availableSpace > bytes) {
+                return this.insertAtIndex(vertexData, i + 1);
+            }
+        }
+
+        // Put it all the way at the end
+        return this.insertAtIndex(vertexData, this.entries.size());
+    }
+
+    private <V extends VertexConfig<V>> @NotNull Entry<V> insertAtIndex(final @NotNull VertexData<V> vertexData, final int listIndex) {
+        long pos = 0;
+        final long bytes = vertexData.getBuffer().position();
+
+        if (listIndex > 0) {
+            final @Nullable Entry<?> prev = this.entries.get(listIndex - 1);
+            assert prev != null;
+            pos = prev.position + prev.size;
+        }
+
+        if (pos + bytes >= this.capacity) {
+            this.expandVBO();
+        }
+
+        final @NotNull Entry<V> entry = new Entry<>(vertexData.config, pos, bytes);
+
+        if (listIndex > 0) {
+            final @Nullable Entry<?> previousEntry = this.entries.get(listIndex - 1);
+            assert previousEntry != null;
+            if (previousEntry.position + previousEntry.size > pos) {
+                throw new RuntimeException("Entry collision: " + entry + " and " + previousEntry);
+            }
+        }
+        if (listIndex < this.entries.size() - 1) {
+            final @Nullable Entry<?> nextEntry = this.entries.get(listIndex + 1);
+            assert nextEntry != null;
+            if (nextEntry.position <= pos + bytes) {
+                throw new RuntimeException("Entry collision: " + entry + " and " + nextEntry);
+            }
+        }
+
+        vertexData.getBuffer().flip();
+
+        assert pos >= 0 : "Entry pos must be positive!";
+
+        glBindBuffer(GL_ARRAY_BUFFER, this.vbo);
+        glBufferSubData(GL_ARRAY_BUFFER, pos, vertexData.getBuffer());
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
 
         this.entries.add(listIndex, entry);
-		
-		return entry;
-	}
-	
-	private void expandVBO() {
-		final long prevCapacity = this.capacity;
-		long newCapacity = this.capacity * 2L;
-		if(newCapacity < this.capacity) {
-			// future proof
-			throw new RuntimeException();
-		}
-
-		LOGGER.warn("Expand VBO Buffer: " + newCapacity);
-		
-		OpenGLHelper.checkError("pre expand buffer");
-		
-		int newBuffer = glGenBuffers();
-		glBindBuffer(GL_ARRAY_BUFFER, newBuffer);
-		glBufferData(GL_ARRAY_BUFFER, newCapacity, GL_STATIC_DRAW);
-		
-		OpenGLHelper.checkError("create expand buffer");
+
+        return entry;
+    }
+
+    private void expandVBO() {
+        final long prevCapacity = this.capacity;
+        final long newCapacity = this.capacity * 2L;
+        if (newCapacity < this.capacity) {
+            // future proof
+            throw new RuntimeException();
+        }
+
+        LOGGER.warn("Expand VBO Buffer: " + newCapacity);
+
+        OpenGLHelper.checkError("pre expand buffer");
+
+        final int newBuffer = glGenBuffers();
+        glBindBuffer(GL_ARRAY_BUFFER, newBuffer);
+        glBufferData(GL_ARRAY_BUFFER, newCapacity, GL_STATIC_DRAW);
+
+        OpenGLHelper.checkError("create expand buffer");
 
         glBindBuffer(GL41.GL_COPY_READ_BUFFER, this.vbo);
         glBindBuffer(GL41.GL_COPY_WRITE_BUFFER, newBuffer);
@@ -142,52 +153,54 @@ public class VertexBuffer {
         glBindBuffer(GL41.GL_COPY_WRITE_BUFFER, 0);
 
         OpenGLHelper.checkError("copy buffer");
-		
-		this.capacity = newCapacity;
-		this.vbo = newBuffer;
-	}
-	
-	public boolean removeEntry(Entry entry) {
-		return this.entries.remove(entry);
-	}
-	
-	public int getVbo() {
-		return this.vbo;
-	}
-
-	public int getVao() {
-		return this.vao;
-	}
-	
-	public int entryCount() {
-		return this.entries.size();
-	}
-	
-	/**
-	 * A reference to some vertex data that has been stored in this buffer
-	 */
-	public class Entry {
-		
-		public final long position;
-		public final long size;
-		
-		private final int hashCode = VertexBuffer.this.entryHashCounter++;
-		
-		public Entry(long position, long size) {
-			this.position = position;
-			this.size = size;
-		}
-		
-		@Override
-		public String toString() {
-			return "VertexBufferEntry[position: " + this.position + ", size: " + this.size + "]";
-		}
-		
-		@Override
-		public int hashCode() {
-			return this.hashCode;
-		}
-		
-	}
+
+        this.capacity = newCapacity;
+        this.vbo = newBuffer;
+    }
+
+    public void removeEntry(final Entry<?> entry) {
+        this.entries.remove(entry);
+    }
+
+    public int getVbo() {
+        return this.vbo;
+    }
+
+    public int getVao() {
+        return this.vao;
+    }
+
+    public int entryCount() {
+        return this.entries.size();
+    }
+
+    /**
+     * A reference to some vertex data that has been stored in this buffer
+     */
+    public class Entry<V extends VertexConfig<V>> {
+
+        public final long position;
+        public final long size;
+        public final @NotNull V config;
+
+        private final int hashCode = VertexBuffer.this.entryHashCounter++;
+
+        public Entry(final @NotNull V config, final long position, final long size) {
+            this.config = config;
+            this.position = position;
+            this.size = size;
+        }
+
+        @Override
+        public String toString() {
+            return "VertexBufferEntry[position: " + this.position + ", size: " + this.size + "]";
+        }
+
+        @Override
+        public int hashCode() {
+            return this.hashCode;
+        }
+
+    }
 
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexConfig.java b/game/client/src/main/java/net/minecraft/client/render/terrain/VertexConfig.java
index da09d570e..d00009c7c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexConfig.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/VertexConfig.java
@@ -4,9 +4,13 @@ import net.minecraft.client.render.renderer.DrawMode;
 import org.jetbrains.annotations.NotNull;
 
 public interface VertexConfig<T extends VertexConfig<T>> {
-    @NotNull DrawMode drawmode();
+    @NotNull DrawMode drawMode();
+
     void enable(int vao, int vbo);
+
     void disable();
+
     int getVertexSize();
+
     @NotNull T copy();
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexConfigStandard.java b/game/client/src/main/java/net/minecraft/client/render/terrain/VertexConfigStandard.java
deleted file mode 100644
index 2b514974c..000000000
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexConfigStandard.java
+++ /dev/null
@@ -1,189 +0,0 @@
-package net.minecraft.client.render.terrain;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.b100.json.element.JsonObject;
-import net.minecraft.client.render.renderer.DrawMode;
-import net.minecraft.client.render.renderer.GLRenderer;
-import net.minecraft.client.render.tessellator.Tessellator;
-import org.jetbrains.annotations.NotNull;
-import org.lwjgl.opengl.GL41;
-
-public class VertexConfigStandard implements VertexConfig<VertexConfigStandard> {
-	
-	public @NotNull DrawMode drawMode = Tessellator.QUAD_EMULATION ? DrawMode.TRIANGLES : DrawMode.QUADS;
-	public boolean enableColor = false;
-	public boolean enableTexture = false;
-	public boolean enableNormal = false;
-	public boolean enableLightmap = false;
-	public final List<VertexAttribute> attributes = new ArrayList<>();
-
-	@Override
-	public @NotNull DrawMode drawmode() {
-		return this.drawMode;
-	}
-
-	public void enable(int vao, int vbo) {
-		GL41.glBindVertexArray(vao);
-		GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
-		
-		int vertexSize = getVertexSize();
-		int offset = 0;
-		GL41.glVertexAttribPointer(0, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES;    // Pos
-		GL41.glEnableVertexAttribArray(0);
-		if (this.enableColor) {
-			GL41.glVertexAttribPointer(1, 4, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 4;    // Color
-			GL41.glEnableVertexAttribArray(1);
-		} else {
-			GL41.glVertexAttrib4f(1, 1f, 1f, 1f, 1f);
-		}
-		if (this.enableTexture) {
-			GL41.glVertexAttribPointer(2, 2, GL41.GL_FLOAT, false, vertexSize, offset); offset += 2 * Float.BYTES;    // UV
-			GL41.glEnableVertexAttribArray(2);
-		}
-		if (this.enableLightmap) {
-			GL41.glVertexAttribPointer(3, 2, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 2;    // Lightmap
-			GL41.glEnableVertexAttribArray(3);
-		} else {
-			GL41.glVertexAttrib2f(3, GLRenderer.getLightmapBlock(), GLRenderer.getLightmapSky());
-		}
-		if (this.enableNormal) {
-			GL41.glVertexAttribPointer(4, 3, GL41.GL_BYTE, true, vertexSize, offset); offset += 3;    // Normal
-			GL41.glEnableVertexAttribArray(4);
-		} else {
-			GL41.glVertexAttrib3f(4, 0, -1, 0);
-		}
-		
-		for(int i = 0; i < this.attributes.size(); i++) {
-			VertexAttribute attrib = this.attributes.get(i);
-			
-			GL41.glEnableVertexAttribArray(attrib.id);
-			GL41.glVertexAttribPointer(attrib.id, attrib.getSize(), attrib.type, false, vertexSize, offset);
-			offset += attrib.getTypeSize();
-		}
-	}
-	
-	public void disable() {
-		GL41.glDisableVertexAttribArray(0);
-		GL41.glDisableVertexAttribArray(1);
-		GL41.glDisableVertexAttribArray(2);
-		GL41.glDisableVertexAttribArray(3);
-		GL41.glDisableVertexAttribArray(4);
-
-		for(int i = 0; i < this.attributes.size(); i++) {
-			VertexAttribute attrib = this.attributes.get(i);
-			GL41.glDisableVertexAttribArray(attrib.id);
-		}
-		GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, 0);
-		GL41.glBindVertexArray(0);
-	}
-	
-	public int getVertexSize() {
-		int size = Float.BYTES * 3;
-		
-		if(this.enableColor) {
-			size += 4;
-		}
-		if(this.enableTexture) {
-			size += Float.BYTES * 2;
-		}
-		if(this.enableNormal) {
-			size += 3;
-		}
-		if(this.enableLightmap) {
-			size += 2;
-		}
-		
-		for(int i = 0; i < this.attributes.size(); i++) {
-			size += this.attributes.get(i).getTypeSize();
-		}
-		
-		return size;
-	}
-	
-	public @NotNull VertexConfigStandard copy() {
-		VertexConfigStandard copy = new VertexConfigStandard();
-		copy.drawMode = this.drawMode;
-		copy.enableColor = this.enableColor;
-		copy.enableTexture = this.enableTexture;
-		copy.enableNormal = this.enableNormal;
-		copy.enableLightmap = this.enableLightmap;
-		copy.attributes.addAll(this.attributes);
-		return copy;
-	}
-	
-	@Override
-	public boolean equals(Object obj) {
-		if(obj instanceof VertexConfigStandard) {
-			return compare(this, (VertexConfigStandard) obj) == 0;
-		}
-		return false;
-	}
-	
-	/**
-	 * Only used for debugging
-	 */
-	public JsonObject toJson() {
-		JsonObject object = new JsonObject();
-		object.set("drawMode", this.drawMode.name());
-		object.set("enableColor", this.enableColor);
-		object.set("enableTexcoord", this.enableTexture);
-		object.set("enableNormal", this.enableNormal);
-		object.set("enableLightmap", this.enableLightmap);
-		if(!this.attributes.isEmpty()) {
-			JsonObject attribsJson = new JsonObject();
-			
-			attribsJson.set("size", this.attributes.size());
-			
-			for(int i = 0; i < this.attributes.size(); i++) {
-				VertexAttribute attribute = this.attributes.get(i);
-				JsonObject attribObject = new JsonObject();
-				
-				attribObject.set("id", attribute.id);
-				attribObject.set("type", attribute.type);
-				
-				attribsJson.set(attribute.name, attribObject);
-			}
-			
-			object.set("attribs", attribsJson);
-		}
-		return object;
-	}
-
-	public static int compare(VertexConfigStandard c1, VertexConfigStandard c2) {
-		if(c1.drawMode != c2.drawMode) return 1;
-		if(c1.enableColor != c2.enableColor) return 2;
-		if(c1.enableTexture != c2.enableTexture) return 3;
-		if(c1.enableNormal != c2.enableNormal) return 4;
-		if(c1.enableLightmap != c2.enableLightmap) return 4;
-
-		if(c1.attributes.size() != c2.attributes.size()) {
-			return 5;
-		}
-
-		for(int i=0; i < c1.attributes.size(); i++) {
-			VertexAttribute attrib1 = c1.attributes.get(i);
-			VertexAttribute attrib2 = c2.attributes.get(i);
-			int compare = VertexAttribute.compare(attrib1, attrib2);
-			if(compare != 0) {
-				return (6 + i) * 1000 + compare;
-			}
-		}
-
-		return 0;
-	}
-
-	public static void compareThrow(VertexConfig<?> config1, VertexConfig<?> config2) {
-		if(!config1.equals(config2)) {
-			System.err.println("VertexConfig Mismatch:\n" + config1 + "\n!=\n" + config2);
-			throw new RuntimeException("VertexConfig mismatch " + config1 + " " + config2 + "!");
-		}
-	}
-
-	@Override
-	public String toString() {
-		return toJson().toString();
-	}
-
-}
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexData.java b/game/client/src/main/java/net/minecraft/client/render/terrain/VertexData.java
index aa1c5408c..00f0aa277 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/VertexData.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/VertexData.java
@@ -2,18 +2,40 @@ package net.minecraft.client.render.terrain;
 
 import java.nio.ByteBuffer;
 
+import com.mojang.logging.LogUtils;
 import net.minecraft.client.util.helper.Buffer;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.BufferUtils;
+import org.slf4j.Logger;
 
-public class VertexData {
+public class VertexData<V extends VertexConfig<V>> {
+    private static final Logger LOGGER = LogUtils.getLogger();
 
-    public ByteBuffer buffer;
-
-    public VertexConfig<?> config = new VertexConfigStandard();
+    public final @NotNull V config;
 
     public int vertexCount;
 
-    public VertexData(int size) {
+    private @NotNull ByteBuffer buffer;
+
+    public VertexData(final @NotNull V config, final int size) {
+        this.config = config;
         this.buffer = BufferUtils.createByteBuffer(size);
     }
+
+    public @NotNull ByteBuffer getBuffer() {
+        return this.buffer;
+    }
+
+    public void resizeIfNeeded(final int size) {
+        if (this.buffer.capacity() < this.buffer.position() + size) {
+            final int newSize = this.buffer.capacity() * 2;
+
+            LOGGER.info("Expanding {} Buffer ({} -> {})", this.getClass().getSimpleName(), this.buffer.capacity(), newSize);
+
+            final @NotNull ByteBuffer newBuffer = BufferUtils.createByteBuffer(newSize);
+            this.buffer.flip();
+            newBuffer.put(this.buffer);
+            this.buffer = newBuffer;
+        }
+    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java
index 7f5c3215a..a8ca6f9b0 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java
@@ -3,13 +3,13 @@ package net.minecraft.client.render.tessellator;
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.render.renderer.DrawMode;
 import net.minecraft.client.render.renderer.GLRenderer;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import org.jetbrains.annotations.NotNull;
 import org.lwjgl.BufferUtils;
 import org.lwjgl.opengl.GL41;
 import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
-import java.util.Arrays;
 
 public class TessellatorFont {
     private static final Logger LOGGER = LogUtils.getLogger();
@@ -42,7 +42,7 @@ public class TessellatorFont {
         GL41.glVertexAttribPointer(3, 4, GL41.GL_UNSIGNED_BYTE, true,   vertSize, offset); offset += 4;               // Color
         GL41.glVertexAttribPointer(4, 2, GL41.GL_UNSIGNED_BYTE, false,   vertSize, offset); offset += 2; // UV
         GL41.glVertexAttribPointer(5, 2, GL41.GL_UNSIGNED_BYTE, false,   vertSize, offset); offset += 2; // UV Sizes
-        GL41.glVertexAttrib2f(6, 15.5f/16f, 15.5f/16f);
+        GL41.glVertexAttrib1f(6, LightIndexHelper.lightIndex2i(15, 15));
 
         GL41.glEnableVertexAttribArray(0);
         GL41.glEnableVertexAttribArray(1);
@@ -100,7 +100,7 @@ public class TessellatorFont {
         GL41.glBindVertexArray(this.vao);
         GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vbo);
 
-        GL41.glVertexAttrib2f(6, GLRenderer.getLightmapBlock(), GLRenderer.getLightmapSky());
+        GL41.glVertexAttrib1f(6, GLRenderer.getLightIndex());
         GL41.glBufferData(GL41.GL_ARRAY_BUFFER, this.data.flip(), GL41.GL_STREAM_DRAW);
 
         GL41.glDrawArrays(DrawMode.POINTS.cap, 0, this.vertexCount);
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorGeneral.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorGeneral.java
index 2820b27fc..4b8806628 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorGeneral.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorGeneral.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.tessellator;
 
 public interface TessellatorGeneral extends TessellatorColor, TessellatorTextured, TessellatorLightmap, TessellatorNormal, Tessellator {
-
-
+    void setShade1i(int shade);
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLOD.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLOD.java
new file mode 100644
index 000000000..fc9788587
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLOD.java
@@ -0,0 +1,17 @@
+package net.minecraft.client.render.tessellator;
+
+public interface TessellatorLOD {
+    void startDrawingLOD();
+
+    boolean addLOD(
+        double x, double y, double z,
+        float r, float g, float b,
+        boolean minX, boolean maxX,
+        boolean minY, boolean maxY,
+        boolean minZ, boolean maxZ
+    );
+
+    void setTranslation(double x, double y, double z);
+
+    void offsetTranslation(double x, double y, double z);
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLODShader.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLODShader.java
new file mode 100644
index 000000000..4d2375017
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLODShader.java
@@ -0,0 +1,159 @@
+package net.minecraft.client.render.tessellator;
+
+import com.mojang.logging.LogUtils;
+import net.minecraft.client.render.renderer.DrawMode;
+import net.minecraft.client.render.renderer.GLRenderer;
+import net.minecraft.client.render.terrain.VertexConfig;
+import net.minecraft.client.render.terrain.VertexData;
+import org.jetbrains.annotations.NotNull;
+import org.joml.Vector3d;
+import org.lwjgl.BufferUtils;
+import org.lwjgl.opengl.GL41;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class TessellatorLODShader implements TessellatorLOD {
+    private static final Logger LOGGER = LogUtils.getLogger();
+    public @NotNull LODVertexData data;
+    public boolean drawing = false;
+
+    private final @NotNull Vector3d offset = new Vector3d();
+
+    public TessellatorLODShader(final int size) {
+        this.data = new LODVertexData(size);
+    }
+
+    private void checkIsDrawing() {
+        if(!this.drawing) {
+            throw new IllegalStateException("Not drawing!");
+        }
+    }
+
+    @Override
+    public void startDrawingLOD() {
+        if (this.drawing) {
+            throw new IllegalStateException("Already drawing!");
+        }
+
+        this.drawing = true;
+        this.data.vertexCount = 0;
+
+//        this.data.getBuffer().clear();
+    }
+
+    private static final int MASK_BOTTOM = 0b0000_0001;
+    private static final int MASK_TOP = 0b0000_0010;
+    private static final int MASK_NORTH = 0b0000_0100;
+    private static final int MASK_SOUTH = 0b0000_1000;
+    private static final int MASK_WEST = 0b0001_0000;
+    private static final int MASK_EAST = 0b0010_0000;
+
+    @Override
+    public boolean addLOD(
+        final double x, final double y, final double z,
+        final float r, final float g, final float b,
+        final boolean minX, final boolean maxX,
+        final boolean minY, final boolean maxY,
+        final boolean minZ, final boolean maxZ
+    ) {
+        this.checkIsDrawing();
+
+        if (!minX && !minY && !minZ && !maxX && !maxY && !maxZ) {
+            return false;
+        }
+
+//        this.data.resizeIfNeeded(64);
+//
+//        final @NotNull ByteBuffer buffer = this.data.getBuffer();
+//
+//        final int faces =
+//            (minY ? MASK_BOTTOM : 0) |
+//            (maxY ? MASK_TOP : 0) |
+//            (minZ ? MASK_NORTH : 0) |
+//            (maxZ ? MASK_SOUTH : 0) |
+//            (minX ? MASK_WEST : 0) |
+//            (maxX ? MASK_EAST : 0);
+//        final int color =
+//            ((((int) (r * 255.0f)) & 0xFF) << 0) |
+//            ((((int) (g * 255.0f)) & 0xFF) << 8) |
+//            ((((int) (b * 255.0f)) & 0xFF) << 16);
+//
+//        buffer.putFloat((float) (x + this.offset.x)).putFloat((float) (y + this.offset.y)).putFloat((float) (z + this.offset.z)); // Pos
+//        buffer.putFloat(r).putFloat(g).putFloat(b);
+//        buffer.putInt(faces); // Packed color + face culls
+//
+//        this.data.vertexCount++;
+
+        return true;
+    }
+
+    @Override
+    public void setTranslation(final double x, final double y, final double z) {
+        this.offset.x = x;
+        this.offset.y = y;
+        this.offset.z = z;
+    }
+
+    @Override
+    public void offsetTranslation(final double x, final double y, final double z) {
+        this.offset.x += x;
+        this.offset.y += y;
+        this.offset.z += z;
+    }
+
+    public static class LODVertexData extends VertexData<LODVertexConfig> {
+        public LODVertexData(final int size) {
+            super(new LODVertexConfig(), size);
+        }
+    }
+
+    public static class LODVertexConfig implements VertexConfig<LODVertexConfig> {
+        @Override
+        public @NotNull DrawMode drawMode() {
+            return DrawMode.POINTS;
+        }
+
+        @Override
+        public void enable(final int vao, final int vbo) {
+            GL41.glBindVertexArray(vao);
+            GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
+
+            int offset = 0;
+            final int vertexSize = (Float.BYTES * 3) + (Float.BYTES * 3) + Integer.BYTES;
+            GL41.glVertexAttribPointer(0, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES;      // Pos
+            GL41.glVertexAttribPointer(1, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES;      // Pos
+            GL41.glVertexAttribPointer(2, 1, GL41.GL_UNSIGNED_INT, false, vertexSize, offset); offset += Integer.BYTES; // face culls
+
+            GL41.glEnableVertexAttribArray(0);
+            GL41.glEnableVertexAttribArray(1);
+            GL41.glEnableVertexAttribArray(2);
+        }
+
+        @Override
+        public void disable() {
+            GL41.glDisableVertexAttribArray(0);
+            GL41.glDisableVertexAttribArray(1);
+            GL41.glDisableVertexAttribArray(2);
+
+            GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, 0);
+            GL41.glBindVertexArray(0);
+        }
+
+        @Override
+        public int getVertexSize() {
+            return (Float.BYTES * 3) + (Float.BYTES * 3) + Integer.BYTES;
+        }
+
+        @Override
+        public @NotNull LODVertexConfig copy() {
+            return this;
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            return obj instanceof LODVertexConfig;
+        }
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLightmap.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLightmap.java
index 10f74ccaa..c90b61afa 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLightmap.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorLightmap.java
@@ -1,10 +1,10 @@
 package net.minecraft.client.render.tessellator;
 
-import net.minecraft.client.render.LightmapHelper;
+import net.minecraft.core.util.helper.LightIndexHelper;
 
 public interface TessellatorLightmap extends Tessellator{
-    void setLightmapCoord1i(int lightmapCoord);
+    void setLightmapCoord1i(int lightIndex);
     default void setLightmapCoord2i(int blockLight, int skyLight) {
-        setLightmapCoord1i(LightmapHelper.getLightmapCoord(skyLight, blockLight));
+        setLightmapCoord1i(LightIndexHelper.lightIndex2i(skyLight, blockLight));
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticle.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticle.java
index 47c24ffe1..a1175d945 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticle.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticle.java
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
 public interface TessellatorParticle {
 
     void startDrawingParticles();
-    void setLightmapCoord1i(int lightmapCoord);
+    void setLightmapCoord1i(int lightIndex);
     void setColorOpaque3f(float r, float g, float b);
     void setColor4f(float r, float g, float b, float a);
     void setColorOpaque3i(int r, int g, int b);
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticleShader.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticleShader.java
index e75ac25cb..1f5dd4dba 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticleShader.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticleShader.java
@@ -1,10 +1,10 @@
 package net.minecraft.client.render.tessellator;
 
 import com.mojang.logging.LogUtils;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.camera.ICamera;
 import net.minecraft.client.render.renderer.DrawMode;
 import net.minecraft.client.render.renderer.GLRenderer;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.lwjgl.BufferUtils;
@@ -24,7 +24,7 @@ public class TessellatorParticleShader implements TessellatorParticle {
     private final int vbo;
 
     private int color;
-    private int lightmapCoord;
+    private byte lightIndex;
 
     private double offsetX;
     private double offsetY;
@@ -39,13 +39,13 @@ public class TessellatorParticleShader implements TessellatorParticle {
         GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vbo);
 
         int offset = 0;
-        int vertexSize = 38;
+        int vertexSize = 37;
         GL41.glVertexAttribPointer(0, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES;    // Pos
         GL41.glVertexAttribPointer(1, 1, GL41.GL_FLOAT, false, vertexSize, offset); offset += Float.BYTES;        // Scale
         GL41.glVertexAttribPointer(2, 4, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset);  offset += 4;          // Color
         GL41.glVertexAttribPointer(3, 2, GL41.GL_FLOAT, false, vertexSize, offset); offset += 2 * Float.BYTES;    // UV
         GL41.glVertexAttribPointer(4, 2, GL41.GL_FLOAT, false, vertexSize, offset); offset += 2 * Float.BYTES;    // UVSizes
-        GL41.glVertexAttribPointer(5, 2, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 2;           // Lightmap
+        GL41.glVertexAttribPointer(5, 1, GL41.GL_UNSIGNED_BYTE, false, vertexSize, offset); offset += 1;           // Lightmap
 
         GL41.glEnableVertexAttribArray(0);
         GL41.glEnableVertexAttribArray(1);
@@ -64,15 +64,15 @@ public class TessellatorParticleShader implements TessellatorParticle {
         }
         this.drawing = true;
         this.color = 0xFFFFFFFF;
-        this.lightmapCoord = LightmapHelper.getLightmapCoord(15, 15);
+        this.lightIndex = LightIndexHelper.lightIndex2i(15, 15);
         this.count = 0;
         this.buffer.clear();
     }
 
-    public void setLightmapCoord1i(int lightmapCoord) {
+    public void setLightmapCoord1i(int lightIndex) {
         checkIsDrawing();
 
-        this.lightmapCoord = lightmapCoord;
+        this.lightIndex = (byte) lightIndex;
     }
 
     public void addParticle(double x, double y, double z, float scale, double u, double v, double uSize, double vSize) {
@@ -92,7 +92,7 @@ public class TessellatorParticleShader implements TessellatorParticle {
         this.buffer.putInt(this.color);
         this.buffer.putFloat((float) u).putFloat((float) v);
         this.buffer.putFloat((float) uSize).putFloat((float) vSize);
-        this.buffer.put((byte) ((LightmapHelper.getBlockLightFromCoord(this.lightmapCoord) << 4) + 7)).put((byte) ((LightmapHelper.getSkyLightFromCoord(this.lightmapCoord) << 4) + 7));
+        this.buffer.put(this.lightIndex);
 
 
         this.count++;
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorShader.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorShader.java
index a345f7fea..3b69f3879 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorShader.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorShader.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.tessellator;
 
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.renderer.DrawMode;
 import net.minecraft.client.render.renderer.GLRenderer;
 import org.jetbrains.annotations.NotNull;
@@ -17,7 +16,8 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
     public byte config = 0;
 
     private int color;
-    private int lightmap;
+    private byte lightIndex;
+    private byte shade;
 
     private float texU;
     private float texV;
@@ -52,6 +52,7 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
         super.startDrawing(drawMode);
 
         this.lockColor = false;
+        this.shade = (byte) 0xFF;
         this.config = 0;
 
         this.quadEmulation = drawMode == DrawMode.QUADS && Tessellator.QUAD_EMULATION;
@@ -71,7 +72,15 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
         this.data.putFloat((float) (this.offsetZ + z));
 
         if((this.config & MASK_ENABLE_COLOR) != 0) {
-            this.data.putInt(this.color);
+            byte a = (byte) ((this.color & 0xFF000000) >> 24);
+            byte b = (byte) ((this.color & 0xFF0000) >> 16);
+            byte g = (byte) ((this.color & 0xFF00) >> 8);
+            byte r = (byte) ((this.color & 0xFF));
+            this.data
+                .put((byte) ((r * Byte.toUnsignedInt(this.shade)) >> 8))
+                .put((byte) ((g * Byte.toUnsignedInt(this.shade)) >> 8))
+                .put((byte) ((b * Byte.toUnsignedInt(this.shade)) >> 8))
+                .put(a);
         }
 
         if((this.config & MASK_ENABLE_TEXTURE) != 0) {
@@ -80,8 +89,7 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
         }
 
         if((this.config & MASK_ENABLE_LIGHTMAP) != 0) {
-            this.data.put((byte) ((LightmapHelper.getBlockLightFromCoord(this.lightmap) << 4) + 7));
-            this.data.put((byte) ((LightmapHelper.getSkyLightFromCoord(this.lightmap) << 4) + 7));
+            this.data.put(this.lightIndex);
         }
 
         if((this.config & MASK_ENABLE_NORMAL) != 0) {
@@ -151,7 +159,7 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
     }
 
     @Override
-    public void setLightmapCoord1i(int lightmapCoord) {
+    public void setLightmapCoord1i(int lightIndex) {
         checkIsDrawing();
         if ((this.config & MASK_ENABLE_LIGHTMAP) == 0) {
             if (this.vertexCount > 0) {
@@ -161,7 +169,7 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
             this.config |= MASK_ENABLE_LIGHTMAP;
         }
 
-        this.lightmap = lightmapCoord;
+        this.lightIndex = (byte) lightIndex;
     }
 
     @Override
@@ -224,7 +232,7 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
             size += 3;
         }
         if(lightmap) {
-            size += 2;
+            size += 1;
         }
 
         return size;
@@ -234,11 +242,11 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
         enableVertexAttribs(vao, vbo, (this.config & MASK_ENABLE_COLOR) != 0, (this.config & MASK_ENABLE_TEXTURE) != 0, (this.config & MASK_ENABLE_LIGHTMAP) != 0, (this.config & MASK_ENABLE_NORMAL) != 0);
     }
 
-    protected void enableVertexAttribs(int vao, int vbo, boolean color, boolean texture, boolean lightmap, boolean normal) {
+    protected void enableVertexAttribs(int vao, int vbo, boolean color, boolean texture, boolean lightIndex, boolean normal) {
         GL41.glBindVertexArray(vao);
         GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
 
-        int vertexSize = getVertexSize(color, texture, lightmap, normal);
+        int vertexSize = getVertexSize(color, texture, lightIndex, normal);
         int offset = 0;
         GL41.glVertexAttribPointer(0, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES;    // Pos
         GL41.glEnableVertexAttribArray(0);
@@ -256,8 +264,8 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
             GL41.glDisableVertexAttribArray(2);
         }
 
-        if (lightmap) {
-            GL41.glVertexAttribPointer(3, 2, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 2;    // Lightmap
+        if (lightIndex) {
+            GL41.glVertexAttribPointer(3, 1, GL41.GL_UNSIGNED_BYTE, false, vertexSize, offset); offset += 1;    // Lightmap
             GL41.glEnableVertexAttribArray(3);
         } else {
             GL41.glDisableVertexAttribArray(3);
@@ -271,7 +279,7 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
         }
     }
 
-    protected void enableBufferedConfig(int vao, int vbo, boolean color, boolean texture, boolean lightmap, boolean normal) {
+    protected void enableBufferedConfig(int vao, int vbo, boolean color, boolean texture, boolean lightIndex, boolean normal) {
         GL41.glBindVertexArray(vao);
         GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
 
@@ -279,12 +287,18 @@ public class TessellatorShader extends TessellatorBase implements TessellatorGen
             GL41.glVertexAttrib4f(1, 1f, 1f, 1f, 1f);
         }
 
-        if (!lightmap) {
-            GL41.glVertexAttrib2f(3, GLRenderer.getLightmapBlock(), GLRenderer.getLightmapSky());
+        if (!lightIndex) {
+            GL41.glVertexAttrib1f(3, GLRenderer.getLightIndex());
         }
 
         if (!normal) {
             GL41.glVertexAttrib3f(4, 0, -1, 0);
         }
     }
+
+    @Override
+    public void setShade1i(int shade) {
+        checkIsDrawing();
+        this.shade = (byte) shade;
+    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorTerrainImpl.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorTerrainImpl.java
index fab038112..2c72be94e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorTerrainImpl.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorTerrainImpl.java
@@ -1,254 +1,329 @@
 package net.minecraft.client.render.tessellator;
 
-import java.nio.ByteBuffer;
-
-import com.mojang.logging.LogUtils;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.renderer.DrawMode;
 import net.minecraft.client.render.terrain.VertexConfig;
 import net.minecraft.client.render.terrain.VertexData;
+import net.minecraft.core.util.helper.Color;
+import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
-import org.lwjgl.BufferUtils;
 import org.lwjgl.opengl.GL41;
-import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
 
 public class TessellatorTerrainImpl implements TessellatorGeneral {
-	private static final Logger LOGGER = LogUtils.getLogger();
-	public TerrainVertexData data;
-	public boolean drawing;
-
-	private int color;
-	private int lightmapCoord;
-	
-	private double textureU;
-	private double textureV;
-	
-	private double offsetX;
-	private double offsetY;
-	private double offsetZ;
-
-	private byte normalX;
-	private byte normalY;
-	private byte normalZ;
-
-	private boolean lockedColor = false;
-	private int quadVertCount = 0;
-	
-	public TessellatorTerrainImpl(int bufferSize) {
+    private final float[] quadPoses = new float[3 * 4];
+    private final float[] quadUVs = new float[2 * 4];
+    private final byte[] quadNormals = new byte[3 * 4];
+    private final byte[] quadLightMap = new byte[4];
+    private final byte[] quadShade = new byte[4];
+    private final int[] quadColors = new int[4];
+
+
+    public final @NotNull TerrainVertexData data;
+
+    public boolean drawing;
+
+    private int color;
+    private byte lightIndex;
+    private byte shade = (byte) 0xFF;
+
+    private double textureU;
+    private double textureV;
+
+    private double offsetX;
+    private double offsetY;
+    private double offsetZ;
+
+    private byte normalX;
+    private byte normalY;
+    private byte normalZ;
+
+    private boolean lockedColor = false;
+    private int quadVertCount = 0;
+
+    public TessellatorTerrainImpl(final int bufferSize) {
         this.data = new TerrainVertexData(bufferSize);
-	}
-	
-	@Override
-	public void startDrawing(@NotNull DrawMode drawMode) {
-		if(this.drawing) {
-			this.drawing = false;
-			throw new IllegalStateException("Already drawing!");
-		}
-
-		this.drawing = true;
+    }
+
+    @Override
+    public void startDrawing(final @NotNull DrawMode drawMode) {
+        if (this.drawing) {
+            this.drawing = false;
+            throw new IllegalStateException("Already drawing!");
+        }
+
+        this.drawing = true;
         this.data.vertexCount = 0;
-		this.quadVertCount = 0;
+        this.quadVertCount = 0;
+
+        this.setLightmapCoord2i(15, 15);
+        this.setColor4i(255, 255, 255, 255);
+        this.setTextureUV(0.0, 0.0);
+        this.setNormal(0, 1, 0);
+
+        this.lockedColor = false;
+        this.data.getBuffer().clear();
+    }
+
+    @Override
+    public void draw() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public @NotNull RenderBuffer record(final int vao, final int vbo) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addVertex(final double x, final double y, final double z) {
+        this.checkIsDrawing();
+
+        int index = this.quadVertCount % 4;
+        this.quadPoses[index * 3] = (float) (this.offsetX + x);
+        this.quadPoses[index * 3 + 1] = (float) (this.offsetY + y);
+        this.quadPoses[index * 3 + 2] = (float) (this.offsetZ + z);
+
+        this.quadColors[index] = this.color;
+
+        this.quadUVs[index * 2] = (float) this.textureU;
+        this.quadUVs[index * 2 + 1] = (float) this.textureV;
+
+        this.quadLightMap[index] = this.lightIndex;
+        this.quadShade[index] = this.shade;
+
+        this.quadNormals[index * 3] = this.normalX;
+        this.quadNormals[index * 3 + 1] = this.normalY;
+        this.quadNormals[index * 3 + 2] = this.normalZ;
+
+        this.quadVertCount++;
+
+        if (index == 3) { // Emit compressed quad
+            this.data.resizeIfNeeded(128);
+            ByteBuffer buffer = this.data.getBuffer();
+
+            float spX = this.quadPoses[0];
+            float spY = this.quadPoses[1];
+            float spZ = this.quadPoses[2];
+
+            // Average normals for quad
+            byte nX = (byte) ((this.quadNormals[0] + this.quadNormals[3] + this.quadNormals[6] + this.quadNormals[9])/4);
+            byte nY = (byte) ((this.quadNormals[1] + this.quadNormals[4] + this.quadNormals[7] + this.quadNormals[10])/4);
+            byte nZ = (byte) ((this.quadNormals[2] + this.quadNormals[5] + this.quadNormals[8] + this.quadNormals[11])/4);
 
-		setLightmapCoord1i(LightmapHelper.getLightmapCoord(15, 15));
-		setColor4i(255, 255, 255, 255);
-		setTextureUV(0.0, 0.0);
-		setNormal(0, 1, 0);
+            int color = this.quadColors[0];
 
-		this.lockedColor = false;
-        this.data.buffer.clear();
-	}
-
-	@Override
-	public void draw() {
-		throw new UnsupportedOperationException();
-	}
-
-	@Override
-	public @NotNull RenderBuffer record(int vao, int vbo) {
-		throw new UnsupportedOperationException();
-	}
-
-	@Override
-	public void addVertex(double x, double y, double z) {
-		checkIsDrawing();
-		checkCanFit(64);
-		
-		ByteBuffer buffer = this.data.buffer;
-		
-		buffer.putFloat((float) (this.offsetX + x));
-		buffer.putFloat((float) (this.offsetY + y));
-		buffer.putFloat((float) (this.offsetZ + z));
-
-        buffer.putInt(this.color);
-
-        buffer.putFloat((float) this.textureU);
-        buffer.putFloat((float) this.textureV);
-
-		buffer
-			.put((byte) ((LightmapHelper.getBlockLightFromCoord(this.lightmapCoord) << 4) + 7))
-			.put((byte) ((LightmapHelper.getSkyLightFromCoord(this.lightmapCoord) << 4) + 7));
-
-		buffer.put(this.normalX);
-		buffer.put(this.normalY);
-		buffer.put(this.normalZ);
-
-
-
-        this.data.vertexCount++;
-
-		if (Tessellator.QUAD_EMULATION && this.quadVertCount % 4 == 2) {
-			int vertSize = this.data.config.getVertexSize();
-
-			checkCanFit(128);
-			this.data.buffer.put(this.data.buffer.position(), this.data.buffer, this.data.buffer.position() - vertSize * 3, vertSize);
-			this.data.buffer.put(this.data.buffer.position() + vertSize, this.data.buffer, this.data.buffer.position() - vertSize, vertSize);
-			this.data.buffer.position(this.data.buffer.position() + vertSize * 2);
-			this.data.vertexCount += 2;
-		}
-
-		this.quadVertCount++;
-	}
-
-	public void checkCanFit(int size) {
-		if(this.data.buffer.capacity() < this.data.buffer.position() + size) {
-			int newSize = this.data.buffer.capacity() * 2;
-
-			LOGGER.info("Expanding {} Buffer ({} -> {})", "Terrain Tessellator", this.data.buffer.capacity(), newSize);
-
-			ByteBuffer newBuffer = BufferUtils.createByteBuffer(newSize);
-			this.data.buffer.flip();
-			newBuffer.put(this.data.buffer);
-			this.data.buffer = newBuffer;
-		}
-	}
-
-	@Override
-	public void setTextureUV(double u, double v) {
-		checkIsDrawing();
-
-		this.textureU = u;
-		this.textureV = v;
-	}
-
-	@Override
-	public void setLightmapCoord1i(int lightmapCoord) {
-		checkIsDrawing();
-
-		this.lightmapCoord = lightmapCoord;
-	}
-
-	@Override
-	public void setColor1i(int argb) {
-		checkIsDrawing();
-		if (this.lockedColor) {
-			return;
-		}
-
-		int a = (argb >> 24) & 0xFF;
-		int r = (argb >> 16) & 0xFF;
-		int g = (argb >> 8) & 0xFF;
-		int b = argb & 0xFF;
-
-		this.color = a << 24 | b << 16 | g << 8 | r;
-	}
-
-	@Override
-	public void lockColor() {
-		checkIsDrawing();
-		
-		this.lockedColor = true;
-	}
-
-	@Override
-	public void setTranslation(double x, double y, double z) {
-		this.offsetX = x;
-		this.offsetY = y;
-		this.offsetZ = z;
-	}
-
-	@Override
-	public void offsetTranslation(double x, double y, double z) {
-		this.offsetX += x;
-		this.offsetY += y;
-		this.offsetZ += z;
-	}
-
-	public void checkIsDrawing() {
-		if(!this.drawing) {
-			this.drawing = false;
-			throw new IllegalStateException("Not drawing!");
-		}
-	}
-
-	@Override
-	public void setNormal(float x, float y, float z) {
-		checkIsDrawing();
-
-		this.normalX = (byte) (x * 127.0f);
-		this.normalY = (byte) (y * 127.0f);
-		this.normalZ = (byte) (z * 127.0f);
-	}
-
-	public static class TerrainVertexData extends VertexData {
-
-		public TerrainVertexData(int size) {
-			super(size);
-			this.config = new TerrainVertexConfig();
-		}
-	}
-
-	public static class TerrainVertexConfig implements VertexConfig<TerrainVertexConfig> {
-
-		@Override
-		public @NotNull DrawMode drawmode() {
-			return Tessellator.QUAD_EMULATION ? DrawMode.TRIANGLES : DrawMode.QUADS;
-		}
-
-		public void enable(int vao, int vbo) {
-			GL41.glBindVertexArray(vao);
-			GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
-
-			int vertexSize = getVertexSize();
-			int offset = 0;
-			GL41.glVertexAttribPointer(0, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES;    // Pos
-            GL41.glVertexAttribPointer(1, 4, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 4;    // Color
-			GL41.glVertexAttribPointer(2, 2, GL41.GL_FLOAT, false, vertexSize, offset); offset += 2 * Float.BYTES;    // UV
-			GL41.glVertexAttribPointer(3, 2, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 2;    // Lightmap
-			GL41.glVertexAttribPointer(4, 3, GL41.GL_BYTE, true, vertexSize, offset); offset += 3;    // Normals
-
-			GL41.glEnableVertexAttribArray(0);
-			GL41.glEnableVertexAttribArray(1);
-			GL41.glEnableVertexAttribArray(2);
-			GL41.glEnableVertexAttribArray(3);
-			GL41.glEnableVertexAttribArray(4);
-		}
-
-		public void disable() {
-			GL41.glDisableVertexAttribArray(0);
-			GL41.glDisableVertexAttribArray(1);
-			GL41.glDisableVertexAttribArray(2);
-			GL41.glDisableVertexAttribArray(3);
-
-			GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, 0);
-			GL41.glBindVertexArray(0);
-		}
-
-		public int getVertexSize() {
-			int size = Float.BYTES * 3;
-            size += 4;
-            size += Float.BYTES * 2;
-            size += 2;
-            size += 3;
-			return size;
-		}
-
-		public @NotNull TerrainVertexConfig copy() {
+            buffer.putFloat(spX).putFloat(spY).putFloat(spZ);
+            buffer.put((byte) Color.blueFromInt(color)).put((byte) Color.greenFromInt(color)).put((byte) Color.redFromInt(color));
+            buffer.put(nX).put(nY).put(nZ);
+
+            buffer.putShort((short) (this.quadUVs[0] * 0xFFFF)).putShort((short) (this.quadUVs[1] * 0xFFFF));
+            buffer.put(this.quadShade[0]).put(this.quadLightMap[0]);
+
+            buffer.putShort(MathHelper.toHalfFloat(this.quadPoses[3] - spX)).putShort(MathHelper.toHalfFloat(this.quadPoses[4] - spY)).putShort(MathHelper.toHalfFloat(this.quadPoses[5] - spZ));
+            buffer.putShort((short) (this.quadUVs[2] * 0xFFFF)).putShort((short) (this.quadUVs[3] * 0xFFFF));
+            buffer.put(this.quadShade[1]).put(this.quadLightMap[1]);
+
+            buffer.putShort(MathHelper.toHalfFloat(this.quadPoses[6] - spX)).putShort(MathHelper.toHalfFloat(this.quadPoses[7] - spY)).putShort(MathHelper.toHalfFloat(this.quadPoses[8] - spZ));
+            buffer.putShort((short) (this.quadUVs[4] * 0xFFFF)).putShort((short) (this.quadUVs[5] * 0xFFFF));
+            buffer.put(this.quadShade[2]).put(this.quadLightMap[2]);
+
+            buffer.putShort(MathHelper.toHalfFloat(this.quadPoses[9] - spX)).putShort(MathHelper.toHalfFloat(this.quadPoses[10] - spY)).putShort(MathHelper.toHalfFloat(this.quadPoses[11] - spZ));
+            buffer.putShort((short) (this.quadUVs[6] * 0xFFFF)).putShort((short) (this.quadUVs[7] * 0xFFFF));
+            buffer.put(this.quadShade[3]).put(this.quadLightMap[3]);
+
+            this.data.vertexCount++;
+        }
+    }
+
+    @Override
+    public void setTextureUV(final double u, final double v) {
+        this.checkIsDrawing();
+
+        this.textureU = u;
+        this.textureV = v;
+    }
+
+    @Override
+    public void setLightmapCoord1i(final int lightIndex) {
+        this.checkIsDrawing();
+
+        this.lightIndex = (byte) lightIndex;
+    }
+
+    @Override
+    public void setColor1i(final int argb) {
+        this.checkIsDrawing();
+        if (this.lockedColor) {
+            return;
+        }
+
+        final int a = (argb >> 24) & 0xFF;
+        final int r = (argb >> 16) & 0xFF;
+        final int g = (argb >> 8) & 0xFF;
+        final int b = argb & 0xFF;
+
+        this.color = a << 24 | b << 16 | g << 8 | r;
+    }
+
+    @Override
+    public void lockColor() {
+        this.checkIsDrawing();
+
+        this.lockedColor = true;
+    }
+
+    @Override
+    public void setTranslation(final double x, final double y, final double z) {
+        this.offsetX = x;
+        this.offsetY = y;
+        this.offsetZ = z;
+    }
+
+    @Override
+    public void offsetTranslation(final double x, final double y, final double z) {
+        this.offsetX += x;
+        this.offsetY += y;
+        this.offsetZ += z;
+    }
+
+    private void checkIsDrawing() {
+        if (!this.drawing) {
+            throw new IllegalStateException("Not drawing!");
+        }
+    }
+
+    @Override
+    public void setNormal(final float x, final float y, final float z) {
+        this.checkIsDrawing();
+
+        this.normalX = (byte) (x * 127.0f);
+        this.normalY = (byte) (y * 127.0f);
+        this.normalZ = (byte) (z * 127.0f);
+    }
+
+    private int getUncompressVertexSize() {
+        int size = 0;
+        size += Float.BYTES * 3;
+        size += Byte.BYTES * 4;
+        size += Float.BYTES * 2;
+        size += Byte.BYTES;
+        size += Byte.BYTES * 3;
+        return size;
+    }
+
+    @Override
+    public void setShade1i(int shade) {
+        this.checkIsDrawing();
+        this.shade = (byte) shade;
+    }
+
+    public static class TerrainVertexData extends VertexData<TerrainVertexConfig> {
+
+        public TerrainVertexData(final int size) {
+            super(new TerrainVertexConfig(), size);
+        }
+    }
+
+    public static class TerrainVertexConfig implements VertexConfig<TerrainVertexConfig> {
+        @Override
+        public @NotNull DrawMode drawMode() {
+            return DrawMode.POINTS;
+        }
+
+        public void enable(final int vao, final int vbo) {
+            GL41.glBindVertexArray(vao);
+            GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, vbo);
+
+            final int vertexSize = this.getVertexSize();
+            int offset = 0;
+            GL41.glVertexAttribPointer(0, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES; // Source Pos
+            GL41.glVertexAttribPointer(1, 3, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 3; // Source Color
+            GL41.glVertexAttribPointer(2, 3, GL41.GL_BYTE, true, vertexSize, offset); offset += 3; // Source Normal
+
+            GL41.glVertexAttribPointer(3, 2, GL41.GL_UNSIGNED_SHORT, true, vertexSize, offset); offset += 2 * Short.BYTES; // V1 UV
+            GL41.glVertexAttribPointer(4, 2, GL41.GL_UNSIGNED_BYTE, false, vertexSize, offset); offset += 2; // V1 LightShade
+
+            GL41.glVertexAttribPointer(5, 3, GL41.GL_HALF_FLOAT, false, vertexSize, offset); offset += 3 * (Float.BYTES/2); // V2 Pos Offset
+            GL41.glVertexAttribPointer(6, 2, GL41.GL_UNSIGNED_SHORT, true, vertexSize, offset); offset += 2 * Short.BYTES; // V2 UV
+            GL41.glVertexAttribPointer(7, 2, GL41.GL_UNSIGNED_BYTE, false, vertexSize, offset); offset += 2; // V2 LightShade
+
+            GL41.glVertexAttribPointer(8, 3, GL41.GL_HALF_FLOAT, false, vertexSize, offset); offset += 3 * (Float.BYTES/2); // V3 Pos Offset
+            GL41.glVertexAttribPointer(9, 2, GL41.GL_UNSIGNED_SHORT, true, vertexSize, offset); offset += 2 * Short.BYTES; // V3 UV
+            GL41.glVertexAttribPointer(10, 2, GL41.GL_UNSIGNED_BYTE, false, vertexSize, offset); offset += 2; // V3 LightShade
+
+            GL41.glVertexAttribPointer(11, 3, GL41.GL_HALF_FLOAT, false, vertexSize, offset); offset += 3 * (Float.BYTES/2); // V4 Pos Offset
+            GL41.glVertexAttribPointer(12, 2, GL41.GL_UNSIGNED_SHORT, true, vertexSize, offset); offset += 2 * Short.BYTES; // V4 UV
+            GL41.glVertexAttribPointer(13, 2, GL41.GL_UNSIGNED_BYTE, false, vertexSize, offset); offset += 2; // V4 LightShade
+
+            assert  offset == vertexSize;
+
+            GL41.glEnableVertexAttribArray(0);
+            GL41.glEnableVertexAttribArray(1);
+            GL41.glEnableVertexAttribArray(2);
+            GL41.glEnableVertexAttribArray(3);
+            GL41.glEnableVertexAttribArray(4);
+            GL41.glEnableVertexAttribArray(5);
+            GL41.glEnableVertexAttribArray(6);
+            GL41.glEnableVertexAttribArray(7);
+            GL41.glEnableVertexAttribArray(8);
+            GL41.glEnableVertexAttribArray(9);
+            GL41.glEnableVertexAttribArray(10);
+            GL41.glEnableVertexAttribArray(11);
+            GL41.glEnableVertexAttribArray(12);
+            GL41.glEnableVertexAttribArray(13);
+        }
+
+        public void disable() {
+            GL41.glDisableVertexAttribArray(0);
+            GL41.glDisableVertexAttribArray(1);
+            GL41.glDisableVertexAttribArray(2);
+            GL41.glDisableVertexAttribArray(3);
+            GL41.glDisableVertexAttribArray(4);
+            GL41.glDisableVertexAttribArray(5);
+            GL41.glDisableVertexAttribArray(6);
+            GL41.glDisableVertexAttribArray(7);
+            GL41.glDisableVertexAttribArray(8);
+            GL41.glDisableVertexAttribArray(9);
+            GL41.glDisableVertexAttribArray(10);
+            GL41.glDisableVertexAttribArray(11);
+            GL41.glDisableVertexAttribArray(12);
+            GL41.glDisableVertexAttribArray(13);
+
+            GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, 0);
+            GL41.glBindVertexArray(0);
+        }
+
+        public int getVertexSize() {
+            int size = 0;
+            size += 3 * Float.BYTES; // Source Pos
+            size += 3; // Source Color
+            size += 3; // Source Normal
+
+            size += 2 * Short.BYTES; // V1 UV
+            size += 2; // V1 LightShade
+
+            size += 3 * (Float.BYTES/2); // V2 Pos Offset
+            size += 2 * Short.BYTES; // V2 UV
+            size += 2; // V2 LightShade
+
+            size += 3 * (Float.BYTES/2); // V3 Pos Offset
+            size += 2 * Short.BYTES; // V3 UV
+            size += 2; // V3 LightShade
+
+            size += 3 * (Float.BYTES/2); // V4 Pos Offset
+            size += 2 * Short.BYTES; // V4 UV
+            size += 2; // V4 LightShade
+            return size;
+        }
+
+        public @NotNull TerrainVertexConfig copy() {
             return this;
-		}
+        }
 
-		@Override
-		public boolean equals(Object obj) {
+        @Override
+        public boolean equals(final Object obj) {
             return obj instanceof TerrainVertexConfig;
         }
-	}
+    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/TextureRegistry.java b/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/TextureRegistry.java
index 5092ad179..10419191d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/TextureRegistry.java
+++ b/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/TextureRegistry.java
@@ -57,7 +57,7 @@ public class TextureRegistry {
             .addDirectory("block", "textures/block")
             .addDirectory("item", "textures/item")
             .addDirectory("particle", "textures/particle")
-//            .addLayer("maskColor", "cmask", 0xFFFFFFFF)
+            .addLayer("maskColor", "cmask", 0xFFFFFFFF)
             .addLayer("emissive", "emiss", 0x00000000)
     );
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMeshGold.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMeshGold.java
index 842d66d02..58c4fea60 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMeshGold.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMeshGold.java
@@ -25,7 +25,7 @@ public class TileEntityRendererMeshGold extends TileEntityRenderer<TileEntityMes
 
         ItemModelDispatcher.getInstance().getDispatch(tileEntity.filterItem).renderItemEntity(tessellator, tileEntity.filterItem,
             GameSettings.ITEMS_3D.value, 1, tileEntity.ticksRan, yaw,
-            Minecraft.getMinecraft().currentWorld.getLightmapCoord(new TilePos(tileEntity.x, tileEntity.y, tileEntity.z), 0), renderPartialTicks);
+            Minecraft.getMinecraft().currentWorld.getLightIndex(new TilePos(tileEntity.x, tileEntity.y, tileEntity.z), 0), renderPartialTicks);
         GLRenderer.popFrame();
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
index 73fac9b52..a6787c30d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
@@ -5,7 +5,6 @@ import it.unimi.dsi.fastutil.ints.IntList;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.option.enums.TextOutlineQuality;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.camera.ICamera;
 import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.font.SF;
@@ -113,7 +112,7 @@ public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign> {
         float lightOffset = 0f;
         if (tileEntity.isGlowing()) {
             lightOffset = 96f;
-            GLRenderer.setLightmapCoord1i(LightmapHelper.getLightmapCoord(15, 15));
+            GLRenderer.setLightmapCoord2i(15, 15);
         }
 
         GLRenderer.pushFrame();
diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java
index 79374338e..acddbcc65 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java
@@ -75,21 +75,21 @@ public class TileEntityRendererStatue extends TileEntityRenderer<TileEntityStatu
                 renderArmor(tessellator, armorWearer, i, pose);
             }
         }
-        renderHeldItem(heldStack, Minecraft.getMinecraft().currentWorld.getLightmapCoord(new TilePos(statue.x, statue.y, statue.z), 0), isPigman);
+        renderHeldItem(heldStack, Minecraft.getMinecraft().currentWorld.getLightIndex(new TilePos(statue.x, statue.y, statue.z), 0), isPigman);
         GLRenderer.popFrame();
 
         GLRenderer.enableState(State.CULL_FACE);
         GLRenderer.popFrame();
     }
 
-    private void renderHeldItem(final @Nullable ItemStack itemStack, int lightmap, final boolean isPigman) {
+    private void renderHeldItem(final @Nullable ItemStack itemStack, byte lightIndex, final boolean isPigman) {
         if (itemStack != null) {
             GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F);
             model(isPigman).translateToBone("rightItem");
             GLRenderer.modelM4f().scale(-1, 1, 1);
             GLRenderer.modelM4f().scale(ENTITY_RENDER_SCALE, ENTITY_RENDER_SCALE, ENTITY_RENDER_SCALE);
             ItemModelDispatcher.getInstance().getDispatch(itemStack).render(GLRenderer.getTessellator(), null, itemStack, DisplayPos.THIRD_PERSON_RIGHT_HAND, true, 1,
-               lightmap, 1f, false);
+                lightIndex, 1f, false);
             GLRenderer.enableState(State.CULL_FACE);
         }
     }
diff --git a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
index bdf321612..b61b6d726 100644
--- a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
+++ b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
@@ -156,11 +156,6 @@ public class WorldClient extends World {
         return new Vector3f(r, g, b);
     }
 
-    @Override
-    public int getLightmapCoord(int skyLight, int blockLight) {
-        return LightmapHelper.getLightmapCoord(skyLight, blockLight);
-    }
-
     @Override
     public int renderDistance() {
         return GameSettings.RENDER_DISTANCE.value;
diff --git a/game/client/src/main/java/org/useless/dragonfly/models/block/StaticBlockModel.java b/game/client/src/main/java/org/useless/dragonfly/models/block/StaticBlockModel.java
index 3186374da..b51a0106c 100644
--- a/game/client/src/main/java/org/useless/dragonfly/models/block/StaticBlockModel.java
+++ b/game/client/src/main/java/org/useless/dragonfly/models/block/StaticBlockModel.java
@@ -17,7 +17,7 @@ public interface StaticBlockModel {
     /**
      * @return True if anything rendered, false otherwise
      */
-    boolean renderStandalone(@NotNull BlockModelGeneric<? extends BlockLogic> sourceModel, @NotNull TessellatorGeneral tessellator, double x, double y, double z, int metadata, int lightmapCoord, @NotNull BlockColor color);
+    boolean renderStandalone(@NotNull BlockModelGeneric<? extends BlockLogic> sourceModel, @NotNull TessellatorGeneral tessellator, double x, double y, double z, int metadata, byte lightIndex, @NotNull BlockColor color);
 
     /**
      * @return True if anything rendered, false otherwise
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 286ceb6fe..efffcdb57 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
@@ -2,7 +2,6 @@ package org.useless.dragonfly.models.block.mojang;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.LightingCache;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.block.color.BlockColor;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.block.model.generic.BlockModelGeneric;
@@ -12,6 +11,7 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.Color;
 import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePosc;
@@ -52,14 +52,14 @@ public class StaticBlockModelMojang implements StaticBlockModel {
     }
 
     @Override
-    public boolean renderStandalone(@NotNull BlockModelGeneric<? extends BlockLogic> sourceModel, @NotNull TessellatorGeneral tessellator, double x, double y, double z, int metadata, int lightmapCoord, @NotNull BlockColor color) {
+    public boolean renderStandalone(@NotNull BlockModelGeneric<? extends BlockLogic> sourceModel, @NotNull TessellatorGeneral tessellator, double x, double y, double z, int metadata, byte lightIndex, @NotNull BlockColor color) {
         if (this.compiled.elements.length == 0) return false;
 
         tessellator.startDrawingQuads();
         for (int i = 0; i < this.compiled.elements.length; i++) {
             C_Element element = this.compiled.elements[i];
 
-            tessellator.setLightmapCoord1i(lightmapCoord);
+            tessellator.setLightmapCoord1i(lightIndex);
             for (int face = 0; face < element.faces; face++) {
                 IconCoordinate coordinate = element.textures[face];
 
@@ -255,10 +255,10 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 final int dirY = element.flip ? -direction.getOffsetY() : direction.getOffsetY();
                 final int dirZ = element.flip ? -direction.getOffsetZ() : direction.getOffsetZ();
 
-                final int lightmapCoordTopLeft;
-                final int lightmapCoordBottomLeft;
-                final int lightmapCoordBottomRight;
-                final int lightmapCoordTopRight;
+                final byte lightIndexTopLeft;
+                final byte lightIndexBottomLeft;
+                final byte lightIndexBottomRight;
+                final byte lightIndexTopRight;
 
                 LIGHTING_CACHE.setupCache(sourceModel.block, worldSource, blockPos);
 
@@ -286,30 +286,30 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                     final boolean botLefT = LIGHTING_CACHE.getOpacity(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ);
                     final boolean botRigT = LIGHTING_CACHE.getOpacity(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ);
 
-                    final int lmcCen = getLightmap(dirX2, dirY2, dirZ2, element.lightEmission);
+                    final byte lmcCen = getLightIndex(dirX2, dirY2, dirZ2, element.lightEmission);
 
-                    final int lmcTop = topT ? lmcCen : getLightmap(dirX2 + topX, dirY2 + topY, dirZ2 + topZ, element.lightEmission);
-                    final int lmcBot = botT ? lmcCen : getLightmap(dirX2 - topX, dirY2 - topY, dirZ2 - topZ, element.lightEmission);
-                    final int lmcLef = lefT ? lmcCen : getLightmap(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ, element.lightEmission);
-                    final int lmcRig = rigT ? lmcCen : getLightmap(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ, element.lightEmission);
+                    final byte lmcTop = topT ? lmcCen : getLightIndex(dirX2 + topX, dirY2 + topY, dirZ2 + topZ, element.lightEmission);
+                    final byte lmcBot = botT ? lmcCen : getLightIndex(dirX2 - topX, dirY2 - topY, dirZ2 - topZ, element.lightEmission);
+                    final byte lmcLef = lefT ? lmcCen : getLightIndex(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ, element.lightEmission);
+                    final byte lmcRig = rigT ? lmcCen : getLightIndex(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ, element.lightEmission);
 
-                    final int lmcTopLef = topT && lefT ? lmcLef : (topLefT ? lmcCen : getLightmap(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ, element.lightEmission));
-                    final int lmcBotLef = botT && lefT ? lmcLef : (botLefT ? lmcCen : getLightmap(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ, element.lightEmission));
-                    final int lmcTopRig = topT && rigT ? lmcRig : (topRigT ? lmcCen : getLightmap(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ, element.lightEmission));
-                    final int lmcBotRig = botT && rigT ? lmcRig : (botRigT ? lmcCen : getLightmap(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ, element.lightEmission));
+                    final byte lmcTopLef = topT && lefT ? lmcLef : (topLefT ? lmcCen : getLightIndex(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ, element.lightEmission));
+                    final byte lmcBotLef = botT && lefT ? lmcLef : (botLefT ? lmcCen : getLightIndex(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ, element.lightEmission));
+                    final byte lmcTopRig = topT && rigT ? lmcRig : (topRigT ? lmcCen : getLightIndex(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ, element.lightEmission));
+                    final byte lmcBotRig = botT && rigT ? lmcRig : (botRigT ? lmcCen : getLightIndex(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ, element.lightEmission));
 
-                    lightmapCoordTopLeft = LightmapHelper.avg(lmcCen, lmcLef, lmcTop, lmcTopLef);
-                    lightmapCoordTopRight = LightmapHelper.avg(lmcCen, lmcRig, lmcTop, lmcTopRig);
-                    lightmapCoordBottomLeft = LightmapHelper.avg(lmcCen, lmcLef, lmcBot, lmcBotLef);
-                    lightmapCoordBottomRight = LightmapHelper.avg(lmcCen, lmcRig, lmcBot, lmcBotRig);
+                    lightIndexTopLeft = LightIndexHelper.avg(lmcCen, lmcLef, lmcTop, lmcTopLef);
+                    lightIndexTopRight = LightIndexHelper.avg(lmcCen, lmcRig, lmcTop, lmcTopRig);
+                    lightIndexBottomLeft = LightIndexHelper.avg(lmcCen, lmcLef, lmcBot, lmcBotLef);
+                    lightIndexBottomRight = LightIndexHelper.avg(lmcCen, lmcRig, lmcBot, lmcBotRig);
                 } else {
-                    final int lmc;
+                    final byte lmc;
                     if (!isFullCube) {
-                        lmc = getLightmap(0, 0, 0, element.lightEmission);
+                        lmc = getLightIndex(0, 0, 0, element.lightEmission);
                     } else {
-                        lmc = getLightmap(dirX, dirY, dirZ, element.lightEmission);
+                        lmc = getLightIndex(dirX, dirY, dirZ, element.lightEmission);
                     }
-                    lightmapCoordTopLeft = lightmapCoordBottomLeft = lightmapCoordBottomRight = lightmapCoordTopRight = lmc;
+                    lightIndexTopLeft = lightIndexBottomLeft = lightIndexBottomRight = lightIndexTopRight = lmc;
                 }
 
                 float lightTR;
@@ -396,21 +396,6 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 final float lbl = lefP * bl + (1 - lefP) * br;
                 final float lbr = rigP * bl + (1 - rigP) * br;
                 final float ltr = rigP * tl + (1 - rigP) * tr;
-                colorRedTopLeft *= ltl;
-                colorGreenTopLeft *= ltl;
-                colorBlueTopLeft *= ltl;
-
-                colorRedBottomLeft *= lbl;
-                colorGreenBottomLeft *= lbl;
-                colorBlueBottomLeft *= lbl;
-
-                colorRedBottomRight *= lbr;
-                colorGreenBottomRight *= lbr;
-                colorBlueBottomRight *= lbr;
-
-                colorRedTopRight *= ltr;
-                colorGreenTopRight *= ltr;
-                colorBlueTopRight *= ltr;
 
                 final int offset = face * 4;
 
@@ -436,7 +421,8 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 Vector2fc uvsTL = element.vertexUvs[offset + VERTEX_TOP_LEFT];
                 if (uvlock) uvsTL = rotateUV(uvsTL, rotX, rotY, rotZ, element.directions[face], this.vertUV);
                 tessellator.setColorOpaque3f(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
-                tessellator.setLightmapCoord1i(lightmapCoordTopLeft);
+                tessellator.setLightmapCoord1i(lightIndexTopLeft);
+                tessellator.setShade1i((int) (ltl * 0xFF));
                 tessellator.addVertexWithUV(
                     posTL.x() + blockPos.x() + xOff,
                     posTL.y() + blockPos.y() + yOff,
@@ -455,7 +441,8 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 Vector2fc uvsBL = element.vertexUvs[offset + VERTEX_BOTTOM_LEFT];
                 if (uvlock) uvsBL = rotateUV(uvsBL, rotX, rotY, rotZ, element.directions[face], this.vertUV);
                 tessellator.setColorOpaque3f(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
-                tessellator.setLightmapCoord1i(lightmapCoordBottomLeft);
+                tessellator.setLightmapCoord1i(lightIndexBottomLeft);
+                tessellator.setShade1i((int) (lbl * 0xFF));
                 tessellator.addVertexWithUV(
                     posBL.x() + blockPos.x() + xOff,
                     posBL.y() + blockPos.y() + yOff,
@@ -474,7 +461,8 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 Vector2fc uvsBR = element.vertexUvs[offset + VERTEX_BOTTOM_RIGHT];
                 if (uvlock) uvsBR = rotateUV(uvsBR, rotX, rotY, rotZ, element.directions[face], this.vertUV);
                 tessellator.setColorOpaque3f(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
-                tessellator.setLightmapCoord1i(lightmapCoordBottomRight);
+                tessellator.setLightmapCoord1i(lightIndexBottomRight);
+                tessellator.setShade1i((int) (lbr * 0xFF));
                 tessellator.addVertexWithUV(
                     posBR.x() + blockPos.x() + xOff,
                     posBR.y() + blockPos.y() + yOff,
@@ -493,7 +481,8 @@ public class StaticBlockModelMojang implements StaticBlockModel {
                 Vector2fc uvsTR = element.vertexUvs[offset + VERTEX_TOP_RIGHT];
                 if (uvlock) uvsTR = rotateUV(uvsTR, rotX, rotY, rotZ, element.directions[face], this.vertUV);
                 tessellator.setColorOpaque3f(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
-                tessellator.setLightmapCoord1i(lightmapCoordTopRight);
+                tessellator.setLightmapCoord1i(lightIndexTopRight);
+                tessellator.setShade1i((int) (ltr * 0xFF));
                 tessellator.addVertexWithUV(
                     posTR.x() + blockPos.x() + xOff,
                     posTR.y() + blockPos.y() + yOff,
@@ -607,11 +596,11 @@ public class StaticBlockModelMojang implements StaticBlockModel {
         return Math.max(LIGHTING_CACHE.getBrightness(relX, relY, relZ), min);
     }
 
-    protected int getLightmap(int relX, int relY, int relZ, int min) {
-        int coord = LIGHTING_CACHE.getLightmapCoord(relX, relY, relZ);
-        int block = LightmapHelper.getBlockLightFromCoord(coord);
+    protected byte getLightIndex(int relX, int relY, int relZ, int min) {
+        byte coord = LIGHTING_CACHE.getLightIndex(relX, relY, relZ);
+        int block = LightIndexHelper.blockLightFromIndex(coord);
         if (block < min) {
-            coord = LightmapHelper.setBlocklightValue(coord, min);
+            coord = LightIndexHelper.setBlockLight(coord, min);
         }
         return coord;
     }
diff --git a/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java b/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java
index a74e34b68..b5f0c970a 100644
--- a/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java
+++ b/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java
@@ -9,6 +9,7 @@ import net.minecraft.client.render.tessellator.RenderBuffer;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.uniform.UniformBlockManager;
 import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -110,7 +111,7 @@ public class StaticEntityModelMojang implements StaticEntityModel {
         GLRenderer.pushFrame();
         GLRenderer.setShader(Shaders.ENTITY);
         GLRenderer.globalSetUniforms(Shaders.ENTITY);
-        Shaders.ENTITY.uniformVec2f("uLightmap", GLRenderer.getLightmapBlock(), GLRenderer.getLightmapSky());
+        Shaders.ENTITY.uniformVec2f("uLightmap", (LightIndexHelper.blockLightFromIndex(GLRenderer.getLightIndex()) + 0.5f)/16f, (LightIndexHelper.skyLightFromIndex(GLRenderer.getLightIndex()) + 0.5f)/16f);
         {
             GL41.glBindBuffer(GL41.GL_UNIFORM_BUFFER, UniformBlockManager.BLOCK_ENTITY_BONES.ubo);
             UniformBlockManager.BLOCK_ENTITY_BONES.buffer.clear();
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/basalt_mossy.json b/game/client/src/main/resources/assets/minecraft/models/block/basalt_mossy.json
deleted file mode 100644
index ed392adb9..000000000
--- a/game/client/src/main/resources/assets/minecraft/models/block/basalt_mossy.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "parent": "minecraft:block/template_mossy",
-  "textures": {
-    "base": "minecraft:block/basalt",
-    "overlay": "minecraft:block/moss_overlay"
-  }
-}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/granite_mossy.json b/game/client/src/main/resources/assets/minecraft/models/block/granite_mossy.json
deleted file mode 100644
index 3c41b87a1..000000000
--- a/game/client/src/main/resources/assets/minecraft/models/block/granite_mossy.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "parent": "minecraft:block/template_mossy",
-  "textures": {
-    "base": "minecraft:block/granite",
-    "overlay": "minecraft:block/moss_overlay"
-  }
-}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/grass.json b/game/client/src/main/resources/assets/minecraft/models/block/grass.json
index ca93bf227..a0ba17d95 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/grass.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/grass.json
@@ -11,38 +11,23 @@
 		"west": "#side",
 		"bottom": "block/dirt",
 		"top": "block/grass/top",
-		"side": "block/grass/side",
-		"render_overlay": "block/grass/side_overlay"
+		"side": "block/grass/side"
 	},
 	"elements": [
 		{
 			"from": [0, 0, 0],
 			"to": [16, 16, 16],
 			"faces": {
-				"north": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "north"},
-				"east": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "east"},
-				"south": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "south"},
-				"west": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "west"},
+				"north": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "north", "tintindex": 0},
+				"east": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "east", "tintindex": 0},
+				"south": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "south", "tintindex": 0},
+				"west": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "west", "tintindex": 0},
 				"up": {"uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up", "tintindex": 0},
 				"down": {"uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down"}
 			}
-		},
-		{
-			"from": [0, 0, 0],
-			"to": [16, 16, 16],
-			"faces": {
-				"north": {"uv": [0, 0, 16, 16], "texture": "#render_overlay", "cullface": "north", "tintindex": 0},
-				"east": {"uv": [0, 0, 16, 16], "texture": "#render_overlay", "cullface": "east", "tintindex": 0},
-				"south": {"uv": [0, 0, 16, 16], "texture": "#render_overlay", "cullface": "south", "tintindex": 0},
-				"west": {"uv": [0, 0, 16, 16], "texture": "#render_overlay", "cullface": "west", "tintindex": 0}
-			}
 		}
 	],
 	"particles": {
-		"down": -1,
-		"north": -1,
-		"south": -1,
-		"west": -1,
-		"east": -1
+		"down": -1
 	}
 }
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/limestone_mossy.json b/game/client/src/main/resources/assets/minecraft/models/block/limestone_mossy.json
deleted file mode 100644
index 044694ead..000000000
--- a/game/client/src/main/resources/assets/minecraft/models/block/limestone_mossy.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "parent": "minecraft:block/template_mossy",
-  "textures": {
-    "base": "minecraft:block/limestone",
-    "overlay": "minecraft:block/moss_overlay"
-  }
-}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/moss/basalt.json b/game/client/src/main/resources/assets/minecraft/models/block/moss/basalt.json
new file mode 100644
index 000000000..241fcdd54
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/moss/basalt.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:block/tinted_cube_all",
+  "textures": {
+    "all": "minecraft:block/moss/basalt"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/moss/granite.json b/game/client/src/main/resources/assets/minecraft/models/block/moss/granite.json
new file mode 100644
index 000000000..1fee3074b
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/moss/granite.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:block/tinted_cube_all",
+  "textures": {
+    "all": "minecraft:block/moss/granite"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/moss/limestone.json b/game/client/src/main/resources/assets/minecraft/models/block/moss/limestone.json
new file mode 100644
index 000000000..d7ec3408a
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/moss/limestone.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:block/tinted_cube_all",
+  "textures": {
+    "all": "minecraft:block/moss/limestone"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/moss/stone.json b/game/client/src/main/resources/assets/minecraft/models/block/moss/stone.json
new file mode 100644
index 000000000..046589249
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/moss/stone.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:block/tinted_cube_all",
+  "textures": {
+    "all": "minecraft:block/moss/stone"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/stone_mossy.json b/game/client/src/main/resources/assets/minecraft/models/block/stone_mossy.json
deleted file mode 100644
index d94248c1d..000000000
--- a/game/client/src/main/resources/assets/minecraft/models/block/stone_mossy.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "parent": "minecraft:block/template_mossy",
-  "textures": {
-    "base": "minecraft:block/stone",
-    "overlay": "minecraft:block/moss_overlay"
-  }
-}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/template_mossy.json b/game/client/src/main/resources/assets/minecraft/models/block/template_mossy.json
deleted file mode 100644
index 1b7dbbff3..000000000
--- a/game/client/src/main/resources/assets/minecraft/models/block/template_mossy.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "format_version": "1.21.6",
-  "credit": "Made with Blockbench",
-  "parent": "block/cube",
-  "textures": {
-    "down": "#overlay",
-    "up": "#overlay",
-    "north": "#overlay",
-    "east": "#overlay",
-    "south": "#overlay",
-    "west": "#overlay"
-  },
-  "elements": [
-    {
-      "from": [0, 0, 0],
-      "to": [16, 16, 16],
-      "faces": {
-        "north": {"uv": [0, 0, 16, 16], "texture": "#base"},
-        "east": {"uv": [0, 0, 16, 16], "texture": "#base"},
-        "south": {"uv": [0, 0, 16, 16], "texture": "#base"},
-        "west": {"uv": [0, 0, 16, 16], "texture": "#base"},
-        "up": {"uv": [0, 0, 16, 16], "texture": "#base"},
-        "down": {"uv": [0, 0, 16, 16], "texture": "#base"}
-      }
-    },
-    {
-      "from": [-0, -0, -0],
-      "to": [16, 16, 16],
-      "faces": {
-        "north": {"uv": [0, 0, 16, 16], "texture": "#overlay", "tintindex": 0},
-        "east": {"uv": [0, 0, 16, 16], "texture": "#overlay", "tintindex": 0},
-        "south": {"uv": [0, 0, 16, 16], "texture": "#overlay", "tintindex": 0},
-        "west": {"uv": [0, 0, 16, 16], "texture": "#overlay", "tintindex": 0},
-        "up": {"uv": [0, 0, 16, 16], "texture": "#overlay", "tintindex": 0},
-        "down": {"uv": [0, 0, 16, 16], "texture": "#overlay", "tintindex": 0}
-      }
-    }
-  ]
-}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/grass/side.cmask.png b/game/client/src/main/resources/assets/minecraft/textures/block/grass/side.cmask.png
new file mode 100644
index 000000000..553f5ff7f
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/grass/side.cmask.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/grass/side.png b/game/client/src/main/resources/assets/minecraft/textures/block/grass/side.png
index ef1502010..ecce99da7 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/grass/side.png and b/game/client/src/main/resources/assets/minecraft/textures/block/grass/side.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/grass/side_overlay.png b/game/client/src/main/resources/assets/minecraft/textures/block/grass/side_overlay.png
deleted file mode 100644
index ad1de140d..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/grass/side_overlay.png and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/grass/top.cmask.png b/game/client/src/main/resources/assets/minecraft/textures/block/grass/top.cmask.png
new file mode 100644
index 000000000..f0de358b8
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/grass/top.cmask.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss/basalt.cmask.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss/basalt.cmask.png
new file mode 100644
index 000000000..a74c2ac65
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/moss/basalt.cmask.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss/basalt.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss/basalt.png
new file mode 100644
index 000000000..686ac0145
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/moss/basalt.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss/granite.cmask.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss/granite.cmask.png
new file mode 100644
index 000000000..a74c2ac65
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/moss/granite.cmask.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss/granite.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss/granite.png
new file mode 100644
index 000000000..dd796d72f
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/moss/granite.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss/limestone.cmask.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss/limestone.cmask.png
new file mode 100644
index 000000000..a74c2ac65
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/moss/limestone.cmask.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss/limestone.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss/limestone.png
new file mode 100644
index 000000000..396232c61
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/moss/limestone.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss/stone.cmask.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss/stone.cmask.png
new file mode 100644
index 000000000..a74c2ac65
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/moss/stone.cmask.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss/stone.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss/stone.png
new file mode 100644
index 000000000..d09746434
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/moss/stone.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/moss_overlay.png b/game/client/src/main/resources/assets/minecraft/textures/block/moss_overlay.png
deleted file mode 100644
index fbbde9acd..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/moss_overlay.png and /dev/null differ
diff --git a/game/client/src/main/resources/shaders/color_world.vsh b/game/client/src/main/resources/shaders/color_world.vsh
index 8a30d9bfa..789a284c8 100644
--- a/game/client/src/main/resources/shaders/color_world.vsh
+++ b/game/client/src/main/resources/shaders/color_world.vsh
@@ -1,7 +1,7 @@
 #version 410 core
 layout (location = 0) in vec3 aPos;
 layout (location = 1) in vec4 aColor;
-layout (location = 3) in vec2 aLightmap;
+layout (location = 3) in float aLightmap;
 layout (location = 4) in vec3 aNormal;
 
 out vec4 Color;
@@ -24,12 +24,17 @@ layout (std140) uniform Matrices {
     mat4 viewInv;
 } matrices;
 
+vec2 unpackLightCoord() {
+    int asInt = int(aLightmap);
+    return vec2(((asInt & 0xF) + 0.5)/16.0, (((asInt & 0xF0) >> 4) + 0.5)/16.0);
+}
+
 void main() {
     vec4 p = vec4(aPos, 1);
     gl_Position = matrices.projection * matrices.view * model * p;
 
     Color = aColor;
-    LightMapCoord = aLightmap;
+    LightMapCoord = unpackLightCoord();
 
     vec4 norm = normalize(normalTransform * model * vec4(aNormal, 0));
     float dir1 = max(0.0, dot(norm, lightSourcePosition1));
diff --git a/game/client/src/main/resources/shaders/font.vsh b/game/client/src/main/resources/shaders/font.vsh
index 66ffb5e4c..573276518 100644
--- a/game/client/src/main/resources/shaders/font.vsh
+++ b/game/client/src/main/resources/shaders/font.vsh
@@ -5,7 +5,7 @@ layout (location = 2) in float aShift;
 layout (location = 3) in vec4 aColor;
 layout (location = 4) in vec2 aUv;
 layout (location = 5) in vec2 aUvSizes;
-layout (location = 6) in vec2 aLightmap;
+layout (location = 6) in float aLightmap;
 
 out VS_OUT {
     vec2 size;
@@ -18,6 +18,11 @@ out VS_OUT {
 
 uniform float uZ;
 
+vec2 unpackLightCoord() {
+    int asInt = int(aLightmap);
+    return vec2(((asInt & 0xF) + 0.5)/16.0, (((asInt & 0xF0) >> 4) + 0.5)/16.0);
+}
+
 void main() {
     gl_Position = vec4(aPos, uZ, 1);
 
@@ -26,5 +31,5 @@ void main() {
     vs_out.color = aColor;
     vs_out.uv = aUv/256.0;
     vs_out.uvSizes = aUvSizes/256.0;
-    vs_out.lightmap = aLightmap;
+    vs_out.lightmap = unpackLightCoord();
 }
diff --git a/game/client/src/main/resources/shaders/item.fsh b/game/client/src/main/resources/shaders/item.fsh
new file mode 100644
index 000000000..03bdcc37c
--- /dev/null
+++ b/game/client/src/main/resources/shaders/item.fsh
@@ -0,0 +1,91 @@
+#version 410 core
+
+out vec4 FragColor;
+
+in vec4 Color;
+in vec2 TexCoord;
+in vec2 LightMapCoord;
+in vec3 Light;
+in vec3 Norm;
+
+uniform float uAlphaTest;
+uniform vec4 uColor;
+uniform vec2 uViewPortSize;
+
+layout (std140) uniform FogState {
+    vec4 color;
+    int mode;
+    float start;
+    float end;
+    float density;
+} fogState;
+
+layout (std140) uniform Matrices {
+    mat4 projection;
+    mat4 projectionInv;
+    mat4 view;
+    mat4 viewInv;
+} matrices;
+
+uniform sampler2D colortex;
+uniform sampler2D lighttex;
+uniform sampler2D emmisivetex;
+uniform sampler2D colormasktex;
+
+float distance() {
+    vec4 fragPos = matrices.projectionInv * vec4((gl_FragCoord.xy / uViewPortSize) * 2.0 - 1.0, gl_FragCoord.z * 2.0 - 1.0, 1.0);
+    fragPos /= fragPos.w;
+
+    return length(fragPos.xyz);
+}
+
+// Taken from https://github.com/hughsk/glsl-fog
+float fogFactorLinear() {
+    return 1.0 - clamp(((fogState.end - (distance())) / (fogState.end - fogState.start)), 0.0, 1.0);
+}
+
+float fogFactorExp() {
+    return 1.0 - clamp(exp(-fogState.density * (distance())), 0.0, 1.0);
+}
+
+float fogFactorExp2() {
+    float LOG2 = -1.442695;
+    float d = fogState.density * (distance());
+    return 1.0 - clamp(exp2(d * d * LOG2), 0.0, 1.0);
+}
+
+
+vec4 computeFog(vec4 color) {
+    float f = 0;
+    if (fogState.mode == 0) { // Linear
+        f = fogFactorLinear();
+    }
+    else if (fogState.mode == 1) { // EXP
+        f = fogFactorExp();
+    }
+    else if (fogState.mode == 2) { // EXP2
+        f = fogFactorExp2();
+    }
+    return vec4(mix(color.rgb, fogState.color.rgb, f), color.a);
+}
+
+void main() {
+    vec4 emmisiveColor = texture(emmisivetex, TexCoord);
+    vec4 lightColor = texture(lighttex, vec2(max(LightMapCoord.x, emmisiveColor.r), max(LightMapCoord.y, emmisiveColor.g)));
+    vec4 texColor = texture(colortex, TexCoord);
+    vec4 maskColor = texture(colormasktex, TexCoord);
+
+    vec4 c = vec4(mix(vec3(1, 1, 1), Color.rgb, maskColor.r), 1) * uColor;
+
+    vec4 postColor = texColor * c * lightColor;
+    vec4 litColor = vec4(postColor.rgb * clamp(Light, 0, 1), postColor.a);
+    //    vec4 litColor = vec4(abs(Norm), 1f);
+
+    vec4 fColor = computeFog(litColor);
+
+
+    FragColor = fColor;
+    if (FragColor.a < uAlphaTest) {
+        discard;
+    }
+}
diff --git a/game/client/src/main/resources/shaders/item.vsh b/game/client/src/main/resources/shaders/item.vsh
new file mode 100644
index 000000000..676551563
--- /dev/null
+++ b/game/client/src/main/resources/shaders/item.vsh
@@ -0,0 +1,48 @@
+#version 410 core
+layout (location = 0) in vec3 aPos;
+layout (location = 1) in vec4 aColor;
+layout (location = 2) in vec2 aUV;
+layout (location = 3) in float aLightmap;
+layout (location = 4) in vec3 aNormal;
+
+out vec4 Color;
+out vec2 TexCoord;
+out vec2 LightMapCoord;
+out vec3 Light;
+out vec3 Norm;
+
+uniform mat4 normalTransform;
+uniform vec4 lightModelAmbient;
+uniform vec4 lightSourcePosition1;
+uniform vec4 lightSourcePosition2;
+uniform vec4 lightSourceDiffuse1;
+uniform vec4 lightSourceDiffuse2;
+
+uniform mat4 model;
+
+layout (std140) uniform Matrices {
+    mat4 projection;
+    mat4 projectionInv;
+    mat4 view;
+    mat4 viewInv;
+} matrices;
+
+vec2 unpackLightCoord() {
+    int asInt = int(aLightmap);
+    return vec2(((asInt & 0xF) + 0.5)/16.0, (((asInt & 0xF0) >> 4) + 0.5)/16.0);
+}
+
+void main() {
+    vec4 p = vec4(aPos, 1);
+    gl_Position = matrices.projection * matrices.view * model * p;
+
+    TexCoord = aUV;
+    Color = aColor;
+    LightMapCoord = unpackLightCoord();
+
+    Norm = normalize(aNormal);
+    vec4 norm = normalize(normalTransform * model * vec4(aNormal, 0));
+    float dir1 = max(0.0, dot(norm, lightSourcePosition1));
+    float dir2 = max(0.0, dot(norm, lightSourcePosition2));
+    Light = (lightModelAmbient + lightSourceDiffuse1 * (dir1 + dir2)).xyz;
+}
diff --git a/game/client/src/main/resources/shaders/lod.fsh b/game/client/src/main/resources/shaders/lod.fsh
new file mode 100644
index 000000000..b39576477
--- /dev/null
+++ b/game/client/src/main/resources/shaders/lod.fsh
@@ -0,0 +1,8 @@
+#version 330 core
+out vec4 FragColor;
+
+in vec4 Color;
+
+void main() {
+    FragColor = Color;
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/shaders/lod.gsh b/game/client/src/main/resources/shaders/lod.gsh
new file mode 100644
index 000000000..9571aa103
--- /dev/null
+++ b/game/client/src/main/resources/shaders/lod.gsh
@@ -0,0 +1,205 @@
+#version 330 core
+layout (points) in;
+layout (triangle_strip, max_vertices = 36) out;
+
+in VS_OUT {
+    vec3 color;
+    uint faces;
+} gs_in[];
+
+out vec4 Color;
+
+uniform mat4 model;
+layout (std140) uniform Matrices {
+    mat4 projection;
+    mat4 projectionInv;
+    mat4 view;
+    mat4 viewInv;
+} matrices;
+
+#define FACES_MASK_BOTTOM 0x01u
+#define FACES_MASK_TOP 0x02u
+#define FACES_MASK_NORTH 0x04u
+#define FACES_MASK_SOUTH 0x08u
+#define FACES_MASK_WEST 0x10u
+#define FACES_MASK_EAST 0x20u
+
+/*
+ * for north/south faces:
+ *   Y  A  B
+ *   ^  C  D
+ *      >  X
+ * for east/west faces:
+ *   Y  B  A
+ *   ^  D  C
+ *      X  <
+ * for top/bottom faces:
+ *   Z  A  B
+ *   ^  C  D
+ *      >  X
+ * A = 0, 1
+ * B = 1, 1
+ * C = 0, 0
+ * D = 1, 0
+ */
+
+#define Aa 0.0
+#define Ab 1.0
+#define Ba 1.0
+#define Bb 1.0
+#define Ca 0.0
+#define Cb 0.0
+#define Da 1.0
+#define Db 0.0
+
+#define BR_BOTTOM 0.5
+#define BR_TOP 1.0
+#define BR_NORTH_SOUTH 0.8
+#define BR_EAST_WEST 0.6
+
+void main() {
+    // uint color = gs_in[0].packedColorFaces & 0x00FFFFFFu;
+    // float r = ((color >> 0) & 0xFFu) / 255.0;
+    // float g = ((color >> 8) & 0xFFu) / 255.0;
+    // float b = ((color >> 16) & 0xFFu) / 255.0;
+    // uint faces = ((gs_in[0].packedColorFaces >> 24) & 0xFFu);
+    // vec3 cc = vec3(r, g, b);
+    uint faces = gs_in[0].faces;
+    vec3 cc = gs_in[0].color;
+
+    if (faces > 0u) {
+        faces = 0xFFu;
+    }
+
+    if ((faces & FACES_MASK_BOTTOM) > 0u) { // min Y
+        Color = vec4(cc * BR_BOTTOM, 1.0);
+
+        // C
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Ca, 0.0, Cb, 0.0));
+        EmitVertex();
+
+        // D
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Da, 0.0, Db, 0.0));
+        EmitVertex();
+
+        // A
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Aa, 0.0, Ab, 0.0));
+        EmitVertex();
+
+        // B
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Ba, 0.0, Bb, 0.0));
+        EmitVertex();
+
+        EndPrimitive();
+    }
+
+    if ((faces & FACES_MASK_TOP) > 0u) { // max Y
+        Color = vec4(cc * BR_TOP, 1.0);
+
+        // C
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Ca, 1.0, Cb, 0.0));
+        EmitVertex();
+
+        // A
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Aa, 1.0, Ab, 0.0));
+        EmitVertex();
+
+        // D
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Da, 1.0, Db, 0.0));
+        EmitVertex();
+
+        // B
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Ba, 1.0, Bb, 0.0));
+        EmitVertex();
+        
+        EndPrimitive();
+    }
+
+    if ((faces & FACES_MASK_NORTH) > 0u) { // min Z
+        Color = vec4(cc * BR_NORTH_SOUTH, 1.0);
+
+        // C
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Ca, Cb, 0.0, 0.0));
+        EmitVertex();
+
+        // A
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Aa, Ab, 0.0, 0.0));
+        EmitVertex();
+
+        // D
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Da, Db, 0.0, 0.0));
+        EmitVertex();
+
+        // B
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Ba, Bb, 0.0, 0.0));
+        EmitVertex();
+        
+        EndPrimitive();
+    }
+
+    if ((faces & FACES_MASK_SOUTH) > 0u) { // max Z
+        Color = vec4(cc * BR_NORTH_SOUTH, 1.0);
+
+        // C
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Ca, Cb, 1.0, 0.0));
+        EmitVertex();
+
+        // D
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Da, Db, 1.0, 0.0));
+        EmitVertex();
+
+        // A
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Aa, Ab, 1.0, 0.0));
+        EmitVertex();
+
+        // B
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(Ba, Bb, 1.0, 0.0));
+        EmitVertex();
+        
+        EndPrimitive();
+    }
+
+    if ((faces & FACES_MASK_WEST) > 0u) { // min X
+        Color = vec4(cc * BR_EAST_WEST, 1.0);
+
+        // C
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(0.0, Ca, Cb, 0.0));
+        EmitVertex();
+
+        // A
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(0.0, Aa, Ab, 0.0));
+        EmitVertex();
+
+        // D
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(0.0, Da, Db, 0.0));
+        EmitVertex();
+
+        // B
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(0.0, Ba, Bb, 0.0));
+        EmitVertex();
+        
+        EndPrimitive();
+    }
+
+    if ((faces & FACES_MASK_EAST) > 0u) { // max X
+        Color = vec4(cc * BR_EAST_WEST, 1.0);
+
+        // C
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(1.0, Ca, Cb, 0.0));
+        EmitVertex();
+
+        // D
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(1.0, Da, Db, 0.0));
+        EmitVertex();
+
+        // A
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(1.0, Aa, Ab, 0.0));
+        EmitVertex();
+
+        // B
+        gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + vec4(1.0, Ba, Bb, 0.0));
+        EmitVertex();
+        
+        EndPrimitive();
+    }
+}
diff --git a/game/client/src/main/resources/shaders/lod.vsh b/game/client/src/main/resources/shaders/lod.vsh
new file mode 100644
index 000000000..7bfed510b
--- /dev/null
+++ b/game/client/src/main/resources/shaders/lod.vsh
@@ -0,0 +1,16 @@
+#version 330 core
+layout (location = 0) in vec3 aPos;
+layout (location = 1) in vec3 aColor;
+layout (location = 2) in uint aFaces;
+
+out VS_OUT {
+    vec3 color;
+    uint faces;
+} vs_out;
+
+void main() {
+    gl_Position = vec4(aPos, 1.0);
+
+    vs_out.color = aColor;
+    vs_out.faces = aFaces;
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/shaders/particle.fsh b/game/client/src/main/resources/shaders/particle.fsh
index 0208364de..f7a726d72 100644
--- a/game/client/src/main/resources/shaders/particle.fsh
+++ b/game/client/src/main/resources/shaders/particle.fsh
@@ -3,15 +3,82 @@ out vec4 FragColor;
 
 in vec4 Color;
 in vec2 TexCoord;
-in vec2 Lightmap;
+in vec2 LightMapCoord;
 
 uniform float uAlphaTest;
+uniform vec4 uColor;
+uniform vec2 uViewPortSize;
+
+layout (std140) uniform FogState {
+    vec4 color;
+    int mode;
+    float start;
+    float end;
+    float density;
+} fogState;
+
+layout (std140) uniform Matrices {
+    mat4 projection;
+    mat4 projectionInv;
+    mat4 view;
+    mat4 viewInv;
+} matrices;
 
 uniform sampler2D colortex;
 uniform sampler2D lighttex;
+uniform sampler2D emmisivetex;
+uniform sampler2D colormasktex;
+
+float distance() {
+    vec4 fragPos = matrices.projectionInv * vec4((gl_FragCoord.xy / uViewPortSize) * 2.0 - 1.0, gl_FragCoord.z * 2.0 - 1.0, 1.0);
+    fragPos /= fragPos.w;
+
+    return length(fragPos.xyz);
+}
+
+// Taken from https://github.com/hughsk/glsl-fog
+float fogFactorLinear() {
+    return 1.0 - clamp(((fogState.end - (distance())) / (fogState.end - fogState.start)), 0.0, 1.0);
+}
+
+float fogFactorExp() {
+    return 1.0 - clamp(exp(-fogState.density * (distance())), 0.0, 1.0);
+}
+
+float fogFactorExp2() {
+    float LOG2 = -1.442695;
+    float d = fogState.density * (distance());
+    return 1.0 - clamp(exp2(d * d * LOG2), 0.0, 1.0);
+}
+
+
+vec4 computeFog(vec4 color) {
+    float f = 0;
+    if (fogState.mode == 0) { // Linear
+        f = fogFactorLinear();
+    }
+    else if (fogState.mode == 1) { // EXP
+        f = fogFactorExp();
+    }
+    else if (fogState.mode == 2) { // EXP2
+        f = fogFactorExp2();
+    }
+    return vec4(mix(color.rgb, fogState.color.rgb, f), color.a);
+}
 
 void main() {
-    FragColor = texture(colortex, TexCoord) * texture(lighttex, Lightmap) * Color;
+    vec4 emmisiveColor = texture(emmisivetex, TexCoord);
+    vec4 lightColor = texture(lighttex, vec2(max(LightMapCoord.x, emmisiveColor.r), max(LightMapCoord.y, emmisiveColor.g)));
+    vec4 texColor = texture(colortex, TexCoord);
+    vec4 maskColor = texture(colormasktex, TexCoord);
+
+    vec4 c = vec4(mix(vec3(1, 1, 1), Color.rgb, maskColor.r), 1) * uColor;
+
+    vec4 postColor = texColor * c * lightColor;
+
+    vec4 fColor = computeFog(postColor);
+
+    FragColor = fColor;
     if (FragColor.a < uAlphaTest) {
         discard;
     }
diff --git a/game/client/src/main/resources/shaders/particle.gsh b/game/client/src/main/resources/shaders/particle.gsh
index fe109c241..290510268 100644
--- a/game/client/src/main/resources/shaders/particle.gsh
+++ b/game/client/src/main/resources/shaders/particle.gsh
@@ -12,7 +12,7 @@ in VS_OUT {
 
 out vec4 Color;
 out vec2 TexCoord;
-out vec2 Lightmap;
+out vec2 LightMapCoord;
 
 uniform mat4 model;
 layout (std140) uniform Matrices {
@@ -24,7 +24,7 @@ layout (std140) uniform Matrices {
 
 void main() {
     Color = gs_in[0].color;
-    Lightmap = gs_in[0].lightmap;
+    LightMapCoord = gs_in[0].lightmap;
 
     TexCoord = gs_in[0].uv;
     gl_Position = matrices.projection * matrices.view * model * (gl_in[0].gl_Position + matrices.viewInv * vec4(-gs_in[0].scale,  gs_in[0].scale, 0.0, 0.0));
diff --git a/game/client/src/main/resources/shaders/particle.vsh b/game/client/src/main/resources/shaders/particle.vsh
index f9bbfcdcd..a23f94354 100644
--- a/game/client/src/main/resources/shaders/particle.vsh
+++ b/game/client/src/main/resources/shaders/particle.vsh
@@ -4,7 +4,7 @@ layout (location = 1) in float aScale;
 layout (location = 2) in vec4 aColor;
 layout (location = 3) in vec2 aUv;
 layout (location = 4) in vec2 aUvSizes;
-layout (location = 5) in vec2 aLightmap;
+layout (location = 5) in float aLightmap;
 
 out VS_OUT {
     float scale;
@@ -14,6 +14,11 @@ out VS_OUT {
     vec2 lightmap;
 } vs_out;
 
+vec2 unpackLightCoord() {
+    int asInt = int(aLightmap);
+    return vec2(((asInt & 0xF) + 0.5)/16.0, (((asInt & 0xF0) >> 4) + 0.5)/16.0);
+}
+
 void main() {
     gl_Position = vec4(aPos, 1);
 
@@ -21,5 +26,5 @@ void main() {
     vs_out.color = aColor;
     vs_out.uv = aUv;
     vs_out.uvSizes = aUvSizes;
-    vs_out.lightmap = aLightmap;
+    vs_out.lightmap = unpackLightCoord();
 }
diff --git a/game/client/src/main/resources/shaders/terrain.fsh b/game/client/src/main/resources/shaders/terrain.fsh
index fda0727cb..e4d7c4da6 100644
--- a/game/client/src/main/resources/shaders/terrain.fsh
+++ b/game/client/src/main/resources/shaders/terrain.fsh
@@ -3,10 +3,11 @@
 out vec4 FragColor;
 
 in vec4 Color;
+in float Shade;
 in vec2 TexCoord;
 in vec2 LightMapCoord;
 in vec3 Light;
-in vec3 Norm;
+in vec4 Norm;
 
 uniform float uAlphaTest;
 uniform vec4 uColor;
@@ -30,7 +31,7 @@ layout (std140) uniform Matrices {
 uniform sampler2D colortex;
 uniform sampler2D lighttex;
 uniform sampler2D emmisivetex;
-//uniform sampler2D colormasktex;
+uniform sampler2D colormasktex;
 
 float distance() {
     vec4 fragPos = matrices.projectionInv * vec4((gl_FragCoord.xy / uViewPortSize) * 2.0 - 1.0, gl_FragCoord.z * 2.0 - 1.0, 1.0);
@@ -73,14 +74,11 @@ void main() {
     vec4 emmisiveColor = texture(emmisivetex, TexCoord);
     vec4 lightColor = texture(lighttex, vec2(max(LightMapCoord.x, emmisiveColor.r), max(LightMapCoord.y, emmisiveColor.g)));
     vec4 texColor = texture(colortex, TexCoord);
-    //    vec4 maskColor = texture(colormasktex, TexCoord);
+    vec4 maskColor = texture(colormasktex, TexCoord);
 
-    vec4 oColor = texColor * lightColor;
+    vec4 c = vec4(mix(vec3(1, 1, 1), Color.rgb, maskColor.r), 1) * uColor;
 
-//    vec4 c = mix(vec4(1, 1, 1, 1), Color, maskColor.r);
-    vec4 c = Color;
-
-    vec4 postColor = oColor * c * uColor;
+    vec4 postColor = texColor * c * Shade * lightColor;
     vec4 litColor = vec4(postColor.rgb * clamp(Light, 0, 1), postColor.a);
 //    vec4 litColor = vec4(abs(Norm), 1f);
 
diff --git a/game/client/src/main/resources/shaders/terrain.gsh b/game/client/src/main/resources/shaders/terrain.gsh
new file mode 100644
index 000000000..41418cffa
--- /dev/null
+++ b/game/client/src/main/resources/shaders/terrain.gsh
@@ -0,0 +1,105 @@
+#version 330 core
+layout (points) in;
+layout (triangle_strip, max_vertices = 4) out;
+
+in VS_OUT {
+    vec3 sourcePos;
+    vec3 sourceColor;
+    vec3 sourceNormal;
+
+    vec2 V1UV;
+    vec2 V1LightShade;
+
+    vec3 V2PosOffset;
+    vec2 V2UV;
+    vec2 V2LightShade;
+
+    vec3 V3PosOffset;
+    vec2 V3UV;
+    vec2 V3LightShade;
+
+    vec3 V4PosOffset;
+    vec2 V4UV;
+    vec2 V4LightShade;
+} gs_in[];
+
+out vec4 Color;
+out float Shade;
+out vec2 TexCoord;
+out vec2 LightMapCoord;
+out vec3 Light;
+out vec4 Norm;
+
+uniform mat4 model;
+layout (std140) uniform Matrices {
+    mat4 projection;
+    mat4 projectionInv;
+    mat4 view;
+    mat4 viewInv;
+} matrices;
+
+uniform mat4 normalTransform;
+uniform vec4 lightModelAmbient;
+uniform vec4 lightSourcePosition1;
+uniform vec4 lightSourcePosition2;
+uniform vec4 lightSourceDiffuse1;
+uniform vec4 lightSourceDiffuse2;
+
+vec2 unpackLightCoord(vec2 lightShade) {
+    int asInt = int(lightShade.y);
+    return vec2(((asInt & 0xF) + 0.5)/16.0, (((asInt & 0xF0) >> 4) + 0.5)/16.0);
+}
+
+float unpackShade(vec2 lightShade) {
+    return lightShade.x/256;
+}
+
+vec3 expand(vec3 source, vec3 center, float expandAmount) {
+    vec3 diff = source - center;
+    return center + diff * expandAmount;
+}
+
+vec2 expand(vec2 source, vec2 center, float expandAmount) {
+    vec2 diff = source - center;
+    return center + diff * expandAmount;
+}
+
+void main() {
+    Norm = normalize(normalTransform * model * vec4(gs_in[0].sourceNormal, 0));
+    float dir1 = max(0.0, dot(Norm, lightSourcePosition1));
+    float dir2 = max(0.0, dot(Norm, lightSourcePosition2));
+    Light = (lightModelAmbient + lightSourceDiffuse1 * (dir1 + dir2)).xyz;
+
+    vec3 posCenter = gs_in[0].sourcePos + (gs_in[0].V2PosOffset + gs_in[0].V3PosOffset + gs_in[0].V4PosOffset)/3;
+    vec2 uvCenter = (gs_in[0].V1UV + gs_in[0].V2UV + gs_in[0].V3UV + gs_in[0].V4UV)/4;
+
+    Color = vec4(gs_in[0].sourceColor, 1);
+    Shade = unpackShade(gs_in[0].V1LightShade);
+    TexCoord = expand(gs_in[0].V1UV, uvCenter, 0.995f);
+    LightMapCoord = unpackLightCoord(gs_in[0].V1LightShade);
+    gl_Position = matrices.projection * matrices.view * model * vec4(expand(gs_in[0].sourcePos, posCenter, 1.0005f), 1);
+    EmitVertex();
+
+    Color = vec4(gs_in[0].sourceColor, 1);
+    Shade = unpackShade(gs_in[0].V2LightShade);
+    TexCoord = expand(gs_in[0].V2UV, uvCenter, 0.995f);
+    LightMapCoord = unpackLightCoord(gs_in[0].V2LightShade);
+    gl_Position = matrices.projection * matrices.view * model * vec4(expand(gs_in[0].sourcePos + gs_in[0].V2PosOffset, posCenter, 1.0005f), 1);
+    EmitVertex();
+
+    Color = vec4(gs_in[0].sourceColor, 1);
+    Shade = unpackShade(gs_in[0].V4LightShade);
+    TexCoord = expand(gs_in[0].V4UV, uvCenter, 0.995f);
+    LightMapCoord = unpackLightCoord(gs_in[0].V4LightShade);
+    gl_Position = matrices.projection * matrices.view * model * vec4(expand(gs_in[0].sourcePos + gs_in[0].V4PosOffset, posCenter, 1.0005f), 1);
+    EmitVertex();
+
+    Color = vec4(gs_in[0].sourceColor, 1);
+    Shade = unpackShade(gs_in[0].V3LightShade);
+    TexCoord = expand(gs_in[0].V3UV, uvCenter, 0.995f);
+    LightMapCoord = unpackLightCoord(gs_in[0].V3LightShade);
+    gl_Position = matrices.projection * matrices.view * model * vec4(expand(gs_in[0].sourcePos + gs_in[0].V3PosOffset, posCenter, 1.0005f), 1);
+    EmitVertex();
+
+    EndPrimitive();
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/shaders/terrain.vsh b/game/client/src/main/resources/shaders/terrain.vsh
index bad079d51..53d29cb43 100644
--- a/game/client/src/main/resources/shaders/terrain.vsh
+++ b/game/client/src/main/resources/shaders/terrain.vsh
@@ -1,43 +1,64 @@
 #version 410 core
-layout (location = 0) in vec3 aPos;
-layout (location = 1) in vec4 aColor;
-layout (location = 2) in vec2 aUV;
-layout (location = 3) in vec2 aLightmap;
-layout (location = 4) in vec3 aNormal;
-
-out vec4 Color;
-out vec2 TexCoord;
-out vec2 LightMapCoord;
-out vec3 Light;
-out vec3 Norm;
-
-uniform mat4 normalTransform;
-uniform vec4 lightModelAmbient;
-uniform vec4 lightSourcePosition1;
-uniform vec4 lightSourcePosition2;
-uniform vec4 lightSourceDiffuse1;
-uniform vec4 lightSourceDiffuse2;
-
-uniform mat4 model;
-
-layout (std140) uniform Matrices {
-    mat4 projection;
-    mat4 projectionInv;
-    mat4 view;
-    mat4 viewInv;
-} matrices;
+// Only guranteed 16 4 comp locations, so some attributes are packed together to save count, see (https://docs.gl/gl4/glGet @ GL_MAX_VERTEX_ATTRIBS)
+// Can combine uv and light shade in future if number needs further reduction
+layout (location = 0) in vec3 aSourcePos;
+layout (location = 1) in vec3 aSourceColor;
+layout (location = 2) in vec3 aSourceNormal;
+
+// Vertex one uses the position of the source pos
+layout (location = 3) in vec2 aV1UV;
+layout (location = 4) in vec2 aV1LightShade;
+
+layout (location = 5) in vec3 aV2PosOffset;
+layout (location = 6) in vec2 aV2UV;
+layout (location = 7) in vec2 aV2LightShade;
+
+layout (location = 8) in vec3 aV3PosOffset;
+layout (location = 9) in vec2 aV3UV;
+layout (location = 10) in vec2 aV3LightShade;
+
+layout (location = 11) in vec3 aV4PosOffset;
+layout (location = 12) in vec2 aV4UV;
+layout (location = 13) in vec2 aV4LightShade;
+
+out VS_OUT {
+    vec3 sourcePos;
+    vec3 sourceColor;
+    vec3 sourceNormal;
+
+    vec2 V1UV;
+    vec2 V1LightShade;
+
+    vec3 V2PosOffset;
+    vec2 V2UV;
+    vec2 V2LightShade;
+
+    vec3 V3PosOffset;
+    vec2 V3UV;
+    vec2 V3LightShade;
+
+    vec3 V4PosOffset;
+    vec2 V4UV;
+    vec2 V4LightShade;
+} vs_out;
 
 void main() {
-    vec4 p = vec4(aPos, 1);
-    gl_Position = matrices.projection * matrices.view * model * p;
-
-    TexCoord = aUV;
-    Color = aColor;
-    LightMapCoord = aLightmap;
-
-    Norm = normalize(aNormal);
-    vec4 norm = normalize(normalTransform * model * vec4(aNormal, 0));
-    float dir1 = max(0.0, dot(norm, lightSourcePosition1));
-    float dir2 = max(0.0, dot(norm, lightSourcePosition2));
-    Light = (lightModelAmbient + lightSourceDiffuse1 * (dir1 + dir2)).xyz;
+    vs_out.sourcePos = aSourcePos;
+    vs_out.sourceColor = aSourceColor;
+    vs_out.sourceNormal = aSourceNormal;
+
+    vs_out.V1UV = aV1UV;
+    vs_out.V1LightShade = aV1LightShade;
+
+    vs_out.V2PosOffset = aV2PosOffset;
+    vs_out.V2UV = aV2UV;
+    vs_out.V2LightShade = aV2LightShade;
+
+    vs_out.V3PosOffset = aV3PosOffset;
+    vs_out.V3UV = aV3UV;
+    vs_out.V3LightShade = aV3LightShade;
+
+    vs_out.V4PosOffset = aV4PosOffset;
+    vs_out.V4UV = aV4UV;
+    vs_out.V4LightShade = aV4LightShade;
 }
diff --git a/game/client/src/main/resources/shaders/world.vsh b/game/client/src/main/resources/shaders/world.vsh
index ed183056e..aebf0b0d8 100644
--- a/game/client/src/main/resources/shaders/world.vsh
+++ b/game/client/src/main/resources/shaders/world.vsh
@@ -2,7 +2,7 @@
 layout (location = 0) in vec3 aPos;
 layout (location = 1) in vec4 aColor;
 layout (location = 2) in vec2 aUV;
-layout (location = 3) in vec2 aLightmap;
+layout (location = 3) in float aLightmap;
 layout (location = 4) in vec3 aNormal;
 
 out vec4 Color;
@@ -27,13 +27,18 @@ layout (std140) uniform Matrices {
     mat4 viewInv;
 } matrices;
 
+vec2 unpackLightCoord() {
+    int asInt = int(aLightmap);
+    return vec2(((asInt & 0xF) + 0.5)/16.0, (((asInt & 0xF0) >> 4) + 0.5)/16.0);
+}
+
 void main() {
     vec4 p = vec4(aPos, 1);
     gl_Position = matrices.projection * matrices.view * model * p;
 
     TexCoord = (texture * vec4(aUV, 0.0, 1.0)).xy;
     Color = aColor;
-    LightMapCoord = aLightmap;
+    LightMapCoord = unpackLightCoord();
 
     vec4 norm = normalize(normalTransform * model * vec4(aNormal, 0));
     float dir1 = max(0.0, dot(norm, lightSourcePosition1));
diff --git a/game/core/src/main/java/net/minecraft/core/block/Block.java b/game/core/src/main/java/net/minecraft/core/block/Block.java
index 5089647be..645222364 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Block.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Block.java
@@ -342,8 +342,8 @@ public final class Block<T extends BlockLogic>
     }
 
     @Override
-    public int getLightmapCoord(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) {
-        return this.logic.getLightmapCoord(source, tilePos);
+    public byte getLightIndex(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) {
+        return this.logic.getLightIndex(source, tilePos);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java b/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
index a3bd4dac6..d4d212a36 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
@@ -91,11 +91,11 @@ interface BlockInterface {
         return this.getBrightness(source, new TilePos(x, y, z));
     }
 
-    int getLightmapCoord(final @NotNull WorldSource source, final @NotNull TilePosc tilePos);
+    byte getLightIndex(final @NotNull WorldSource source, final @NotNull TilePosc tilePos);
 
     @Deprecated
     default int getLightmapCoord(final @NotNull WorldSource source, final int x, final int y, final int z) {
-        return this.getLightmapCoord(source, new TilePos(x, y, z));
+        return this.getLightIndex(source, new TilePos(x, y, z));
     }
 
     /**
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
index c52700d53..3d75f6085 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
@@ -34,7 +34,6 @@ import org.joml.primitives.AABBd;
 import org.joml.primitives.AABBdc;
 
 import java.util.List;
-import java.util.Objects;
 import java.util.Random;
 
 public class BlockLogic implements BlockInterface, IItemConvertible {
@@ -132,8 +131,8 @@ public class BlockLogic implements BlockInterface, IItemConvertible {
     }
 
     @Override
-    public int getLightmapCoord(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) {
-        return source.getLightmapCoord(tilePos, this.block.emission);
+    public byte getLightIndex(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) {
+        return source.getLightIndex(tilePos, this.block.emission);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
index 4fc091ab0..16cc73ec2 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
@@ -3,7 +3,9 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Materials;
+import net.minecraft.core.block.support.FullSupport;
 import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
 import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
@@ -21,7 +23,7 @@ import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
-public class BlockLogicRepeater extends BlockLogic {
+public class BlockLogicRepeater extends BlockLogic implements ISupportable {
     public static final double[] torchPosOffset = {
         -0.0625D, 0.0625D, 0.1875D, 0.3125D
     };
@@ -55,7 +57,7 @@ public class BlockLogicRepeater extends BlockLogic {
 
     @Override
     public boolean canPlaceAt(@NotNull World world, @NotNull TilePosc tilePos) {
-        return world.canPlaceOnSurfaceOfBlock(tilePos.down(new TilePos())) && super.canPlaceAt(world, tilePos);
+        return this.isSupported(world, tilePos, Side.BOTTOM);
     }
 
     @Override
@@ -238,4 +240,8 @@ public class BlockLogicRepeater extends BlockLogic {
         world.spawnParticle("reddust", px + xOffset, py, pz + zOffset, 0, 0, 0, redstoneBrightness);
     }
 
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side) {
+        return FullSupport.INSTANCE;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
index 57a96ee9c..6fd2d552f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
@@ -206,8 +206,8 @@ public class BlockLogicTorch extends BlockLogic implements ISupportable {
     }
 
     @Override
-    public int getLightmapCoord(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
-        return source.getLightmapCoord(tilePos, this.block.emission > 0 ? 15 : 0);
+    public byte getLightIndex(@NotNull WorldSource source, @NotNull TilePosc tilePos) {
+        return source.getLightIndex(tilePos, this.block.emission > 0 ? 15 : 0);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Entity.java b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
index 0c5cb84ea..09103a1ed 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Entity.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
@@ -1,47 +1,45 @@
 package net.minecraft.core.entity;
 
-import java.util.List;
-import java.util.Random;
-
-import net.minecraft.core.block.BlockLogicFluid;
-import net.minecraft.core.block.Blocks;
-import net.minecraft.core.block.material.Materials;
-import net.minecraft.core.entity.animal.MobPig;
-import net.minecraft.core.entity.vehicle.EntityBoat;
-import net.minecraft.core.block.piston.BlockLogicPistonHead;
-import net.minecraft.core.util.collection.NamespaceID;
-import net.minecraft.core.util.helper.Direction;
-import net.minecraft.core.util.helper.DyeColor;
-import net.minecraft.core.world.Dimension;
-import net.minecraft.core.world.ICarriable;
-import net.minecraft.core.world.pos.TilePos;
-import net.minecraft.core.world.pos.TilePosc;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
 import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.tags.DoubleTag;
 import com.mojang.nbt.tags.FloatTag;
 import com.mojang.nbt.tags.ListTag;
-
 import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockLogicFluid;
+import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.material.Materials;
+import net.minecraft.core.block.piston.BlockLogicPistonHead;
 import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.entity.animal.MobPig;
 import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.entity.vehicle.EntityBoat;
 import net.minecraft.core.enums.EnumBlockSoundEffectType;
-import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.util.helper.DamageType;
+import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.DyeColor;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.ICarriable;
 import net.minecraft.core.world.IVehicle;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.data.SynchedEntityData;
+import net.minecraft.core.world.pos.TilePos;
+import net.minecraft.core.world.pos.TilePosc;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.joml.Vector3dc;
 import org.joml.primitives.AABBd;
 import org.joml.primitives.AABBdc;
 
+import java.util.List;
+import java.util.Random;
+
 public abstract class Entity
     implements IVehicle {
     public static final int DATA_SHARED_FLAGS_ID = 0;
@@ -795,63 +793,28 @@ public abstract class Entity
         return calcBrightness(partialTick);
     }
 
-    public int calcLightmap(float partialTick) {
-        if (Global.accessor.isFullbrightEnabled()) return 15 << 20 | 15;
+    public byte calcLightIndex(float partialTick) {
+        if (Global.accessor.isFullbrightEnabled()) return LightIndexHelper.lightIndex2i(15, 15);
         TilePos blockPos = new TilePos(this.x, this.y - this.heightOffset + this.ySlideOffset + this.bbHeight * 0.66D, this.z);
 
-        final int skylight;
-        final int blocklight;
+        byte lightIndex = 0;
         if (this.world.getBlockLitInteriorSurface(blockPos)) {
             TilePos queryPos = new TilePos();
 
-            int bU = this.world.getSavedLightValue(LightLayer.Block, blockPos.up(queryPos));
-            final int bW = this.world.getSavedLightValue(LightLayer.Block, blockPos.west(queryPos));
-            final int bE = this.world.getSavedLightValue(LightLayer.Block, blockPos.east(queryPos));
-            final int bS = this.world.getSavedLightValue(LightLayer.Block, blockPos.south(queryPos));
-            final int bN = this.world.getSavedLightValue(LightLayer.Block, blockPos.north(queryPos));
-            if (bW > bU) {
-                bU = bW;
-            }
-            if (bE > bU) {
-                bU = bE;
-            }
-            if (bS > bU) {
-                bU = bS;
-            }
-            if (bN > bU) {
-                bU = bN;
-            }
-            blocklight = bU;
-
-            int sU = this.world.getSavedLightValue(LightLayer.Sky, blockPos.up(queryPos));
-            final int sW = this.world.getSavedLightValue(LightLayer.Sky, blockPos.west(queryPos));
-            final int sE = this.world.getSavedLightValue(LightLayer.Sky, blockPos.east(queryPos));
-            final int sS = this.world.getSavedLightValue(LightLayer.Sky, blockPos.south(queryPos));
-            final int sN = this.world.getSavedLightValue(LightLayer.Sky, blockPos.north(queryPos));
-            if (sW > sU) {
-                sU = sW;
-            }
-            if (sE > sU) {
-                sU = sE;
-            }
-            if (sS > sU) {
-                sU = sS;
-            }
-            if (sN > sU) {
-                sU = sN;
-            }
-            skylight = sU;
-
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.up(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.west(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.east(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.south(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.north(queryPos)));
         } else {
-            skylight = this.world.getSavedLightValue(LightLayer.Sky, blockPos);
-            blocklight = this.world.getSavedLightValue(LightLayer.Block, blockPos);
+            lightIndex = this.world.getSavedLightIndex(blockPos);
         }
 
-        return this.world.getLightmapCoord(skylight, blocklight);
+        return lightIndex;
     }
 
-    public int getLightmap(float partialTick) {
-        return calcLightmap(partialTick);
+    public byte getLightIndex(float partialTick) {
+        return calcLightIndex(partialTick);
     }
 
     public void setWorld(@NotNull final World world) {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityFallingBlock.java b/game/core/src/main/java/net/minecraft/core/entity/EntityFallingBlock.java
index 583a3aa94..9ec9c62f4 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityFallingBlock.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityFallingBlock.java
@@ -1,5 +1,6 @@
 package net.minecraft.core.entity;
 
+import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicSand;
@@ -9,11 +10,10 @@ import net.minecraft.core.block.entity.TileEntityDispatcher;
 import net.minecraft.core.block.motion.CarriedBlock;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.enums.EnumDropCause;
-import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
-import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.world.IVehicle;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
@@ -196,59 +196,24 @@ public class EntityFallingBlock extends Entity
     }
 
     @Override
-    public int calcLightmap(float partialTick) {
-        if (Global.accessor.isFullbrightEnabled()) return 15 << 20 | 15;
+    public byte calcLightIndex(float partialTick) {
+        if (Global.accessor.isFullbrightEnabled()) return LightIndexHelper.lightIndex2i(15, 15);
         TilePos blockPos = new TilePos(this.x, this.y - this.heightOffset + this.ySlideOffset + this.bbHeight * 0.66D, this.z);
 
-        final int skylight;
-        final int blocklight;
+        byte lightIndex = 0;
         if (this.world.getBlockLitInteriorSurface(blockPos) || this.world.getBlockType(blockPos) == this.carriedBlock.block()) {
             TilePos queryPos = new TilePos();
 
-            int bU = this.world.getSavedLightValue(LightLayer.Block, blockPos.up(queryPos));
-            final int bW = this.world.getSavedLightValue(LightLayer.Block, blockPos.west(queryPos));
-            final int bE = this.world.getSavedLightValue(LightLayer.Block, blockPos.east(queryPos));
-            final int bS = this.world.getSavedLightValue(LightLayer.Block, blockPos.south(queryPos));
-            final int bN = this.world.getSavedLightValue(LightLayer.Block, blockPos.north(queryPos));
-            if (bW > bU) {
-                bU = bW;
-            }
-            if (bE > bU) {
-                bU = bE;
-            }
-            if (bS > bU) {
-                bU = bS;
-            }
-            if (bN > bU) {
-                bU = bN;
-            }
-            blocklight = bU;
-
-            int sU = this.world.getSavedLightValue(LightLayer.Sky, blockPos.up(queryPos));
-            final int sW = this.world.getSavedLightValue(LightLayer.Sky, blockPos.west(queryPos));
-            final int sE = this.world.getSavedLightValue(LightLayer.Sky, blockPos.east(queryPos));
-            final int sS = this.world.getSavedLightValue(LightLayer.Sky, blockPos.south(queryPos));
-            final int sN = this.world.getSavedLightValue(LightLayer.Sky, blockPos.north(queryPos));
-            if (sW > sU) {
-                sU = sW;
-            }
-            if (sE > sU) {
-                sU = sE;
-            }
-            if (sS > sU) {
-                sU = sS;
-            }
-            if (sN > sU) {
-                sU = sN;
-            }
-            skylight = sU;
-
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.up(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.west(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.east(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.south(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.north(queryPos)));
         } else {
-            skylight = this.world.getSavedLightValue(LightLayer.Sky, blockPos);
-            blocklight = this.world.getSavedLightValue(LightLayer.Block, blockPos);
+            lightIndex = this.world.getSavedLightIndex(blockPos);
         }
 
-        return this.world.getLightmapCoord(skylight, blocklight);
+        return lightIndex;
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java
index e58ae8690..4488db962 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java
@@ -7,6 +7,7 @@ import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.projectile.ProjectileFireball;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.item.Items;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import net.minecraft.core.util.helper.DamageType;
@@ -253,7 +254,7 @@ public class MobGhast extends MobFlying
     }
 
     @Override
-    public int calcLightmap(float partialTick) {
-        return this.world.getLightmapCoord(15, 15);
+    public byte calcLightIndex(float partialTick) {
+        return LightIndexHelper.lightIndex2i(15, 15);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/enums/LightLayer.java b/game/core/src/main/java/net/minecraft/core/enums/LightLayer.java
index a65a1c1ef..e5c8cb9ec 100644
--- a/game/core/src/main/java/net/minecraft/core/enums/LightLayer.java
+++ b/game/core/src/main/java/net/minecraft/core/enums/LightLayer.java
@@ -1,9 +1,12 @@
 package net.minecraft.core.enums;
 
+import net.minecraft.core.util.helper.LightIndexHelper;
+
 public enum LightLayer
 {
     Sky(15),
     Block(0);
+    public static final byte DEFAULT_LIGHT_INDEX = LightIndexHelper.lightIndex2i(Sky.defaultLightLevel, Block.defaultLightLevel);
 
     LightLayer(int defaultLightLevel)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/LightIndexHelper.java b/game/core/src/main/java/net/minecraft/core/util/helper/LightIndexHelper.java
new file mode 100644
index 000000000..62e4478ea
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/util/helper/LightIndexHelper.java
@@ -0,0 +1,58 @@
+package net.minecraft.core.util.helper;
+
+public final class LightIndexHelper {
+    private LightIndexHelper() {
+
+    }
+
+    public static byte lightIndex2i(int skyLight, int blockLight) {
+        return (byte) ((skyLight & 0xF) << 4  | blockLight & 0xF);
+    }
+
+    public static byte lightIndex2f(float skyLight, float blockLight) {
+        return lightIndex2i((int) (skyLight * 0xF), (int) (blockLight * 0xF));
+    }
+
+    public static int skyLightFromIndex(byte lightIndex) {
+        return (lightIndex >> 4) & 0xF;
+    }
+
+    public static int blockLightFromIndex(byte lightIndex) {
+        return lightIndex & 0xF;
+    }
+
+    public static byte setSkyLight(byte lightIndex, int skyLight) {
+        return (byte) ((skyLight & 0xF) << 4 | (lightIndex & 0xF));
+    }
+
+    public static byte setBlockLight(byte lightIndex, int blockLight) {
+        return (byte) ((lightIndex & 0xF0) | (blockLight & 0xF));
+    }
+
+    public static byte max(byte lightIndex1, byte lightIndex2) {
+        int sky1 = (lightIndex1 >> 4) & 0xF;
+        int sky2 = (lightIndex2 >> 4) & 0xF;
+
+        int block1 = lightIndex1 & 0xF;
+        int block2 = lightIndex2 & 0xF;
+
+        return (byte) (Math.max(sky1, sky2) << 4 | Math.max(block1, block2));
+    }
+
+    public static byte avg(byte lightIndex1, byte lightIndex2) {
+        int sky0 = (lightIndex1 >> 4) & 0xF;
+        int sky1 = (lightIndex2 >> 4) & 0xF;
+
+        int block0 = lightIndex1 & 0xF;
+        int block1 = lightIndex2 & 0xF;
+
+        int sky = (sky0 + sky1) >> 1;
+        int block = (block0 + block1) >> 1;
+
+        return (byte) (sky << 4 | block);
+    }
+
+    public static byte avg(byte lightIndex1, byte lightIndex2, byte lightIndex3, byte lightIndex4) {
+        return avg(avg(lightIndex1, lightIndex2), avg(lightIndex3, lightIndex4));
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java b/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java
index 8813b5145..f706e07a4 100644
--- a/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java
+++ b/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java
@@ -183,6 +183,63 @@ public class MathHelper {
         return ((a + b) * (a + b + 1)) / 2 + b;
     }
 
+    // From https://stackoverflow.com/questions/6162651/half-precision-floating-point-in-java
+    // ignores the higher 16 bits
+    public static float fromHalfFloat(short halfFloat )
+    {
+        int mant = halfFloat & 0x03ff;            // 10 bits mantissa
+        int exp =  halfFloat & 0x7c00;            // 5 bits exponent
+        if( exp == 0x7c00 )                   // NaN/Inf
+            exp = 0x3fc00;                    // -> NaN/Inf
+        else if( exp != 0 )                   // normalized value
+        {
+            exp += 0x1c000;                   // exp - 15 + 127
+            if( mant == 0 && exp > 0x1c400 )  // smooth transition
+                return Float.intBitsToFloat( ( halfFloat & 0x8000 ) << 16
+                    | exp << 13 | 0x3ff );
+        }
+        else if( mant != 0 )                  // && exp==0 -> subnormal
+        {
+            exp = 0x1c400;                    // make it normal
+            do {
+                mant <<= 1;                   // mantissa * 2
+                exp -= 0x400;                 // decrease exp by 1
+            } while( ( mant & 0x400 ) == 0 ); // while not normal
+            mant &= 0x3ff;                    // discard subnormal bit
+        }                                     // else +/-0 -> +/-0
+        return Float.intBitsToFloat(          // combine all parts
+            ( halfFloat & 0x8000 ) << 16          // sign  << ( 31 - 15 )
+                | ( exp | mant ) << 13 );         // value << ( 23 - 10 )
+    }
+
+    // returns all higher 16 bits as 0 for all results
+    public static short toHalfFloat(float fval )
+    {
+        int fbits = Float.floatToIntBits( fval );
+        int sign = fbits >>> 16 & 0x8000;          // sign only
+        int val = ( fbits & 0x7fffffff ) + 0x1000; // rounded value
+
+        if( val >= 0x47800000 )               // might be or become NaN/Inf
+        {                                     // avoid Inf due to rounding
+            if( ( fbits & 0x7fffffff ) >= 0x47800000 )
+            {                                 // is or must become NaN/Inf
+                if( val < 0x7f800000 )        // was value but too large
+                    return (short) (sign | 0x7c00);     // make it +/-Inf
+                return (short) (sign | 0x7c00 |        // remains +/-Inf or NaN
+                                    ( fbits & 0x007fffff ) >>> 13); // keep NaN (and Inf) bits
+            }
+            return (short) (sign | 0x7bff);             // unrounded not quite Inf
+        }
+        if( val >= 0x38800000 )               // remains normalized value
+            return (short) (sign | val - 0x38000000 >>> 13); // exp - 127 + 15
+        if( val < 0x33000000 )                // too small for subnormal
+            return (short) sign;                      // becomes +/-0
+        val = ( fbits & 0x7fffffff ) >>> 23;  // tmp exp for subnormal calc
+        return (short) (sign | ( ( fbits & 0x7fffff | 0x800000 ) // add subnormal bit
+                    + ( 0x800000 >>> val - 102 )     // round depending on cut off
+                    >>> 126 - val ));   // div by 2^(1-(exp-127+15)) and >> 13 | exp=0
+    }
+
     private static final float[] SIN_TABLE;
 
     public static final float PI = (float) Math.PI;
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 7a3bc79af..877bf8593 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
@@ -143,17 +143,12 @@ public class BlocksContainer implements MutableWorldSource {
     }
 
     @Override
-    public int getLightmapCoord(final @NotNull TilePosc tilePos, final int lightEmission) {
+    public byte getLightIndex(final @NotNull TilePosc tilePos, final int lightEmission) {
         if (this.lightRefEntity != null) {
-            return this.lightRefEntity.getLightmap(this.partialTick);
+            return this.lightRefEntity.getLightIndex(this.partialTick);
         }
 
-        return this.world.getLightmapCoord(tilePos, lightEmission);
-    }
-
-    @Override
-    public int getLightmapCoord(final int skyLight, final int blockLight) {
-        return this.world.getLightmapCoord(skyLight, blockLight);
+        return this.world.getLightIndex(tilePos, lightEmission);
     }
 
     @Override
@@ -218,6 +213,11 @@ public class BlocksContainer implements MutableWorldSource {
         return this.world.getSavedLightValue(lightLayer, tilePos);
     }
 
+    @Override
+    public byte getSavedLightIndex(@NotNull TilePosc tilePos) {
+        return this.world.getSavedLightIndex(tilePos);
+    }
+
     @Override
     public boolean isRetro() {
         return this.world.isRetro();
diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java
index 2bc8f61dd..827166fbb 100644
--- a/game/core/src/main/java/net/minecraft/core/world/World.java
+++ b/game/core/src/main/java/net/minecraft/core/world/World.java
@@ -29,6 +29,7 @@ import net.minecraft.core.sound.BlockSound;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.debug.Debug;
 import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.HitResult;
@@ -90,7 +91,7 @@ public class World implements MutableWorldSource {
     public static boolean AUTOSAVE = true;
 
     public static final int HEIGHT_BLOCKS = 256;
-    public static final int MAX_BRIGHTNESS = 15;
+    public static final int MAX_LIGHT_LEVEL = 15;
 
     public static final int MAX_BLOCK_X = 32000000;
     public static final int MAX_BLOCK_Z = 32000000;
@@ -827,7 +828,7 @@ public class World implements MutableWorldSource {
         if (tilePos.y() < 0) {
             return 0;
         } else {
-            return this.getChunk(tilePos).getRawBrightness(new ChunkTilePos(new TilePos(tilePos.x(), Math.min(tilePos.y(), this.getHeightBlocks() - 1), tilePos.z())), 0);
+            return this.getChunk(tilePos).getRawSkyLightLevel(new ChunkTilePos(new TilePos(tilePos.x(), Math.min(tilePos.y(), this.getHeightBlocks() - 1), tilePos.z())), 0);
         }
     }
 
@@ -847,7 +848,7 @@ public class World implements MutableWorldSource {
 
     private int getBlockLightValue_do(final @NotNull TilePosc tilePos, final boolean first) {
         if (!tilePos.inBounds(this)) {
-            return MAX_BRIGHTNESS;
+            return MAX_LIGHT_LEVEL;
         }
 
         if (first) {
@@ -865,7 +866,7 @@ public class World implements MutableWorldSource {
         if (tilePos.y() < 0) {
             return 0;
         }
-        return this.getChunk(tilePos).getRawBrightness(new ChunkTilePos(tilePos.x(), Math.min(tilePos.y(), this.getHeightBlocks() - 1), tilePos.z()), this.skyDarken);
+        return this.getChunk(tilePos).getRawSkyLightLevel(new ChunkTilePos(tilePos.x(), Math.min(tilePos.y(), this.getHeightBlocks() - 1), tilePos.z()), this.skyDarken);
     }
 
     public boolean canLoadedBlockSeeSky(final @NotNull TilePosc tilePos) {
@@ -905,7 +906,18 @@ public class World implements MutableWorldSource {
         } else if (!this.isBlockLoaded(tilePos)) {
             return 0;
         } else {
-            return this.getChunk(tilePos).getBrightness(lightLayer, new ChunkTilePos(tilePos));
+            return this.getChunk(tilePos).getLightLevel(lightLayer, new ChunkTilePos(tilePos));
+        }
+    }
+
+    @Override
+    public byte getSavedLightIndex(@NotNull TilePosc tilePos) {
+        if (!tilePos.inBounds(this)) {
+            return LightLayer.DEFAULT_LIGHT_INDEX;
+        } else if (!this.isBlockLoaded(tilePos)) {
+            return 0;
+        } else {
+            return this.getChunk(tilePos).getLightIndex(new ChunkTilePos(tilePos));
         }
     }
 
@@ -917,7 +929,7 @@ public class World implements MutableWorldSource {
     @Override
     public void setLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePosc tilePos, final int value) {
         if (tilePos.inBounds(this) && this.isBlockLoaded(tilePos)) {
-            this.getChunk(tilePos).setBrightness(lightLayer, new ChunkTilePos(tilePos), value);
+            this.getChunk(tilePos).setLightLevel(lightLayer, new ChunkTilePos(tilePos), value);
             for (final @NotNull LevelListener listener : this.listeners) {
                 listener.blockChanged(tilePos.x(), tilePos.y(), tilePos.z());
             }
@@ -931,33 +943,21 @@ public class World implements MutableWorldSource {
     }
 
     @Override
-    public int getLightmapCoord(final @NotNull TilePosc tilePos, final int lightEmission) {
-        int skyLight = this.getSavedLightValue(LightLayer.Sky, tilePos);
-        int blockLight = Math.max(this.getSavedLightValue(LightLayer.Block, tilePos), lightEmission);
+    public byte getLightIndex(final @NotNull TilePosc tilePos, final int lightEmission) {
+        byte lightIndex = getSavedLightIndex(tilePos);
+        lightIndex = LightIndexHelper.max(lightIndex, (byte) lightEmission);
 
         if (this.getBlockLitInteriorSurface(tilePos)) {
             TilePos queryPos = new TilePos();
-            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.add(Direction.UP, queryPos)));
-            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.add(Direction.DOWN, queryPos)));
-            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.add(Direction.EAST, queryPos)));
-            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.add(Direction.WEST, queryPos)));
-            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.add(Direction.SOUTH, queryPos)));
-            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.add(Direction.NORTH, queryPos)));
-
-            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.add(Direction.UP, queryPos)));
-            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.add(Direction.DOWN, queryPos)));
-            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.add(Direction.EAST, queryPos)));
-            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.add(Direction.WEST, queryPos)));
-            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.add(Direction.SOUTH, queryPos)));
-            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.add(Direction.NORTH, queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.up(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.down(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.east(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.west(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.south(queryPos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.north(queryPos)));
         }
 
-        return this.getLightmapCoord(skyLight, blockLight);
-    }
-
-    @Override
-    public int getLightmapCoord(final int skyLight, final int blockLight) {
-        return 0; // TODO figure out if/how we would get this working in core
+        return lightIndex;
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/WorldSource.java b/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
index 21aadb3ef..bfea39716 100644
--- a/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
+++ b/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
@@ -56,15 +56,13 @@ public interface WorldSource {
         return this.getBrightness(new TilePos(x, y, z), lightEmission);
     }
 
-    int getLightmapCoord(final @NotNull TilePosc tilePos, final int lightEmission);
+    byte getLightIndex(final @NotNull TilePosc tilePos, final int lightEmission);
 
     @Deprecated
-    default int getLightmapCoord(final int x, final int y, final int z, final int lightEmission) {
-        return this.getLightmapCoord(new TilePos(x, y, z), lightEmission);
+    default byte getLightmapCoord(final int x, final int y, final int z, final int lightEmission) {
+        return this.getLightIndex(new TilePos(x, y, z), lightEmission);
     }
 
-    int getLightmapCoord(int skyLight, int blockLight);
-
     float getLightBrightness(final @NotNull TilePosc tilePos);
 
     @Deprecated
@@ -132,6 +130,8 @@ public interface WorldSource {
 
     int getSavedLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePosc tilePos);
 
+    byte getSavedLightIndex(@NotNull TilePosc tilePos);
+
     @Deprecated
     default int getSavedLightValue(final @NotNull LightLayer layer, final int x, final int y, final int z) {
         return this.getSavedLightValue(layer, new TilePos(x, y, z));
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 15a3f0922..24d906cfd 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
@@ -8,9 +8,9 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.entity.Entity;
+import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
-import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.pos.ChunkPos;
 import net.minecraft.core.world.pos.ChunkPosc;
@@ -23,7 +23,12 @@ import org.jetbrains.annotations.Nullable;
 import org.joml.primitives.AABBdc;
 import org.slf4j.Logger;
 
-import java.util.*;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
 
 public class Chunk {
     private static final Logger LOGGER = LogUtils.getLogger();
@@ -209,7 +214,7 @@ public class Chunk {
         final @NotNull TilePos worldPos = new TilePos(this.pos, tilePos);
         if (iPos.y < heightValue) {
             for (int dy = iPos.y; dy < heightValue; dy++) {
-                this.setBrightness(LightLayer.Sky, iPos.x, dy, iPos.z, World.MAX_BRIGHTNESS);
+                this.setBrightness(LightLayer.Sky, iPos.x, dy, iPos.z, World.MAX_LIGHT_LEVEL);
             }
         } else {
             this.world.scheduleLightingUpdate(LightLayer.Sky, new TilePos(worldPos.x, heightValue, worldPos.z), new TilePos(worldPos.x, iPos.y, worldPos.z));
@@ -218,7 +223,7 @@ public class Chunk {
             }
         }
 
-        int lightValue = World.MAX_BRIGHTNESS;
+        int lightValue = World.MAX_LIGHT_LEVEL;
         final int lightY = iPos.y;
         while (iPos.y > 0 && lightValue > 0) {
             iPos.y--;
@@ -230,7 +235,7 @@ public class Chunk {
             if (lightValue < 0) {
                 lightValue = 0;
             }
-            this.setBrightness(LightLayer.Sky, iPos, lightValue);
+            this.setLightLevel(LightLayer.Sky, iPos, lightValue);
         }
 
         for (; iPos.y > 0 && Blocks.lightBlock[this.getBlockId(iPos.down(queryPos))] == 0; iPos.y--) {
@@ -489,39 +494,47 @@ public class Chunk {
         return true;
     }
 
-    public int getBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos) {
+    public int getLightLevel(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos) {
+        if (!tilePos.inBounds()) {
+            return 0;
+        }
+
+        return this.getSection(tilePos).getLightLevel(lightLayer, new ChunkSectionTilePos(tilePos));
+    }
+
+    public byte getLightIndex(final @NotNull ChunkTilePosc tilePos) {
         if (!tilePos.inBounds()) {
             return 0;
         }
 
-        return this.getSection(tilePos).getBrightness(lightLayer, new ChunkSectionTilePos(tilePos));
+        return this.getSection(tilePos).getLightIndex(new ChunkSectionTilePos(tilePos));
     }
 
     @Deprecated
     public final int getBrightness(final @NotNull LightLayer lightLayer, final int x, final int y, final int z) {
-        return this.getBrightness(lightLayer, new ChunkTilePos(x, y, z));
+        return this.getLightLevel(lightLayer, new ChunkTilePos(x, y, z));
     }
 
-    public void setBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos, final int value) {
+    public void setLightLevel(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos, final int value) {
         if (!tilePos.inBounds()) {
             return;
         }
 
-        this.getSection(tilePos).setBrightness(lightLayer, new ChunkSectionTilePos(tilePos), value);
+        this.getSection(tilePos).setLightLevel(lightLayer, new ChunkSectionTilePos(tilePos), value);
         this.isModified = true;
     }
 
     @Deprecated
     public final void setBrightness(final @NotNull LightLayer lightLayer, final int x, final int y, final int z, final int value) {
-        this.setBrightness(lightLayer, new ChunkTilePos(x, y, z), value);
+        this.setLightLevel(lightLayer, new ChunkTilePos(x, y, z), value);
     }
 
-    public int getRawBrightness(final @NotNull ChunkTilePosc tilePos, final int subtractedSkyLight) {
+    public int getRawSkyLightLevel(final @NotNull ChunkTilePosc tilePos, final int subtractedSkyLight) {
         if (!tilePos.inBounds()) {
             return 0;
         }
 
-        final int lightValue = this.getSection(tilePos).getRawBrightness(new ChunkSectionTilePos(tilePos), subtractedSkyLight);
+        final int lightValue = this.getSection(tilePos).getRawSkyLightLevel(new ChunkSectionTilePos(tilePos), subtractedSkyLight);
         if (lightValue > 0) {
             Chunk.isLit = true;
         }
@@ -531,7 +544,7 @@ public class Chunk {
 
     @Deprecated
     public final int getRawBrightness(final int x, final int y, final int z, final int subtractedSkyLight) {
-        return this.getRawBrightness(new ChunkTilePos(x, y, z), subtractedSkyLight);
+        return this.getRawSkyLightLevel(new ChunkTilePos(x, y, z), subtractedSkyLight);
     }
 
     public void addEntity(final @NotNull Entity entity) {
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 77e360966..8513989ec 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
@@ -5,6 +5,7 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.enums.LightLayer;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.biome.Biome;
@@ -116,32 +117,20 @@ public class ChunkCache
     }
 
     @Override
-    public int getLightmapCoord(final @NotNull TilePosc tilePos, final int lightEmission) {
-        int skyLight = getSavedLightValue(LightLayer.Sky, tilePos);
-        int blockLight = Math.max(getSavedLightValue(LightLayer.Block, tilePos), lightEmission);
+    public byte getLightIndex(final @NotNull TilePosc tilePos, final int lightEmission) {
+        byte lightIndex = getSavedLightIndex(tilePos);
+        lightIndex = LightIndexHelper.max(lightIndex, (byte) lightEmission);
 
         if (this.getBlockLitInteriorSurface(tilePos)) {
-            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)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.up(this.queryTilePos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.down(this.queryTilePos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.east(this.queryTilePos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.west(this.queryTilePos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.south(this.queryTilePos)));
+            lightIndex = LightIndexHelper.max(lightIndex, getSavedLightIndex(tilePos.north(this.queryTilePos)));
         }
 
-        return this.getLightmapCoord(skyLight, blockLight);
-    }
-
-    @Override
-    public int getLightmapCoord(final int skyLight, final int blockLight) {
-        return this.world.getLightmapCoord(skyLight, blockLight);
+        return lightIndex;
     }
 
     @Override
@@ -181,7 +170,7 @@ public class ChunkCache
             }
             return brightness;
         } else {
-            return getChunk(tilePos).getRawBrightness(this.queryChunkTilePos.set(tilePos), this.world.skyDarken);
+            return getChunk(tilePos).getRawSkyLightLevel(this.queryChunkTilePos.set(tilePos), this.world.skyDarken);
         }
     }
 
@@ -242,7 +231,18 @@ public class ChunkCache
         } else if (!this.isChunkLoaded(tilePos)) {
             return 0;
         } else {
-            return this.getChunk(tilePos).getBrightness(lightLayer, this.queryChunkTilePos.set(tilePos));
+            return this.getChunk(tilePos).getLightLevel(lightLayer, this.queryChunkTilePos.set(tilePos));
+        }
+    }
+
+    @Override
+    public byte getSavedLightIndex(@NotNull TilePosc tilePos) {
+        if (tilePos.y() < 0 || tilePos.y() >= this.getHeightBlocks()) {
+            return LightLayer.DEFAULT_LIGHT_INDEX;
+        } else if (!this.isChunkLoaded(tilePos)) {
+            return 0;
+        } else {
+            return this.getChunk(tilePos).getLightIndex(this.queryChunkTilePos.set(tilePos));
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderLegacy.java b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderLegacy.java
index f716543c3..11196739e 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderLegacy.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderLegacy.java
@@ -1,28 +1,37 @@
 package net.minecraft.core.world.chunk;
 
 import com.mojang.logging.LogUtils;
+import com.mojang.nbt.NbtIo;
+import com.mojang.nbt.tags.CompoundTag;
+import com.mojang.nbt.tags.ListTag;
+import com.mojang.nbt.tags.Tag;
 import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import net.minecraft.core.Global;
-import net.minecraft.core.block.entity.TileEntityDispatcher;
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.entity.TileEntityDispatcher;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityDispatcher;
-import com.mojang.nbt.tags.Tag;
-import com.mojang.nbt.tags.CompoundTag;
-import com.mojang.nbt.tags.ListTag;
-import com.mojang.nbt.NbtIo;
-import net.minecraft.core.world.chunk.reader.*;
+import net.minecraft.core.util.helper.LightIndexHelper;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.reader.ChunkReader;
+import net.minecraft.core.world.chunk.reader.ChunkReaderLegacy;
+import net.minecraft.core.world.chunk.reader.ChunkReaderVersion1;
+import net.minecraft.core.world.chunk.reader.ChunkReaderVersion2;
+import net.minecraft.core.world.chunk.reader.ChunkReaderVersion3;
 import net.minecraft.core.world.chunk.writer.ChunkWriter;
 import net.minecraft.core.world.data.ChunkNibbleArray;
 import net.minecraft.core.world.data.ChunkUnsignedByteArray;
-import net.minecraft.core.world.World;
 import net.minecraft.core.world.save.LevelData;
 import org.slf4j.Logger;
 
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.file.Files;
-import java.util.*;
+import java.util.Arrays;
+import java.util.List;
 
 public class ChunkLoaderLegacy
     implements IChunkLoader
@@ -227,11 +236,23 @@ public class ChunkLoaderLegacy
         if (section.data != null) {
             writer.putData(section.yPosition, section.data);
         }
-        if (section.skylightMap != null) {
-            writer.putSkyLight(section.yPosition, section.skylightMap);
-        }
-        if (section.blocklightMap != null) {
-            writer.putBlockLight(section.yPosition, section.blocklightMap);
+        if (section.lightData != null) {
+            byte[] blockLightData = new byte[section.lightData.length / 2];
+            byte[] skyLightData = new byte[section.lightData.length / 2];
+            for (int i = 0; i < section.lightData.length / 2; i++) {
+                byte lightIndex0 = section.lightData[i * 2];
+                byte lightIndex1 = section.lightData[i * 2 + 1];
+
+                int block0 = LightIndexHelper.blockLightFromIndex(lightIndex0);
+                int block1 = LightIndexHelper.blockLightFromIndex(lightIndex1);
+
+                int sky0 = LightIndexHelper.skyLightFromIndex(lightIndex0);
+                int sky1 = LightIndexHelper.skyLightFromIndex(lightIndex1);
+                blockLightData[i] = (byte) (block1 << 4 | block0);
+                skyLightData[i] = (byte) (sky1 << 4 | sky0);
+            }
+            writer.putSkyLight(section.yPosition, skyLightData);
+            writer.putBlockLight(section.yPosition, blockLightData);
         }
         writer.putBiomeMap(section.yPosition, section.biome);
     }
@@ -323,20 +344,27 @@ public class ChunkLoaderLegacy
     public static void loadChunkSectionFromCompound(ChunkSection section, ChunkReader reader, Int2ObjectMap<String> biomeRegistry) {
         section.blocks = reader.getBlocks(section.yPosition);
         section.data = reader.getData(section.yPosition);
-        section.skylightMap = reader.getSkyLight(section.yPosition);
-        section.blocklightMap = reader.getBlockLight(section.yPosition);
+        ChunkNibbleArray skylightMap = reader.getSkyLight(section.yPosition);
+        ChunkNibbleArray blocklightMap = reader.getBlockLight(section.yPosition);
+        section.lightData = new byte[Chunk.CHUNK_SIZE_X * ChunkSection.SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z];
+        if (skylightMap != null && skylightMap.data != null) {
+            for (int i = 0; i < section.lightData.length/2; i++) {
+                section.lightData[i * 2] |= (byte) ((skylightMap.data[i] & 0xF) << 4);
+                section.lightData[i * 2 + 1] |= (byte) ((((skylightMap.data[i] & 0xF0) >> 4) & 0xF) << 4);
+            }
+        }
+        if (blocklightMap != null && blocklightMap.data != null) {
+            for (int i = 0; i < section.lightData.length/2; i++) {
+                section.lightData[i * 2] |= (byte) (blocklightMap.data[i] & 0xF);
+                section.lightData[i * 2 + 1] |= (byte) (((blocklightMap.data[i] & 0xF0) >> 4) & 0xF);
+            }
+        }
         section.biome = reader.getBiomeMap(section.yPosition, biomeRegistry);
 
         // Recreate any missing data
         if (section.data != null && !section.data.isValid()) {
             section.data = new ChunkUnsignedByteArray(Chunk.CHUNK_SIZE_X, ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
         }
-        if (section.skylightMap != null && !section.skylightMap.isValid()) {
-            section.skylightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-        }
-        if (section.blocklightMap != null && !section.blocklightMap.isValid()) {
-            section.blocklightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-        }
         if (section.biome == null || section.biome.length != Chunk.CHUNK_SIZE_X * (ChunkSection.SECTION_SIZE_Y >> 3) * Chunk.CHUNK_SIZE_Z) {
             section.biome = new byte[Chunk.CHUNK_SIZE_X * (ChunkSection.SECTION_SIZE_Y >> 3) * Chunk.CHUNK_SIZE_Z];
             Arrays.fill(section.biome, (byte)-1);
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkSection.java b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkSection.java
index 037998bc3..698845cb7 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkSection.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkSection.java
@@ -4,9 +4,9 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.LightLayer;
+import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.data.ChunkNibbleArray;
 import net.minecraft.core.world.data.ChunkUnsignedByteArray;
 import net.minecraft.core.world.pos.ChunkSectionTilePos;
 import net.minecraft.core.world.pos.ChunkSectionTilePosc;
@@ -29,8 +29,7 @@ public class ChunkSection {
 
     public short @Nullable [] blocks;
     public @Nullable ChunkUnsignedByteArray data = null;
-    public @Nullable ChunkNibbleArray skylightMap = null;
-    public @Nullable ChunkNibbleArray blocklightMap = null;
+    public byte @Nullable [] lightData = null;
     public byte @NotNull [] biome = new byte[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z * (SECTION_SIZE_Y >> 3)];
     public @NotNull List<@NotNull Entity> entities = new ArrayList<>();
 
@@ -41,8 +40,7 @@ public class ChunkSection {
 
     public void init() {
         this.data = new ChunkUnsignedByteArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-        this.skylightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-        this.blocklightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
+        this.lightData = new byte[Chunk.CHUNK_SIZE_X * SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z];
         Arrays.fill(this.biome, (byte) -1);
     }
 
@@ -78,8 +76,6 @@ public class ChunkSection {
     }
 
     public void setBlockId(final @NotNull ChunkSectionTilePosc sectionPos, final int id) {
-        assert Blocks.getBlock(id) != null;
-
         if (!sectionPos.inBounds() || (this.blocks == null && id == Blocks.AIR.id())) {
             return;
         } else if (this.blocks == null) {
@@ -158,25 +154,18 @@ public class ChunkSection {
         this.setBiome(new ChunkSectionTilePos(x, y, z), biome);
     }
 
-    public int getBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkSectionTilePosc sectionPos) {
+    public int getLightLevel(final @NotNull LightLayer lightLayer, final @NotNull ChunkSectionTilePosc sectionPos) {
         if (!sectionPos.inBounds()) {
             return 0;
         }
 
+        if (this.lightData == null) return 0;
         switch (lightLayer) {
             case Sky -> {
-                if (this.skylightMap == null) {
-                    return 0;
-                }
-
-                return this.skylightMap.get(sectionPos.x(), sectionPos.y(), sectionPos.z());
+                return LightIndexHelper.skyLightFromIndex(this.lightData[makeBlockIndex(sectionPos)]);
             }
             case Block -> {
-                if (this.blocklightMap == null) {
-                    return 0;
-                }
-
-                return this.blocklightMap.get(sectionPos.x(), sectionPos.y(), sectionPos.z());
+                return LightIndexHelper.blockLightFromIndex(this.lightData[makeBlockIndex(sectionPos)]);
             }
             default -> {
                 return 0;
@@ -184,50 +173,51 @@ public class ChunkSection {
         }
     }
 
+    public byte getLightIndex(final @NotNull ChunkSectionTilePosc sectionPos) {
+        if (!sectionPos.inBounds()) {
+            return 0;
+        }
+        if (this.lightData == null) return 0;
+        return this.lightData[makeBlockIndex(sectionPos)];
+    }
+
     @Deprecated
     public int getBrightness(final @NotNull LightLayer lightLayer, final int x, final int y, final int z) {
-        return this.getBrightness(lightLayer, new ChunkSectionTilePos(x, y, z));
+        return this.getLightLevel(lightLayer, new ChunkSectionTilePos(x, y, z));
     }
 
-    public void setBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkSectionTilePosc sectionPos, final int brightness) {
+    public void setLightLevel(final @NotNull LightLayer lightLayer, final @NotNull ChunkSectionTilePosc sectionPos, final int brightness) {
         if (!sectionPos.inBounds()) {
             return;
         }
 
-        switch (lightLayer) {
-            case Sky -> {
-                if (this.skylightMap == null) {
-                    this.skylightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-                }
-
-                this.skylightMap.set(sectionPos.x(), sectionPos.y(), sectionPos.z(), brightness);
-            }
-            case Block -> {
-                if (this.blocklightMap == null) {
-                    this.blocklightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-                }
+        if (this.lightData == null) {
+            this.lightData = new byte[Chunk.CHUNK_SIZE_X * SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z];
+        }
 
-                this.blocklightMap.set(sectionPos.x(), sectionPos.y(), sectionPos.z(), brightness);
-            }
+        int index = makeBlockIndex(sectionPos);
+        switch (lightLayer) {
+            case Sky -> this.lightData[index] = LightIndexHelper.setSkyLight(this.lightData[index], brightness);
+            case Block -> this.lightData[index] = LightIndexHelper.setBlockLight(this.lightData[index], brightness);
         }
     }
 
     @Deprecated
     public void setBrightness(final @NotNull LightLayer lightLayer, final int x, final int y, final int z, final int brightness) {
-        this.setBrightness(lightLayer, new ChunkSectionTilePos(x, y, z), brightness);
+        this.setLightLevel(lightLayer, new ChunkSectionTilePos(x, y, z), brightness);
     }
 
-    public int getRawBrightness(final @NotNull ChunkSectionTilePosc sectionPos, final int subtractedSkyLight) {
+    public int getRawSkyLightLevel(final @NotNull ChunkSectionTilePosc sectionPos, final int subtractedSkyLight) {
         if (!sectionPos.inBounds()) {
             return 0;
         }
 
-        return Math.max(this.getBrightness(LightLayer.Sky, sectionPos) - subtractedSkyLight, this.getBrightness(LightLayer.Block, sectionPos));
+        return Math.max(this.getLightLevel(LightLayer.Sky, sectionPos) - subtractedSkyLight, this.getLightLevel(LightLayer.Block, sectionPos));
     }
 
     @Deprecated
     public int getRawBrightness(final int x, final int y, final int z, final int subtractedSkyLight) {
-        return this.getRawBrightness(new ChunkSectionTilePos(x, y, z), subtractedSkyLight);
+        return this.getRawSkyLightLevel(new ChunkSectionTilePos(x, y, z), subtractedSkyLight);
     }
 
     public void addEntity(final @NotNull Entity entity) {
@@ -314,42 +304,23 @@ public class ChunkSection {
             }
         }
 
-        // Read skylight
-        if (data[startIndex++] == 1) {
-            if (this.skylightMap == null || this.skylightMap.data == null) {
-                this.skylightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-            }
-
-            for (int cy = minY; cy < maxY; cy++) {
-                for (int cz = minZ; cz < maxZ; cz++) {
-                    int cIndex = makeBlockIndex(minX, cy, cz) / 2;
-                    System.arraycopy(data, startIndex, this.skylightMap.data, cIndex, xSize / 2);
-                    startIndex += xSize / 2;
-                }
-            }
-        }
-
-        // Read blocklight
+        // Read LightData
         if (data[startIndex++] == 1) {
-            if (this.blocklightMap == null || this.blocklightMap.data == null) {
-                this.blocklightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
+            if (this.lightData == null) {
+                this.lightData = new byte[Chunk.CHUNK_SIZE_X * SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z];
             }
 
             for (int cy = minY; cy < maxY; cy++) {
                 for (int cz = minZ; cz < maxZ; cz++) {
-                    int cIndex = makeBlockIndex(minX, cy, cz) / 2;
-                    System.arraycopy(data, startIndex, this.blocklightMap.data, cIndex, xSize / 2);
-                    startIndex += xSize / 2;
+                    int cIndex = makeBlockIndex(minX, cy, cz);
+                    System.arraycopy(data, startIndex, this.lightData, cIndex, xSize);
+                    startIndex += xSize;
                 }
             }
         }
 
         // Read biomes
         if (data[startIndex++] == 1) {
-            if (this.biome == null) {
-                this.biome = new byte[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z * (SECTION_SIZE_Y >> 3)];
-            }
-
             for (int cy = minY >> 3; cy < maxY >> 3; cy++) {
                 for (int cz = minZ; cz < maxZ; cz++) {
                     int cIndex = makeBlockIndex(minX, cy, cz);
@@ -393,32 +364,19 @@ public class ChunkSection {
                 data[startIndex++] = 0;
             }
 
-            // Write skylight
-            if (this.skylightMap != null && this.skylightMap.isValid() && this.skylightMap.data != null) {
-                data[startIndex++] = 1;
-                System.arraycopy(this.skylightMap.data, 0, data, startIndex, this.skylightMap.data.length);
-                startIndex += this.skylightMap.data.length;
-            } else {
-                data[startIndex++] = 0;
-            }
-
-            // Write blocklight
-            if (this.blocklightMap != null && this.blocklightMap.isValid() && this.blocklightMap.data != null) {
+            // Write lightData
+            if (this.lightData != null) {
                 data[startIndex++] = 1;
-                System.arraycopy(this.blocklightMap.data, 0, data, startIndex, this.blocklightMap.data.length);
-                startIndex += this.blocklightMap.data.length;
+                System.arraycopy(this.lightData, 0, data, startIndex, this.lightData.length);
+                startIndex += this.lightData.length;
             } else {
                 data[startIndex++] = 0;
             }
 
             // Write biomes
-            if (this.biome != null) {
-                data[startIndex++] = 1;
-                System.arraycopy(this.biome, 0, data, startIndex, this.biome.length);
-                startIndex += this.biome.length;
-            } else {
-                data[startIndex++] = 0;
-            }
+            data[startIndex++] = 1;
+            System.arraycopy(this.biome, 0, data, startIndex, this.biome.length);
+            startIndex += this.biome.length;
         } else {
             // Write blocks
             if (this.blocks != null) {
@@ -448,28 +406,14 @@ public class ChunkSection {
                 data[startIndex++] = 0;
             }
 
-            // Write skylight
-            if (this.skylightMap != null && this.skylightMap.isValid() && this.skylightMap.data != null) {
-                data[startIndex++] = 1;
-                for (int cy = minY; cy < maxY; cy++) {
-                    for (int cz = minZ; cz < maxZ; cz++) {
-                        int cIndex = makeBlockIndex(minX, cy, cz) / 2;
-                        System.arraycopy(this.skylightMap.data, cIndex, data, startIndex, xSize / 2);
-                        startIndex += xSize / 2;
-                    }
-                }
-            } else {
-                data[startIndex++] = 0;
-            }
-
-            // Write blocklight
-            if (this.blocklightMap != null && this.blocklightMap.isValid() && this.blocklightMap.data != null) {
+            // Write light data
+            if (this.lightData != null) {
                 data[startIndex++] = 1;
                 for (int cy = minY; cy < maxY; cy++) {
                     for (int cz = minZ; cz < maxZ; cz++) {
-                        int cIndex = makeBlockIndex(minX, cy, cz) / 2;
-                        System.arraycopy(this.blocklightMap.data, cIndex, data, startIndex, xSize / 2);
-                        startIndex += xSize / 2;
+                        int cIndex = makeBlockIndex(minX, cy, cz);
+                        System.arraycopy(this.lightData, cIndex, data, startIndex, xSize);
+                        startIndex += xSize;
                     }
                 }
             } else {
@@ -477,17 +421,13 @@ public class ChunkSection {
             }
 
             // Write biomes
-            if (this.biome != null) {
-                data[startIndex++] = 1;
-                for (int cy = minY >> 3; cy < maxY >> 3; cy++) {
-                    for (int cz = minZ; cz < maxZ; cz++) {
-                        int cIndex = makeBlockIndex(minX, cy, cz);
-                        System.arraycopy(this.biome, cIndex, data, startIndex, xSize);
-                        startIndex += xSize;
-                    }
+            data[startIndex++] = 1;
+            for (int cy = minY >> 3; cy < maxY >> 3; cy++) {
+                for (int cz = minZ; cz < maxZ; cz++) {
+                    int cIndex = makeBlockIndex(minX, cy, cz);
+                    System.arraycopy(this.biome, cIndex, data, startIndex, xSize);
+                    startIndex += xSize;
                 }
-            } else {
-                data[startIndex++] = 0;
             }
         }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java
index 125eebb7a..bf17d9bf7 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java
@@ -44,7 +44,7 @@ public class DisplayChunk extends EmptyChunk{
     }
 
     @Override
-    public int getBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos) {
+    public int getLightLevel(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos) {
         return 15;
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
index 3b5134788..102286a8c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
@@ -63,15 +63,15 @@ public class EmptyChunk extends Chunk {
     }
 
     @Override
-    public int getBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos) {
+    public int getLightLevel(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos) {
         return 0;
     }
 
     @Override
-    public void setBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos, final int value) { }
+    public void setLightLevel(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePosc tilePos, final int value) { }
 
     @Override
-    public int getRawBrightness(final @NotNull ChunkTilePosc tilePos, final int subtractedSkyLight) {
+    public int getRawSkyLightLevel(final @NotNull ChunkTilePosc tilePos, final int subtractedSkyLight) {
         return 0;
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderLegacy.java b/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderLegacy.java
index ba7343ad4..6085e74d0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderLegacy.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderLegacy.java
@@ -2,7 +2,6 @@ package net.minecraft.core.world.chunk.reader;
 
 import com.mojang.nbt.tags.CompoundTag;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
 import net.minecraft.core.NextTickListEntry;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.Chunk;
@@ -12,8 +11,6 @@ import net.minecraft.core.world.data.ChunkUnsignedByteArray;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Map;
-
 public class ChunkReaderLegacy
     extends ChunkReader
 {
@@ -36,22 +33,22 @@ public class ChunkReaderLegacy
     {
         super(world, tag);
 
-        blocks = tag.getShortArrayOrDefault("Blocks", null);
-        data = tag.getByteArrayOrDefault("Data", null);
-        skylight = tag.getByteArrayOrDefault("SkyLight", null);
-        blocklight = tag.getByteArrayOrDefault("BlockLight", null);
+        this.blocks = tag.getShortArrayOrDefault("Blocks", null);
+        this.data = tag.getByteArrayOrDefault("Data", null);
+        this.skylight = tag.getByteArrayOrDefault("SkyLight", null);
+        this.blocklight = tag.getByteArrayOrDefault("BlockLight", null);
     }
 
     @Override
     public int getX()
     {
-        return tag.getInteger("xPos");
+        return this.tag.getInteger("xPos");
     }
 
     @Override
     public int getZ()
     {
-        return tag.getInteger("zPos");
+        return this.tag.getInteger("zPos");
     }
 
     @Override
@@ -65,7 +62,7 @@ public class ChunkReaderLegacy
     {
         short[] newBlocks = new short[Chunk.CHUNK_SIZE_X * ChunkSection.SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z];
 
-        if (blocks != null && makeBlockIndex(15, (ySection * ChunkSection.SECTION_SIZE_Y) + 15, 15) < blocks.length) {
+        if (this.blocks != null && makeBlockIndex(15, (ySection * ChunkSection.SECTION_SIZE_Y) + 15, 15) < this.blocks.length) {
             for (int x = 0; x < 16; x++) {
                 for (int z = 0; z < 16; z++) {
                     for (int y = 0; y < 16; y++) {
@@ -86,7 +83,7 @@ public class ChunkReaderLegacy
         byte[] newData = new byte[Chunk.CHUNK_SIZE_X * ChunkSection.SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z];
         ChunkUnsignedByteArray array = new ChunkUnsignedByteArray(Chunk.CHUNK_SIZE_X, ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, newData);
 
-        if (data != null && makeBlockIndex(15, (ySection * ChunkSection.SECTION_SIZE_Y) + 15, 15) < data.length) {
+        if (this.data != null && makeBlockIndex(15, (ySection * ChunkSection.SECTION_SIZE_Y) + 15, 15) < this.data.length) {
             for (int x = 0; x < 16; x++) {
                 for (int z = 0; z < 16; z++) {
                     for (int y = 0; y < 16; y++) {
@@ -102,12 +99,12 @@ public class ChunkReaderLegacy
     }
 
     @Override
-    public @NotNull ChunkNibbleArray getSkyLight(int ySection)
+    public @Nullable ChunkNibbleArray getSkyLight(int ySection)
     {
         byte[] newSkyLight = new byte[(Chunk.CHUNK_SIZE_X * ChunkSection.SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z) >> 1];
         ChunkNibbleArray array = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, newSkyLight);
 
-        if (skylight != null && makeNibbleIndex(15, (ySection * ChunkSection.SECTION_SIZE_Y) + 15, 15) < skylight.length * 2) {
+        if (this.skylight != null && makeNibbleIndex(15, (ySection * ChunkSection.SECTION_SIZE_Y) + 15, 15) < this.skylight.length * 2) {
             for (int x = 0; x < 16; x++) {
                 for (int z = 0; z < 16; z++) {
                     for (int y = 0; y < 16; y++) {
@@ -117,9 +114,9 @@ public class ChunkReaderLegacy
                         int nibblePart = index & 0x01;
                         int nibble;
                         if (nibblePart == 0) {
-                            nibble = Byte.toUnsignedInt(skylight[nibbleIndex]) & 0x0F;
+                            nibble = Byte.toUnsignedInt(this.skylight[nibbleIndex]) & 0x0F;
                         } else {
-                            nibble = (Byte.toUnsignedInt(skylight[nibbleIndex]) >> 4) & 0x0F;
+                            nibble = (Byte.toUnsignedInt(this.skylight[nibbleIndex]) >> 4) & 0x0F;
                         }
                         array.set(x, y, z, nibble);
                     }
@@ -131,12 +128,12 @@ public class ChunkReaderLegacy
     }
 
     @Override
-    public @NotNull ChunkNibbleArray getBlockLight(int ySection)
+    public @Nullable ChunkNibbleArray getBlockLight(int ySection)
     {
         byte[] newBlockLight = new byte[(Chunk.CHUNK_SIZE_X * ChunkSection.SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z) >> 1];
         ChunkNibbleArray array = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, newBlockLight);
 
-        if (blocklight != null && makeNibbleIndex(15, (ySection * ChunkSection.SECTION_SIZE_Y) + 15, 15) < blocklight.length * 2) {
+        if (this.blocklight != null && makeNibbleIndex(15, (ySection * ChunkSection.SECTION_SIZE_Y) + 15, 15) < this.blocklight.length * 2) {
             for (int x = 0; x < 16; x++) {
                 for (int z = 0; z < 16; z++) {
                     for (int y = 0; y < 16; y++) {
@@ -146,9 +143,9 @@ public class ChunkReaderLegacy
                         int nibblePart = index & 0x01;
                         int nibble;
                         if (nibblePart == 0) {
-                            nibble = Byte.toUnsignedInt(blocklight[nibbleIndex]) & 0x0F;
+                            nibble = Byte.toUnsignedInt(this.blocklight[nibbleIndex]) & 0x0F;
                         } else {
-                            nibble = (Byte.toUnsignedInt(blocklight[nibbleIndex]) >> 4) & 0x0F;
+                            nibble = (Byte.toUnsignedInt(this.blocklight[nibbleIndex]) >> 4) & 0x0F;
                         }
                         array.set(x, y, z, nibble);
                     }
@@ -162,7 +159,7 @@ public class ChunkReaderLegacy
     @Override
     public short @NotNull [] getHeightMap()
     {
-        return tag.getShortArrayOrDefault("HeightMap", null);
+        return this.tag.getShortArrayOrDefault("HeightMap", null);
     }
 
     @Override
@@ -175,7 +172,7 @@ public class ChunkReaderLegacy
     @Override
     public boolean getIsTerrainPopulated()
     {
-        return tag.getBoolean("TerrainPopulated");
+        return this.tag.getBoolean("TerrainPopulated");
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion1.java b/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion1.java
index 814e18d21..5de21fa4d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion1.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion1.java
@@ -2,7 +2,6 @@ package net.minecraft.core.world.chunk.reader;
 
 import com.mojang.nbt.tags.CompoundTag;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
 import net.minecraft.core.NextTickListEntry;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.Registry;
@@ -14,8 +13,6 @@ import net.minecraft.core.world.data.ChunkUnsignedByteArray;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Map;
-
 public class ChunkReaderVersion1
     extends ChunkReader {
     private final short[] blocks;
@@ -102,7 +99,7 @@ public class ChunkReaderVersion1
     }
 
     @Override
-    public @NotNull ChunkNibbleArray getSkyLight(final int ySection) {
+    public @Nullable ChunkNibbleArray getSkyLight(final int ySection) {
         final byte[] newSkyLight = new byte[(Chunk.CHUNK_SIZE_X * ChunkSection.SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z) >> 1];
         final ChunkNibbleArray array = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, newSkyLight);
 
@@ -130,7 +127,7 @@ public class ChunkReaderVersion1
     }
 
     @Override
-    public @NotNull ChunkNibbleArray getBlockLight(final int ySection) {
+    public @Nullable ChunkNibbleArray getBlockLight(final int ySection) {
         final byte[] newBlockLight = new byte[(Chunk.CHUNK_SIZE_X * ChunkSection.SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z) >> 1];
         final ChunkNibbleArray array = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, newBlockLight);
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion2.java b/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion2.java
index 4de091930..d7b8f5f06 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion2.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion2.java
@@ -4,7 +4,6 @@ import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.tags.ListTag;
 import com.mojang.nbt.tags.Tag;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
 import net.minecraft.core.NextTickListEntry;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.Registry;
@@ -17,7 +16,6 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Arrays;
-import java.util.Map;
 
 public class ChunkReaderVersion2
     extends ChunkReader {
@@ -86,7 +84,7 @@ public class ChunkReaderVersion2
     }
 
     @Override
-    public @NotNull ChunkNibbleArray getSkyLight(int ySection) {
+    public @Nullable ChunkNibbleArray getSkyLight(int ySection) {
         byte[] skylight = null;
         CompoundTag sectionTag = findSection(ySection);
         if (sectionTag != null) {
@@ -101,7 +99,7 @@ public class ChunkReaderVersion2
     }
 
     @Override
-    public @NotNull ChunkNibbleArray getBlockLight(int ySection) {
+    public @Nullable ChunkNibbleArray getBlockLight(int ySection) {
         byte[] blocklight = null;
         CompoundTag sectionTag = findSection(ySection);
         if (sectionTag != null) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion3.java b/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion3.java
index e4e790f6a..ac9fb11da 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion3.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/reader/ChunkReaderVersion3.java
@@ -5,8 +5,6 @@ import com.mojang.nbt.tags.ListTag;
 import com.mojang.nbt.tags.Tag;
 import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectArrayMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
 import net.minecraft.core.NextTickListEntry;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.Registry;
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/writer/ChunkWriter.java b/game/core/src/main/java/net/minecraft/core/world/chunk/writer/ChunkWriter.java
index 6298ae49a..babe967bf 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/writer/ChunkWriter.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/writer/ChunkWriter.java
@@ -8,7 +8,6 @@ import net.minecraft.core.NextTickListEntry;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.Registry;
 import net.minecraft.core.world.World;
-import net.minecraft.core.world.data.ChunkNibbleArray;
 import net.minecraft.core.world.data.ChunkUnsignedByteArray;
 import org.jetbrains.annotations.NotNull;
 
@@ -73,14 +72,14 @@ public class ChunkWriter
         findSection(ySection).putByteArray("Data", data.data);
     }
 
-    public void putSkyLight(int ySection, ChunkNibbleArray skyLight)
+    public void putSkyLight(int ySection, byte[] skyLightData)
     {
-        findSection(ySection).putByteArray("SkyLight", skyLight.data);
+        findSection(ySection).putByteArray("SkyLight", skyLightData);
     }
 
-    public void putBlockLight(int ySection, ChunkNibbleArray blockLight)
+    public void putBlockLight(int ySection, byte[] blockLightData)
     {
-        findSection(ySection).putByteArray("BlockLight", blockLight.data);
+        findSection(ySection).putByteArray("BlockLight", blockLightData);
     }
 
     public void putHeightMap(short[] heightMap)
diff --git a/game/core/src/main/java/net/minecraft/core/world/lighting/LightingEngineLegacy.java b/game/core/src/main/java/net/minecraft/core/world/lighting/LightingEngineLegacy.java
index 4290a2082..534e8f367 100644
--- a/game/core/src/main/java/net/minecraft/core/world/lighting/LightingEngineLegacy.java
+++ b/game/core/src/main/java/net/minecraft/core/world/lighting/LightingEngineLegacy.java
@@ -6,15 +6,12 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.Chunk;
-import net.minecraft.core.world.pos.ChunkPos;
-import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
-import java.util.LinkedList;
 import java.util.List;
 
-import static net.minecraft.core.world.World.MAX_BRIGHTNESS;
+import static net.minecraft.core.world.World.MAX_LIGHT_LEVEL;
 
 public class LightingEngineLegacy implements LightingEngine {
     private static final Logger LOGGER = LogUtils.getLogger();
@@ -188,7 +185,7 @@ public class LightingEngineLegacy implements LightingEngine {
                         {
                             if(world.canExistingBlockSeeTheSky(x, y, z))
                             {
-                                blockLightValue = MAX_BRIGHTNESS;
+                                blockLightValue = MAX_LIGHT_LEVEL;
                             }
                         }
                         else if(this.layer == LightLayer.Block)
@@ -196,7 +193,7 @@ public class LightingEngineLegacy implements LightingEngine {
                             blockLightValue = Blocks.lightEmission[blockId];
                         }
 
-                        if(blockLightOpacity >= MAX_BRIGHTNESS && blockLightValue == 0)
+                        if(blockLightOpacity >= MAX_LIGHT_LEVEL && blockLightValue == 0)
                         {
                             newLightValue = 0;
                         }
@@ -291,7 +288,7 @@ public class LightingEngineLegacy implements LightingEngine {
             {
                 if(world.canExistingBlockSeeTheSky(x, y, z))
                 {
-                    lightValue = MAX_BRIGHTNESS;
+                    lightValue = MAX_LIGHT_LEVEL;
                 }
             }
             else if(lightLayer == LightLayer.Block)
