diff --git a/game/client/.gitignore b/game/client/.gitignore
index 4f654f768..cc46de012 100644
--- a/game/client/.gitignore
+++ b/game/client/.gitignore
@@ -1,3 +1,3 @@
 build
-dumpTextures
+/dumpTextures/
 logs
\ No newline at end of file
diff --git a/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java b/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java
index 32c65adac..9123e41e6 100644
--- a/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java
+++ b/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java
@@ -118,8 +118,8 @@ public class DataDumper implements MinecraftAccessor {
                 .append(item.getMaxDamage()).append(",")
                 .append(item instanceof ItemFood ? ((ItemFood) item).getHealAmount() : "").append(",")
                 .append(item.getItemStackLimit(null)).append(",")
-                .append("\"").append(translator.translateNameKey(item.getKey())).append("\"").append(",")
-                .append("\"").append(translator.translateDescKey(item.getKey())).append("\"").append(",");
+                .append("\"").append(translator.translateKey(item.getKey() + ".name")).append("\"").append(",")
+                .append("\"").append(translator.translateKey(item.getKey() + ".desc")).append("\"").append(",");
         builder.append("\"").append(taglistString(ItemTags.TAG_LIST, item)).append("\"");
         builder.append("\n");
         return builder.toString();
@@ -134,8 +134,8 @@ public class DataDumper implements MinecraftAccessor {
                 .append(block.getBlastResistance(null)).append(",")
                 .append(ItemToolPickaxe.miningLevels.getOrDefault(block, 0)).append(",")
                 .append(block.asItem().getItemStackLimit(null)).append(",")
-                .append("\"").append(translator.translateNameKey(block.getKey())).append("\"").append(",")
-                .append("\"").append(translator.translateDescKey(block.getKey())).append("\"").append(",");
+                .append("\"").append(translator.translateKey(block.getKey() + ".name")).append("\"").append(",")
+                .append("\"").append(translator.translateKey(block.getKey() + ".desc")).append("\"").append(",");
         builder.append("\"").append(taglistString(BlockTags.TAG_LIST, block)).append("\"");
         builder.append("\n");
         return builder.toString();
@@ -155,7 +155,7 @@ public class DataDumper implements MinecraftAccessor {
 
         StringBuilder weatherString = new StringBuilder();
         for (Weather weather : biome.blockedWeathers){
-            weatherString.append(weather.languageKey).append(", ");
+            weatherString.append(weather.getLanguageKey()).append(", ");
         }
         String s = weatherString.toString().trim();
         if (!s.isEmpty()){
diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java
index 13500a906..967c41a63 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -29,6 +29,7 @@ import net.minecraft.client.gui.options.data.OptionsPages;
 import net.minecraft.client.gui.toasts.GuiElementToastsHud;
 import net.minecraft.client.holiday.Holidays;
 import net.minecraft.client.net.handler.PacketHandlerClient;
+import net.minecraft.client.render.block.model.BlockModelGrass;
 import net.minecraft.client.world.WorldClient;
 import net.minecraft.client.world.chunk.provider.ChunkProviderStatic;
 import net.minecraft.core.achievement.Achievements;
@@ -113,7 +114,6 @@ import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.LoadingScreenRenderer;
 import net.minecraft.client.render.OpenGLHelper;
 import net.minecraft.client.render.PostProcessingManager;
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.RenderGlobal;
 import net.minecraft.client.render.Renderer;
@@ -280,10 +280,35 @@ public class Minecraft
     private boolean gameStarted = false;
     private int mojrand = new Random(System.currentTimeMillis()).nextInt(200);
     public TerrainRenderer terrainRenderer;
-    
-    public Minecraft(GameWindow gameWindow)
+
+    /**
+     * Keep this as the only constructor in this class for now,
+     * otherwise JVM class verification will fail and the game will crash when the fabric loader tries to run the game.
+     */
+    public Minecraft(GameWindow gameWindow, boolean test)
     {
-        this();
+        Global.accessor = this;
+        hasCrashed = false;
+        timer = new Timer(Global.TICKS_PER_SECOND);
+        session = null;
+        hideQuitButton = false;
+        isGamePaused = false;
+        currentScreen = null;
+        ticksRan = 0;
+        skipRenderWorld = false;
+        objectMouseOver = null;
+        running = true;
+        debug = "";
+        isTakingScreenshot = false;
+        inGameHasFocus = false;
+        mouseTicksRan = 0;
+        isRaining = false;
+        systemTime = System.currentTimeMillis();
+        joinPlayerCounter = 0;
+        INSTANCE = this;
+
+        if(test) return;
+
         this.gameWindow = gameWindow;
         this.resolution = new ScaledResolution(this.gameWindow);
 
@@ -310,27 +335,6 @@ public class Minecraft
             }
         };
     }
-    public Minecraft() {
-        Global.accessor = this;
-        hasCrashed = false;
-        timer = new Timer(Global.TICKS_PER_SECOND);
-        session = null;
-        hideQuitButton = false;
-        isGamePaused = false;
-        currentScreen = null;
-        ticksRan = 0;
-        skipRenderWorld = false;
-        objectMouseOver = null;
-        running = true;
-        debug = "";
-        isTakingScreenshot = false;
-        inGameHasFocus = false;
-        mouseTicksRan = 0;
-        isRaining = false;
-        systemTime = System.currentTimeMillis();
-        joinPlayerCounter = 0;
-        INSTANCE = this;
-    }
 
     public static boolean isClientASteamDeck() {
         final File vendor = new File("/sys/devices/virtual/dmi/id/board_vendor");
@@ -1035,7 +1039,7 @@ public class Minecraft
                     Debug.push("misc");		// 2
 
                     OpenGLHelper.checkError("pre render");
-                    RenderBlocks.fancyGrass = gameSettings.fancyGraphics.value == 1;
+                    BlockModelGrass.fancyGrass = gameSettings.fancyGraphics.value == 1;
                     EntityItem.enableItemClumping = gameSettings.enableItemClumping.value;
                     BlockLogicLeavesBase.enableTreeShadowing = gameSettings.treeShadows.value;
                     sndManager.updateListener(thePlayer, timer.partialTicks);
@@ -2623,7 +2627,7 @@ public class Minecraft
     public static void startMainThread(@Nullable String username, @Nullable String sessionId, @Nullable String uuid, @Nullable String server, @Nullable Integer port, @Nullable Integer width, @Nullable Integer height)
     {
         GameWindow gameWindow = new GameWindowGLFW();
-        Minecraft mc = new Minecraft(gameWindow);
+        Minecraft mc = new Minecraft(gameWindow,false);
         mc.minecraftUri = "www.minecraft.net";
 
         sessionId = sessionId == null ? "" : sessionId;
diff --git a/game/client/src/main/java/net/minecraft/client/console/shell/commands/fields.java b/game/client/src/main/java/net/minecraft/client/console/shell/commands/fields.java
index 0f76393c2..d15a62a93 100644
--- a/game/client/src/main/java/net/minecraft/client/console/shell/commands/fields.java
+++ b/game/client/src/main/java/net/minecraft/client/console/shell/commands/fields.java
@@ -12,6 +12,9 @@ import java.lang.reflect.Modifier;
 
 public class fields {
     public static RawOutputWrapper invoke(Interpreter env, CallStack callstack, Object o) {
+        if (o == null) {
+            return new RawOutputWrapper(TextFormatting.RED + "Argument was null!");
+        }
         final Class<?> clazz = o.getClass();
         StringBuilder sb = new StringBuilder();
         Field[] fields = clazz.getFields();
@@ -78,8 +81,8 @@ public class fields {
 
     private static void appendObject(Field field, Object o, StringBuilder sb) {
         try {
-            final @Nullable Object v = field.get(null);
-            if (o instanceof String) {
+            final @Nullable Object v = field.get(o);
+            if (v instanceof String) {
                 sb
                     .append(TextFormatting.LIGHT_BLUE)
                     .append("\"")
diff --git a/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleBlockBreaking.java b/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleBlockBreaking.java
index 4b6db2647..230b9486e 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleBlockBreaking.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleBlockBreaking.java
@@ -27,8 +27,9 @@ public class ParticleBlockBreaking extends Particle {
     public ParticleBlockBreaking init(int x, int y, int z) {
         int meta = this.world.getBlockMetadata(x, y, z);
         BlockModel<?> model = BlockModelDispatcher.getInstance().getDispatch(this.block);
-        if (model.shouldSideBeColored(this.world, x, y, z, this.side.getId(), meta)) {
-            int col = BlockColorDispatcher.getInstance().getDispatch(this.block).getWorldColor(this.world, x, y, z);
+        int index = model.particleColorIndex(this.world, x, y, z, this.side, meta);
+        if (index >= 0) {
+            int col = BlockColorDispatcher.getInstance().getDispatch(this.block).getWorldColor(this.world, x, y, z, index);
             this.rCol *= (col >> 16 & 0xff) / 255F;
             this.gCol *= (col >> 8 & 0xff) / 255F;
             this.bCol *= (col & 0xff) / 255F;
diff --git a/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleDispatcher.java b/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleDispatcher.java
index 79b564dad..b5e5a9eb9 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleDispatcher.java
@@ -4,12 +4,10 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.util.dispatch.Dispatcher;
-import net.minecraft.core.Global;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.animal.MobFireflyCluster;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.Items;
-import net.minecraft.core.net.command.arguments.ArgumentTypeParticleId;
 import net.minecraft.core.util.helper.BlockParticleHelper;
 import net.minecraft.core.util.helper.MathHelper;
 
@@ -73,7 +71,7 @@ public final class ParticleDispatcher extends Dispatcher<String, ParticleLambda>
             return null;
         });
         addDispatch("dripWater", (world, x, y, z, motionX, motionY, motionZ, data) -> {
-            int color = BlockColorDispatcher.getInstance().getDispatch(Blocks.FLUID_WATER_STILL).getWorldColor(world, MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z));
+            int color = BlockColorDispatcher.getInstance().getDispatch(Blocks.FLUID_WATER_STILL).getWorldColor(world, MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z), 0);
             return new ParticleFluidDrip(world, x, y, z, color, TextureRegistry.getTexture("minecraft:block/water_flowing"));
         });
         addDispatch("dripLava", (world, x, y, z, motionX, motionY, motionZ, data) -> new ParticleFluidDrip(world, x, y, z, 0xFFFFFF, TextureRegistry.getTexture("minecraft:block/lava_flowing")).setFullBright());
diff --git a/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleLeaf.java b/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleLeaf.java
index ed41e9f14..9a7cabea4 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleLeaf.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/particle/ParticleLeaf.java
@@ -30,7 +30,7 @@ public class ParticleLeaf extends Particle {
     public ParticleLeaf init(int x, int y, int z) {
         Block<?> block = Blocks.blocksList[this.world.getBlockId(x, y, z)];
         if (!Block.hasLogicClass(block, BlockLogicLeavesBase.class)) this.remove();
-        int col = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(world, x, y, z);
+        int col = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(world, x, y, z, 0);
         this.rCol *= (float) (col >> 16 & 0xff) / 255F;
         this.gCol *= (float) (col >> 8 & 0xff) / 255F;
         this.bCol *= (float) (col & 0xff) / 255F;
diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
index a85d80004..a1d134c22 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
@@ -39,7 +39,6 @@ import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.vehicle.EntityBoat;
-import net.minecraft.core.entity.vehicle.MobGhastVehicle;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.client.net.command.ClientCommandSource;
@@ -70,7 +69,9 @@ public class PlayerLocal extends Player
         this.dimension = dimension;
         username = session.username;
         uuid = session.uuid;
-        
+
+        playerConfig.setLeftHand(minecraft.gameSettings.playerLeftHanded.value);
+
         new GetSkinUrlThread(this);
         LOGGER.info("logged in with session name: {}", username);
     }
@@ -263,15 +264,15 @@ public class PlayerLocal extends Player
     }
 
     @Override
-    public void displaySignEditorScreen(TileEntitySign blockEntity)
+    public void displaySignEditorScreen(TileEntitySign tileEntity)
     {
-        mc.displayScreen(new ScreenSignEditor(blockEntity));
+        mc.displayScreen(new ScreenSignEditor(tileEntity));
     }
 
     @Override
-    public void displayFlagEditorScreen(TileEntityFlag blockEntity)
+    public void displayFlagEditorScreen(TileEntityFlag tileEntity)
     {
-        mc.displayScreen(new ScreenFlagEditor(this, blockEntity));
+        mc.displayScreen(new ScreenFlagEditor(this, tileEntity));
     }
 
     @Override
@@ -300,7 +301,7 @@ public class PlayerLocal extends Player
 
     @Override
     public void displayMobPickerScreen(int x, int y, int z) {
-        String currentMobId = ((TileEntityMobSpawner) world.getBlockEntity(x, y, z)).getMobId();
+        String currentMobId = ((TileEntityMobSpawner) world.getTileEntity(x, y, z)).getMobId();
         mc.displayScreen(new ScreenMobPicker(currentMobId, x, y, z));
     }
     @Override
@@ -310,27 +311,27 @@ public class PlayerLocal extends Player
     }
 
     @Override
-    public void displayFurnaceScreen(TileEntityFurnace blockEntity)
+    public void displayFurnaceScreen(TileEntityFurnace tileEntity)
     {
-        mc.displayScreen(new ScreenFurnace(inventory, blockEntity));
+        mc.displayScreen(new ScreenFurnace(inventory, tileEntity));
     }
 
     @Override
-    public void displayTrommelScreen(TileEntityTrommel blockEntity)
+    public void displayTrommelScreen(TileEntityTrommel tileEntity)
     {
-        mc.displayScreen(new ScreenTrommel(inventory, blockEntity));
+        mc.displayScreen(new ScreenTrommel(inventory, tileEntity));
     }
 
     @Override
-    public void displayDispenserScreen(TileEntityDispenser blockEntity)
+    public void displayDispenserScreen(TileEntityDispenser tileEntity)
     {
-        mc.displayScreen(new ScreenDispenser(inventory, blockEntity));
+        mc.displayScreen(new ScreenDispenser(inventory, tileEntity));
     }
 
     @Override
-    public void displayActivatorScreen(TileEntityActivator blockEntity)
+    public void displayActivatorScreen(TileEntityActivator tileEntity)
     {
-        mc.displayScreen(new ScreenActivator(inventory, blockEntity));
+        mc.displayScreen(new ScreenActivator(inventory, tileEntity));
     }
 
     @Override
@@ -532,8 +533,5 @@ public class PlayerLocal extends Player
         if (vehicle instanceof EntityBoat) {
             ((EntityBoat) vehicle).controlBoat(-input.moveForward, -input.moveStrafe);
         }
-        if (vehicle instanceof MobGhastVehicle) {
-            ((MobGhastVehicle) vehicle).controlVehicle(-input.moveForward, -input.moveStrafe, input.jump, input.sneak);
-        }
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java
index 765a860fc..1f68a30b4 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java
@@ -7,9 +7,12 @@ import net.minecraft.core.achievement.stat.Stat;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityItem;
+import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.vehicle.EntityBoat;
 import net.minecraft.core.net.packet.PacketBoatControl;
 import net.minecraft.core.net.packet.PacketChat;
+import net.minecraft.core.net.packet.PacketContainerSetSlot;
+import net.minecraft.core.net.packet.PacketPlayerConfig;
 import net.minecraft.core.net.packet.PacketUpdatePlayerState;
 import net.minecraft.core.net.packet.PacketMovePlayer;
 import net.minecraft.core.net.packet.PacketContainerClose;
@@ -26,7 +29,7 @@ import net.minecraft.core.util.helper.DamageType;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
-public class PlayerLocalMultiplayer extends PlayerLocal
+public class PlayerLocalMultiplayer extends PlayerLocal implements Player.PlayerConfig.PlayerConfigListener
 {
     public PacketHandlerClient sendQueue;
     private int lastInventorySendTime;
@@ -50,6 +53,7 @@ public class PlayerLocalMultiplayer extends PlayerLocal
         wasSneaking = false;
         noSendTime = 0;
         sendQueue = netclienthandler;
+        playerConfig.assignListener(this);
     }
 
     @Override
@@ -283,4 +287,9 @@ public class PlayerLocalMultiplayer extends PlayerLocal
             sendQueue.addToSendQueue(new PacketBoatControl((EntityBoat) vehicle));
         }
     }
+
+    @Override
+    public void onValueChange() {
+        sendQueue.addToSendQueue(new PacketPlayerConfig(playerConfig));
+    }
 }
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 89fdd2116..1a4f46e74 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
@@ -1,9 +1,7 @@
 package net.minecraft.client.gui;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.EntityRenderDispatcher;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.item.model.ItemModel;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
@@ -66,9 +64,8 @@ public class ItemElement extends Gui
         {
             GL11.glEnable(GL11.GL_DEPTH_TEST);
             if (itemStack != null){
-                BlockModel.setRenderBlocks(EntityRenderDispatcher.instance.itemRenderer.renderBlocksInstance);
                 ItemModel itemModel = ItemModelDispatcher.getInstance().getDispatch(itemStack.getItem());
-                itemModel.renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, itemStack, x, y, discovered ? 1.0f : 0.0f, 1.0f);
+                itemModel.renderGui(Tessellator.instance, null, itemStack, x, y, discovered ? 1.0f : 0.0f, 1.0f, 1f);
                 if(slot instanceof SlotGuidebook){
                     if(((SlotGuidebook) slot).recipe instanceof RecipeEntryTrommel && ((SlotGuidebook) slot).item != null && ((SlotGuidebook) slot).isOutput){
                         WeightedRandomBag<WeightedRandomLootObject> loot = ((RecipeEntryTrommel)((SlotGuidebook) slot).recipe).getOutput();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/Screen.java b/game/client/src/main/java/net/minecraft/client/gui/Screen.java
index 02e9df1ab..8176b3eb0 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/Screen.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/Screen.java
@@ -146,7 +146,7 @@ public abstract class Screen extends Gui {
                     mc.gameWindow.toggleFullscreen();
                     return;
                 }
-                if (!(this instanceof ScreenConsole) && eventKey == mc.gameSettings.keyShowConsole.getKeyCode()) {
+                if (!(this instanceof ScreenConsole) && eventKey == mc.gameSettings.keyShowConsole.getKeyCode() && mc.gameSettings.developerMode.value && !Keyboard.areRepeatEventsEnabled()) {
                     mc.displayScreen(new ScreenConsole(this));
                     return;
                 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenCreateWorld.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenCreateWorld.java
index 8cab41988..301594ee2 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenCreateWorld.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenCreateWorld.java
@@ -182,9 +182,9 @@ public class ScreenCreateWorld extends Screen {
 
     private void updateButtons() {
         I18n i18n = I18n.getInstance();
-        gamemodeButton.displayString = i18n.translateKeyAndFormat("gui.create_world.button.gamemode", i18n.translateNameKey(selectedGamemode.getLanguageKey()));
+        gamemodeButton.displayString = i18n.translateKeyAndFormat("gui.create_world.button.gamemode", i18n.translateKey(selectedGamemode.getLanguageKey() + ".name"));
         cheatsButton.displayString = i18n.translateKeyAndFormat("gui.create_world.button.cheats", i18n.translateKey(cheatsEnabled ? "gui.create_world.button.cheats.on" : "gui.create_world.button.cheats.off"));
-        worldTypeButton.displayString = i18n.translateKeyAndFormat("gui.create_world.button.world_type", i18n.translateNameKey(worldTypeGroup.get(Dimension.OVERWORLD).getLanguageKey()));
+        worldTypeButton.displayString = i18n.translateKeyAndFormat("gui.create_world.button.world_type", i18n.translateKey(worldTypeGroup.get(Dimension.OVERWORLD).getLanguageKey() + ".name"));
     }
 
     @Override
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 76abaefb3..46ca59dcc 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
@@ -19,6 +19,7 @@ import com.mojang.logging.LogUtils;
 import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.gui.hud.HudIngameDoom;
 import net.minecraft.client.holiday.Holidays;
+import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
@@ -30,7 +31,6 @@ import org.lwjgl.util.glu.GLU;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.options.ScreenOptions;
 import net.minecraft.client.gui.options.data.OptionsPages;
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.lang.I18n;
@@ -410,6 +410,7 @@ public class ScreenMainMenu extends Screen
         GL11.glCullFace(GL11.GL_BACK);
         GL11.glDepthMask(true);
         GL11.glEnable(GL11.GL_DEPTH_TEST);
+        Lighting.enableLight();
         
         for(int var4 = 0; var4 < 3; ++var4) {
             GL11.glPushMatrix();
@@ -441,26 +442,24 @@ public class ScreenMainMenu extends Screen
                 this.mc.textureManager.loadTexture("/title/black.png").bind();
             }
 
-            RenderBlocks var5 = new RenderBlocks();
-
-            for(int var6 = 0; var6 < logoBlockLayers.length; ++var6) {
-                for(int var7 = 0; var7 < logoBlockLayers[var6].length(); ++var7) {
-                    char var8 = logoBlockLayers[var6].charAt(var7);
+            for(int y = 0; y < logoBlockLayers.length; ++y) {
+                for(int x = 0; x < logoBlockLayers[y].length(); ++x) {
+                    char var8 = logoBlockLayers[y].charAt(x);
                     if(var8 != ' ') {
                         GL11.glPushMatrix();
-                        LogoBlock var9 = this.logoBlocks[var7][var6];
-                        float var10 = (float)(var9.prevHeight + (var9.height - var9.prevHeight) * (double)var1);
-                        float var11 = 1.0F;
-                        float var12 = 1.0F;
+                        LogoBlock var9 = this.logoBlocks[x][y];
+                        float z = (float)(var9.prevHeight + (var9.height - var9.prevHeight) * (double)var1);
+                        float scale = 1.0F;
+                        float alpha = 1.0F;
                         if(var4 == 0) {
-                            var11 = var10 * 0.04F + 1.0F;
-                            var12 = 1.0F / var11;
-                            var10 = 0.0F;
+                            scale = z * 0.04F + 1.0F;
+                            alpha = 1.0F / scale;
+                            z = 0.0F;
                         }
 
-                        GL11.glTranslatef((float)var7, (float)var6, var10);
-                        GL11.glScalef(var11, var11, var11);
-                        var5.renderBlockAsItem(Tessellator.instance, BlockModelDispatcher.getInstance().getDispatch(BLOCKS_TO_DRAW[indexToDraw]), var12);
+                        GL11.glTranslatef(x, y, z);
+                        GL11.glScalef(scale, scale, scale);
+                        BlockModelDispatcher.getInstance().getDispatch(BLOCKS_TO_DRAW[indexToDraw]).renderStandalone(Tessellator.instance, 0, 1f, alpha, null);
                         GL11.glPopMatrix();
                     }
                 }
@@ -468,6 +467,7 @@ public class ScreenMainMenu extends Screen
 
             GL11.glPopMatrix();
         }
+        Lighting.disable();
 
         GL11.glDisable(GL11.GL_BLEND);
         GL11.glMatrixMode(GL11.GL_PROJECTION);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenMobPicker.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenMobPicker.java
index 323df04c2..9fbd5a4c3 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenMobPicker.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenMobPicker.java
@@ -62,7 +62,7 @@ public class ScreenMobPicker
                 if (statusCode == 1) {
                     mobId = monsters.get((Integer) results.get("list")).toString();
                     if (!mc.currentWorld.isClientSide) {
-                        TileEntityMobSpawner spawner = (TileEntityMobSpawner) mc.currentWorld.getBlockEntity(x, y, z);
+                        TileEntityMobSpawner spawner = (TileEntityMobSpawner) mc.currentWorld.getTileEntity(x, y, z);
                         if (spawner == null) {
                             return;
                         }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
index 02ca6352d..84bcd719c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
@@ -334,11 +334,11 @@ public class ScreenSelectWorld extends Screen
                 if (dd == null){
                     s2 += TextFormatting.RED + st.translateKey("gui.select_world.label.dimension_corrupted");
                 } else {
-                    s2 += st.translateNameKey(Gamemode.gamemodesList[ld.getGamemode()].getLanguageKey());
+                    s2 += st.translateKey(Gamemode.gamemodesList[ld.getGamemode()].getLanguageKey() + ".name");
                     if (ld.getCheatsEnabled()) s2 += " | " + st.translateKey("gui.select_world.label.cheats");
                     WorldType worldType = dd.getWorldType();
                     if (worldType != null) {
-                        s2 += " | " + st.translateNameKey(dd.getWorldType().getLanguageKey());
+                        s2 += " | " + st.translateKey(dd.getWorldType().getLanguageKey() + ".name");
                     } else {
                         s2 += " | " + TextFormatting.RED + st.translateKey("gui.select_world.label.unknown");
                     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
index 5f37c90d0..9a423b1d7 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
@@ -10,7 +10,7 @@ import net.minecraft.core.block.entity.TileEntitySign;
 import net.minecraft.core.enums.EnumSignPicture;
 import net.minecraft.core.util.helper.ChatAllowedCharacters;
 import net.minecraft.core.net.packet.PacketSignUpdate;
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.lang.I18n;
 import org.lwjgl.input.Keyboard;
@@ -186,7 +186,7 @@ public class ScreenSignEditor extends Screen
         {
             entitySign.lineBeingEdited = editLine;
         }
-        BlockEntityRenderDispatcher.instance.renderTileEntity(Tessellator.instance, entitySign, -0.5D, -0.75D, -0.5D, 0.0F);
+        TileEntityRenderDispatcher.instance.renderTileEntity(Tessellator.instance, entitySign, -0.5D, -0.75D, -0.5D, 0.0F);
         entitySign.lineBeingEdited = -1;
         GL11.glPopMatrix();
         
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 8cf74de5f..0f5b492d5 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
@@ -108,7 +108,7 @@ public class ScreenStats extends Screen {
         GL11.glEnable(GL12.GL_RESCALE_NORMAL);
         Lighting.enableInventoryLight();
         Item item = Item.itemsList[itemID];
-        ItemModelDispatcher.getInstance().getDispatch(item).renderItemIntoGui(Tessellator.instance, font, mc.textureManager, item.getDefaultStack(), x + 2, y + 2, 1F);
+        ItemModelDispatcher.getInstance().getDispatch(item).renderGui(Tessellator.instance, null, item.getDefaultStack(), x + 2, y + 2, 1f, 1f, 1f);
         Lighting.disable();
         GL11.glDisable(GL12.GL_RESCALE_NORMAL);
     }
@@ -285,7 +285,7 @@ public class ScreenStats extends Screen {
                 return;
             }
             Item item = statItem.getItem();
-            String s = I18n.getInstance().translateNameKey(item.getKey()).trim();
+            String s = I18n.getInstance().translateKey(item.getKey() + ".name").trim();
             tooltip.render(s, x, y, 8, -8);
         }
 
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 0ad9d515d..2a1331a24 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
@@ -835,8 +835,8 @@ public class ScreenAchievements extends Screen
 
             GL11.glTranslated(achViewX + 3 * zoom, achViewY + 3 * zoom, 0);
             GL11.glScaled(zoom, zoom, 1);
-            ItemModelDispatcher.getInstance().getDispatch(achievementItem)
-                .renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, achievementItem.getDefaultStack(), 0, 0, 1.0f);
+//            ItemModelDispatcher.getInstance().getDispatch(achievementItem).renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, achievementItem.getDefaultStack(), 0, 0, 1.0f);
+            ItemModelDispatcher.getInstance().getDispatch(achievementItem).renderGui(Tessellator.instance, null, achievementItem.getDefaultStack(), 0, 0, 1f, 1.0f, 1f);
 
             GL11.glDisable(GL11.GL_LIGHTING);
             GL11.glPopMatrix();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/achievements/data/AchievementPage.java b/game/client/src/main/java/net/minecraft/client/gui/achievements/data/AchievementPage.java
index e2170d571..b923dcbc3 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/achievements/data/AchievementPage.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/achievements/data/AchievementPage.java
@@ -75,7 +75,7 @@ public abstract class AchievementPage {
     public abstract int lineColorCanUnlock(boolean isHovered);
 
     public static IconCoordinate getTextureFromBlock(Block<?> block) {
-        return BlockModelDispatcher.getInstance().getDispatch(block).getBlockTextureFromSideAndMetadata(Side.TOP, 0);
+        return BlockModelDispatcher.getInstance().getDispatch(block).getOverlayTexture(0);
     }
 
     public static class AchievementEntry {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/achievements/pages/AchievementPageNether.java b/game/client/src/main/java/net/minecraft/client/gui/achievements/pages/AchievementPageNether.java
index a0c821058..264f94275 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/achievements/pages/AchievementPageNether.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/achievements/pages/AchievementPageNether.java
@@ -28,12 +28,12 @@ public class AchievementPageNether extends AchievementPage {
 
     @Override
     public @NotNull String getName() {
-        return I18n.getInstance().translateNameKey(key);
+        return I18n.getInstance().translateKey(key + ".name");
     }
 
     @Override
     public @NotNull String getDescription() {
-        return I18n.getInstance().translateDescKey(key);
+        return I18n.getInstance().translateKey(key + ".desc");
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/achievements/pages/AchievementPageOverworld.java b/game/client/src/main/java/net/minecraft/client/gui/achievements/pages/AchievementPageOverworld.java
index d258e97d0..8ab77a790 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/achievements/pages/AchievementPageOverworld.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/achievements/pages/AchievementPageOverworld.java
@@ -33,12 +33,12 @@ public class AchievementPageOverworld extends AchievementPage {
 
     @Override
     public @NotNull String getName() {
-        return I18n.getInstance().translateNameKey(key);
+        return I18n.getInstance().translateKey(key + ".name");
     }
 
     @Override
     public @NotNull String getDescription() {
-        return I18n.getInstance().translateDescKey(key);
+        return I18n.getInstance().translateKey(key + ".desc");
     }
 
     @Override
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 168366009..134d3721e 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
@@ -563,7 +563,8 @@ public class ScreenGuidebook
                 GL11.glEnable(GL12.GL_RESCALE_NORMAL);
 
                 GL11.glEnable(GL11.GL_DEPTH_TEST);
-                ItemModelDispatcher.getInstance().getDispatch(icon).renderItemIntoGui(Tessellator.instance, fr, re, icon, x + iconOffset + xo, y + 4, 1.0f);
+//                ItemModelDispatcher.getInstance().getDispatch(icon).renderItemIntoGui(Tessellator.instance, fr, re, icon, x + iconOffset + xo, y + 4, 1.0f);
+                ItemModelDispatcher.getInstance().getDispatch(icon).renderGui(Tessellator.instance, null, icon, x + iconOffset + xo, y + 4, 1.0f, 1f, 1f);
                 GL11.glDisable(GL11.GL_DEPTH_TEST);
 
                 GL11.glDisable(GL12.GL_RESCALE_NORMAL);
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 3091bc47e..7b6cbe466 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
@@ -120,7 +120,7 @@ public class HudIngame extends Gui
         }
 
         for (HudComponent component : HudComponents.INSTANCE.getComponents()) {
-            if (component.isVisible(mc)) {
+            if (component.isVisible(mc) && component.isEnabled(mc)) {
                 component.render(mc, this, width - sp * 2, height - sp * 2, partialTicks);
             }
         }
@@ -306,7 +306,7 @@ public class HudIngame extends Gui
                 debugOffset += space;
 
                 drawDebugScreenLine("Entities: " + mc.currentWorld.getLoadedEntityList().size());
-                drawDebugScreenLine("Block Entities: " + mc.currentWorld.getLoadedBlockEntityList().size());
+                drawDebugScreenLine("Tile Entities: " + mc.currentWorld.getLoadedTileEntityList().size());
 
                 debugOffset += space;
 
@@ -326,7 +326,7 @@ public class HudIngame extends Gui
                     Season season = mc.currentWorld.getSeasonManager().getCurrentSeason();
                     String seasonString = season != null ? season.getTranslatedName() : "None";
                     Weather weather = mc.currentWorld.getCurrentWeather();
-                    String weatherString = weather != null ? weather.getTranslatedName() : "None";
+                    String weatherString = weather != null ? stringtranslate.translateKey(weather.getNameLanguageKey()) : "None";
                     
                     int blockX = MathHelper.floor(mc.thePlayer.x);
 					int blockY = MathHelper.floor(mc.thePlayer.y);
@@ -498,7 +498,7 @@ public class HudIngame extends Gui
                         Weather weather = mc.currentWorld.getCurrentWeather();
                         if (weather != null && weather != mc.currentWorld.worldType.getDefaultWeather())
                         {
-                            this.drawString(font, weather.getTranslatedName(), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xff80ff : 0xffffff);
+                            this.drawString(font, stringtranslate.translateKey(weather.getNameLanguageKey()), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xff80ff : 0xffffff);
                         }
                     }
 					if(mc.gameSettings.overlayShowBiome.value)
@@ -523,7 +523,8 @@ public class HudIngame extends Gui
                 {
                     int x = 2 + sp;
                     int y = height - sp - 64 + i * 16;
-                    ItemModelDispatcher.getInstance().getDispatch(stack).renderItemIntoGui(Tessellator.instance, font, mc.textureManager, stack, x, y, 1.0f);
+//                    ItemModelDispatcher.getInstance().getDispatch(stack).renderItemIntoGui(Tessellator.instance, font, mc.textureManager, stack, x, y, 1.0f);
+                    ItemModelDispatcher.getInstance().getDispatch(stack).renderGui(Tessellator.instance, null, stack, x, y, 1f, 1.0f, partialTicks);
 
                     if (stack.isItemStackDamageable())
                     {
@@ -589,7 +590,8 @@ public class HudIngame extends Gui
                     GL11.glDisable(3042 /* GL_BLEND */);
                     GL11.glEnable(32826 /* GL_RESCALE_NORMAL_EXT */);
                     Lighting.enableInventoryLight();
-                    ItemModelDispatcher.getInstance().getDispatch(heldItemStack).renderItemIntoGui(Tessellator.instance, font, mc.textureManager, heldItemStack, x, y, 1.0f);
+//                    ItemModelDispatcher.getInstance().getDispatch(heldItemStack).renderItemIntoGui(Tessellator.instance, font, mc.textureManager, heldItemStack, x, y, 1.0f);
+                    ItemModelDispatcher.getInstance().getDispatch(heldItemStack).renderGui(Tessellator.instance, null, heldItemStack, x, y, 1f, 1f, partialTicks);
                     Lighting.disable();
                 }
             }
@@ -946,7 +948,7 @@ public class HudIngame extends Gui
         GL11.glDepthMask(false);
         GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
         GL11.glColor4f(1.0F, 1.0F, 1.0F, intensity);
-        IconCoordinate portal = BlockModelDispatcher.getInstance().getDispatch(Blocks.getBlock(mc.thePlayer.portalID)).getBlockTextureFromSideAndMetadata(Side.NORTH, mc.thePlayer.portalColor.blockMeta << 4 | BlockLogicPortal.MASK_COLOR_SET);
+        IconCoordinate portal = BlockModelDispatcher.getInstance().getDispatch(Blocks.getBlock(mc.thePlayer.portalID)).getOverlayTexture(mc.thePlayer.portalColor.blockMeta << 4 | BlockLogicPortal.MASK_COLOR_SET);
         portal.parentAtlas.bind();
         float f1 = (float) portal.getIconUMin();
         float f2 = (float) portal.getIconVMin();
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 4a0cedc82..30175d64b 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
@@ -182,17 +182,19 @@ public class HudComponentHotbar
             GL11.glScalef(1.0F / f2, (f2 + 1.0F) / 2.0F, 1.0F);
             GL11.glTranslatef(-(x + 8), -(y + 12), 0.0F);
         }
-        itemModel.renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, itemstack, x, y, 1.0f);
+//        itemModel.renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, itemstack, x, y, 1.0f);
+        itemModel.renderGui(Tessellator.instance, null, itemstack, x, y, 1, 1, partialTick);
         if (animProgress > 0.0F)
         {
             GL11.glPopMatrix();
         }
-        itemModel.renderItemOverlayIntoGUI(Tessellator.instance, mc.font, mc.textureManager, itemstack, x, y, 1.0f);
+        itemModel.renderItemOverlayIntoGUI(Tessellator.instance, mc.font, mc.textureManager, itemstack, x, y, null, 1.0f);
     }
 
     private void renderItem(Minecraft mc, ItemStack itemStack, int x, int y) {
         ItemModel itemModel = ItemModelDispatcher.getInstance().getDispatch(itemStack.getItem());
-        itemModel.renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, itemStack, x, y, 1.0f);
-        itemModel.renderItemOverlayIntoGUI(Tessellator.instance, mc.font, mc.textureManager, itemStack, x, y, 1.0f);
+//        itemModel.renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, itemStack, x, y, 1.0f);
+        itemModel.renderGui(Tessellator.instance, null, itemStack, x, y, 1.0f, 1f, 1f);
+        itemModel.renderItemOverlayIntoGUI(Tessellator.instance, mc.font, mc.textureManager, itemStack, x, y, null, 1.0f);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/ScreenModelViewer.java b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/ScreenModelViewer.java
index 5190d4e47..2627145ab 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/ScreenModelViewer.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/ScreenModelViewer.java
@@ -15,7 +15,7 @@ import net.minecraft.client.gui.modelviewer.elements.ListenerTextFieldElement;
 import net.minecraft.client.gui.modelviewer.elements.IListenerElement;
 import net.minecraft.client.gui.options.ScreenOptions;
 import net.minecraft.client.gui.options.data.OptionsPages;
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.shader.PhotoModeRenderer;
 import net.minecraft.client.render.shader.Shaders;
 import net.minecraft.client.render.shader.ShadersRenderer;
@@ -381,7 +381,7 @@ public class ScreenModelViewer extends ScreenPhotoMode implements ListenerTextFi
 
         scroll(Mouse.getDWheel());
 
-        BlockEntityRenderDispatcher.instance.renderTileEntity(Tessellator.instance, new TileEntity(), -0.5D, -0.75D, -0.5D, partialTick);
+        TileEntityRenderDispatcher.instance.renderTileEntity(Tessellator.instance, new TileEntity(), -0.5D, -0.75D, -0.5D, partialTick);
 
         drawStringCentered(font, currentCategory.getCurrentDisplayInfo(I18n.getInstance()), width/2, 1, 0xffffff);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/ViewerCategoryBlock.java b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/ViewerCategoryBlock.java
index 7c7554931..279dafee4 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/ViewerCategoryBlock.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/ViewerCategoryBlock.java
@@ -49,7 +49,7 @@ public class ViewerCategoryBlock extends ModelViewerCategory {
         Block<?> displayBlock = Blocks.getBlock(DisplayChunk.displayBlockId);
         String name = "None";
         if (displayBlock != null){
-            name = I18n.getInstance().translateNameKey(displayBlock.getKey());
+            name = I18n.getInstance().translateKey(displayBlock.getKey() + ".name");
             ItemStack[] nameStack = displayBlock.getBreakResult(mc.currentWorld, EnumDropCause.PICK_BLOCK, DisplayChunk.displayBlockPosX, DisplayChunk.displayBlockPosY, DisplayChunk.displayBlockPosZ, DisplayChunk.displayBlockMeta, DisplayChunk.displayTileEntity);
             if (nameStack != null && nameStack.length > 0){
                 name = nameStack[0].getDisplayName();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntryMinecart.java b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntryMinecart.java
index b5c644bc2..a2276c73c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntryMinecart.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntryMinecart.java
@@ -4,7 +4,7 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.client.gui.Screen;
 import net.minecraft.client.gui.modelviewer.elements.ListenerButtonElement;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.world.World;
 import org.lwjgl.input.Keyboard;
@@ -12,22 +12,22 @@ import org.lwjgl.input.Keyboard;
 import java.util.ArrayList;
 import java.util.List;
 
-public class EntityEntryMinecart extends EntityEntry<MinecartEntity>{
+public class EntityEntryMinecart extends EntityEntry<EntityMinecart>{
     @Override
-    public void onTick(MinecartEntity entity) {
+    public void onTick(EntityMinecart entity) {
 
     }
 
     @Override
-    public List<ButtonElement> getEntryButtons(Minecraft mc, Screen parentScreen, MinecartEntity minecart) {
+    public List<ButtonElement> getEntryButtons(Minecraft mc, Screen parentScreen, EntityMinecart minecart) {
         ListenerButtonElement button = new ListenerButtonElement(-1, - 120, 0, 120, 20, I18n.getInstance().translateKey("model.category.entity.minecart.button.cycle"));
-        button.setActionListener(() -> minecart.type = (minecart.type + 3 + (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) ? -1 : 1)) % 3);
+        button.setActionListener(() -> minecart.setType((byte) ((minecart.getType() + 3 + (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) ? -1 : 1)) % 3)));
         return new ArrayList<ButtonElement>(){{add(button);}};
     }
 
     @Override
-    public MinecartEntity getEntityInstance(Minecraft mc, World world) {
-        MinecartEntity minecart = new MinecartEntity(world);
+    public EntityMinecart getEntityInstance(Minecraft mc, World world) {
+        EntityMinecart minecart = new EntityMinecart(world);
         minecart.yRot = 270;
         return minecart;
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntryWolf.java b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntryWolf.java
index a9b3379a2..d26370f1d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntryWolf.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntryWolf.java
@@ -67,7 +67,7 @@ public class EntityEntryWolf extends EntityEntry<MobWolf>{
             entityWolf.getEntityData().set(19, material == null ? "" : material.identifier.toString());
         });
 
-        entityWolf.setWolfHeldItem(null);
+        entityWolf.setHeldItem(null);
         ListenerButtonElement hasItem = new ListenerButtonElement(-1, - 120, armor.yPosition + 21, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.item", false));
 
         TextCycleElement<Integer> itemIdCycle = new TextCycleElement<Integer>(parentScreen, mc.font, - 120, hasItem.yPosition + 21, 120, 20, 1) {
@@ -82,8 +82,8 @@ public class EntityEntryWolf extends EntityEntry<MobWolf>{
                     int id = Integer.parseInt(s);
                     if (Item.itemsList[id] != null) return id;
                 } catch (Exception ignored){}
-                if (entityWolf.getWolfHeldItem() != null){
-                    return entityWolf.getWolfHeldItem().itemID;
+                if (entityWolf.getHeldItem() != null){
+                    return entityWolf.getHeldItem().itemID;
                 }
                 return 0;
             }
@@ -109,8 +109,8 @@ public class EntityEntryWolf extends EntityEntry<MobWolf>{
                     int id = Integer.parseInt(s);
                     return MathHelper.clamp(id, 0, 0x3FFF);
                 } catch (Exception ignored){}
-                if (entityWolf.getWolfHeldItem() != null){
-                    return entityWolf.getWolfHeldItem().getMetadata();
+                if (entityWolf.getHeldItem() != null){
+                    return entityWolf.getHeldItem().getMetadata();
                 }
                 return 0;
             }
@@ -124,16 +124,16 @@ public class EntityEntryWolf extends EntityEntry<MobWolf>{
         metaCycle.textField.setPrefaceText("Meta: ");
         metaCycle.textField.setPlaceholder("Meta");
 
-        itemIdCycle.setOnValueChanged(() -> entityWolf.setWolfHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement())));
-        metaCycle.setOnValueChanged(() -> entityWolf.setWolfHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement())));
+        itemIdCycle.setOnValueChanged(() -> entityWolf.setHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement())));
+        metaCycle.setOnValueChanged(() -> entityWolf.setHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement())));
         hasItem.setActionListener(() -> {
-            boolean _hasItem = entityWolf.getWolfHeldItem() != null;
+            boolean _hasItem = entityWolf.getHeldItem() != null;
             if (_hasItem){
-                entityWolf.setWolfHeldItem(null);
+                entityWolf.setHeldItem(null);
                 itemIdCycle.enabled = false;
                 metaCycle.enabled = false;
             } else {
-                entityWolf.setWolfHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement()));
+                entityWolf.setHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement()));
                 itemIdCycle.enabled = true;
                 metaCycle.enabled = true;
             }
@@ -153,7 +153,7 @@ public class EntityEntryWolf extends EntityEntry<MobWolf>{
     @Override
     public MobWolf getEntityInstance(Minecraft mc, World world) {
         MobWolf wolf = new MobWolf(world);
-        wolf.setWolfHeldItem(null);
+        wolf.setHeldItem(null);
         return wolf;
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/LanguagePackListComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/LanguagePackListComponent.java
index 17177c34f..caeac86ae 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/LanguagePackListComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/LanguagePackListComponent.java
@@ -65,7 +65,7 @@ public class LanguagePackListComponent
             if (relativeMouseX >= 0 && relativeMouseX <= width && relativeMouseY >= 3 + i * (BUTTON_HEIGHT + 3) && relativeMouseY <= 3 + i * (BUTTON_HEIGHT + 3) + BUTTON_HEIGHT) {
                 String lang = button.languagePack.getId();
                 mc.gameSettings.language.set(lang);
-                I18n.getInstance().reload(lang, true);
+                I18n.getInstance().reload(lang);
                 mc.currentScreen.init();
             }
         }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
index 130580447..4472d7644 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
@@ -60,6 +60,7 @@ public abstract class OptionsPages
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.autoHit))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.easyBridge))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.viewBobbing))
+                .withComponent(new BooleanOptionComponent(mc.gameSettings.playerLeftHanded))
             )
             .withComponent(new OptionsCategory("gui.options.page.general.category.user_interface")
                 .withComponent(new ShortcutComponent("gui.options.page.general.button.edit_hud", () -> mc.displayScreen(new ScreenHudDesigner(mc.currentScreen))))
@@ -75,6 +76,7 @@ public abstract class OptionsPages
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.heldItemTooltips))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.alwaysShowDescriptions))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.hideUndiscoveredItems))
+                .withComponent(new BooleanOptionComponent(mc.gameSettings.dynamicCursor))
             )
             .withComponent(new OptionsCategory("gui.options.page.general.category.miscellaneous")
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.discordRichPresence))
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 2bc80ebd7..eaafc2209 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
@@ -179,7 +179,8 @@ public class GuiElementToastsHud extends Gui {
 
         GL11.glEnable(GL11.GL_DEPTH_TEST);
         ItemStack icon = toast.getIcon(duration);
-        ItemModelDispatcher.getInstance().getDispatch(icon).renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, icon, x + 8, y + 8, 1.0f);
+//        ItemModelDispatcher.getInstance().getDispatch(icon).renderItemIntoGui(Tessellator.instance, mc.font, mc.textureManager, icon, x + 8, y + 8, 1.0f);
+        if (icon != null) ItemModelDispatcher.getInstance().getDispatch(icon).renderGui(Tessellator.instance, null, icon, x + 8, y + 8, 1f, 1f, 1.0f);
         GL11.glDisable(GL11.GL_DEPTH_TEST);
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
index 49e431012..ae66fc3c1 100644
--- a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
+++ b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
@@ -165,6 +165,18 @@ public class PacketHandlerClient extends PacketHandler
         mc.thePlayer.id = loginPacket.playerEntityIdAndProtocolVersion;
         NetworkManager.PACKET_DELAY = loginPacket.packetDelay;
         Registries.RECIPES = new RecipeRegistry();
+
+        addToSendQueue(new PacketPlayerConfig(mc.thePlayer.playerConfig));
+    }
+
+    @Override
+    public void handlePlayerConfig(PacketPlayerConfig packetPlayerConfig) {
+        if (packetPlayerConfig.entityId >= 0 && packetPlayerConfig.entityId != mc.thePlayer.id) {
+            Entity e = getEntityByID(packetPlayerConfig.entityId);
+            if (e instanceof Player) {
+                ((Player) e).playerConfig.config = packetPlayerConfig.config;
+            }
+        }
     }
 
     @Override
@@ -299,6 +311,7 @@ public class PacketHandlerClient extends PacketHandler
         float f = (float) (addPlayerPacket.rotation * 360) / 256F;
         float f1 = (float) (addPlayerPacket.pitch * 360) / 256F;
         PlayerRemote playerRemote = new PlayerRemote(mc.currentWorld, addPlayerPacket.name, addPlayerPacket.uuid);
+        playerRemote.playerConfig.config = addPlayerPacket.playerConfig;
         playerRemote.xo = playerRemote.serverPosX = addPlayerPacket.xPosition;
         playerRemote.yo = playerRemote.serverPosY = addPlayerPacket.yPosition;
         playerRemote.zo = playerRemote.serverPosZ = addPlayerPacket.zPosition;
@@ -366,7 +379,7 @@ public class PacketHandlerClient extends PacketHandler
     {
         if (mc.currentWorld.isBlockLoaded(setMobSpawnerPacket.xPosition, setMobSpawnerPacket.yPosition, setMobSpawnerPacket.zPosition))
         {
-            TileEntity tileentity = mc.currentWorld.getBlockEntity(setMobSpawnerPacket.xPosition, setMobSpawnerPacket.yPosition, setMobSpawnerPacket.zPosition);
+            TileEntity tileentity = mc.currentWorld.getTileEntity(setMobSpawnerPacket.xPosition, setMobSpawnerPacket.yPosition, setMobSpawnerPacket.zPosition);
             if (tileentity instanceof TileEntityMobSpawner)
             {
                 TileEntityMobSpawner tileEntityMobSpawner = (TileEntityMobSpawner) tileentity;
@@ -746,7 +759,7 @@ public class PacketHandlerClient extends PacketHandler
             passenger = mc.thePlayer;
         }
         if (setRidingPacket.isTileEntity) {
-            vehicle = (IVehicle) worldClientMP.getBlockEntity(setRidingPacket.x, setRidingPacket.y, setRidingPacket.z);
+            vehicle = (IVehicle) worldClientMP.getTileEntity(setRidingPacket.x, setRidingPacket.y, setRidingPacket.z);
         } else {
             vehicle = getEntityByID(setRidingPacket.vehicleId);
         }
@@ -900,7 +913,7 @@ public class PacketHandlerClient extends PacketHandler
     @Override
     public void handleOpenFlagWindow(PacketFlagOpen flagOpenPacket)
     {
-        TileEntity tileEntity = worldClientMP.getBlockEntity(flagOpenPacket.x, flagOpenPacket.y, flagOpenPacket.z);
+        TileEntity tileEntity = worldClientMP.getTileEntity(flagOpenPacket.x, flagOpenPacket.y, flagOpenPacket.z);
         if (tileEntity instanceof TileEntityFlag)
         {
             TileEntityFlag tileEntityFlag = (TileEntityFlag) tileEntity;
@@ -1121,24 +1134,24 @@ public class PacketHandlerClient extends PacketHandler
     }
 
     @Override
-    public void handleTileEntityData(PacketBlockEntityData blockEntityDataPacket)
+    public void handleTileEntityData(PacketTileEntityData packetTileEntityData)
     {
-        Class<?> clazz = TileEntityDispatcher.getClassFromID(blockEntityDataPacket.tag.getString("id"));
+        Class<?> clazz = TileEntityDispatcher.getClassFromID(packetTileEntityData.tag.getString("id"));
         if (clazz == null) return;
-        TileEntity existingTileEntity = worldClientMP.getBlockEntity(blockEntityDataPacket.tag.getInteger("x"), blockEntityDataPacket.tag.getInteger("y"), blockEntityDataPacket.tag.getInteger("z"));
+        TileEntity existingTileEntity = worldClientMP.getTileEntity(packetTileEntityData.tag.getInteger("x"), packetTileEntityData.tag.getInteger("y"), packetTileEntityData.tag.getInteger("z"));
         if (existingTileEntity == null || existingTileEntity.getClass() != clazz)
         {
-            TileEntity tileEntity = TileEntityDispatcher.createAndLoadEntity(blockEntityDataPacket.tag);
+            TileEntity tileEntity = TileEntityDispatcher.createAndLoadEntity(packetTileEntityData.tag);
             if (tileEntity != null)
             {
-                mc.currentWorld.setBlockTileEntity(tileEntity.x, tileEntity.y, tileEntity.z, tileEntity);
+                mc.currentWorld.setTileEntity(tileEntity.x, tileEntity.y, tileEntity.z, tileEntity);
             }
         }
         else
         {
-            existingTileEntity.readFromNBT(blockEntityDataPacket.tag);
+            existingTileEntity.readFromNBT(packetTileEntityData.tag);
         }
-        worldClientMP.markBlockDirty(blockEntityDataPacket.tag.getInteger("x"), blockEntityDataPacket.tag.getInteger("y"), blockEntityDataPacket.tag.getInteger("z"));
+        worldClientMP.markBlockDirty(packetTileEntityData.tag.getInteger("x"), packetTileEntityData.tag.getInteger("y"), packetTileEntityData.tag.getInteger("z"));
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
index baf5382db..bf45585fa 100644
--- a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
+++ b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
@@ -28,6 +28,7 @@ import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.Color;
 import net.minecraft.core.util.helper.ITranslatable;
+
 import org.slf4j.Logger;
 
 public class GameSettings {
@@ -171,6 +172,9 @@ public class GameSettings {
 	public OptionBoolean subtitles = new OptionBoolean(this, "subtitles", false);
 	public OptionBoolean developerMode = new OptionBoolean(this, "developerMode", false);
 	public OptionBoolean enableHolidayTextures = new OptionBoolean(this, "enableHolidayTextures", true);
+	public OptionBoolean dynamicCursor = new OptionBoolean(this, "dynamicCursor", true);
+
+	public OptionBoolean playerLeftHanded = new OptionBoolean(this, "playerLeftHanded", false);
 
 	public KeyBinding keyAttack = new KeyBinding("key.attack").setDefault(InputDevice.mouse, 0);
 	public KeyBinding keyInteract = new KeyBinding("key.interact").setDefault(InputDevice.mouse, 1);
@@ -423,6 +427,9 @@ public class GameSettings {
 				mc.currentWorld.setDifficulty(difficulty.value, false);
 			}
 		}
+		if(option == playerLeftHanded && mc.thePlayer != null) {
+			mc.thePlayer.playerConfig.setLeftHand(playerLeftHanded.value);
+		}
 		if(option == enableVsync) mc.gameWindow.setVsync(enableVsync.value);
 		if(option == fancyGraphics) mc.renderGlobal.loadRenderers();
 		if(option == ambientOcclusion) mc.renderGlobal.loadRenderers();
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 3441840c7..702faaedf 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
@@ -259,7 +259,7 @@ public abstract class PlayerController {
 		int blockId = world.getBlockId(blockX, blockY, blockZ);
 		if (player.getHeldObject() == null) {
 			if (player.isSneaking() && itemstack == null) { // If crouched and hand empty try to pickup block entity
-				TileEntity tileEntity = world.getBlockEntity(blockX, blockY, blockZ);
+				TileEntity tileEntity = world.getTileEntity(blockX, blockY, blockZ);
 				if (tileEntity != null && tileEntity.canBeCarried(world, player)) {
 					player.setHeldObject(tileEntity.pickup(world, player));
 					return true;
diff --git a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
index ea84e2740..302e025ad 100644
--- a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
+++ b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
@@ -18,7 +18,7 @@ public class PlayerControllerSP extends PlayerController {
 		if (!player.getGamemode().canInteract() || mc.thePlayer.getHeldObject() != null) return false;
 		int id = mc.currentWorld.getBlockId(x, y, z);
 		int meta = mc.currentWorld.getBlockMetadata(x, y, z);
-		TileEntity tileEntity = mc.currentWorld.getBlockEntity(x, y, z);
+		TileEntity tileEntity = mc.currentWorld.getTileEntity(x, y, z);
 		boolean removed = super.destroyBlock(x, y, z, side, player);
 		ItemStack item = mc.thePlayer.getCurrentEquippedItem();
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/EntityRenderDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/EntityRenderDispatcher.java
index b033462b0..e2298fdac 100644
--- a/game/client/src/main/java/net/minecraft/client/render/EntityRenderDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/EntityRenderDispatcher.java
@@ -4,13 +4,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import net.minecraft.client.render.entity.*;
-import net.minecraft.client.render.model.ModelBiped;
-import net.minecraft.client.render.model.ModelChicken;
-import net.minecraft.client.render.model.ModelCow;
-import net.minecraft.client.render.model.ModelSheep;
-import net.minecraft.client.render.model.ModelSkeleton;
-import net.minecraft.client.render.model.ModelSquid;
-import net.minecraft.client.render.model.ModelZombie;
+import net.minecraft.client.render.model.*;
 import net.minecraft.core.entity.EntityItem;
 import net.minecraft.core.entity.EntityLightning;
 import net.minecraft.core.entity.EntityPainting;
@@ -20,26 +14,16 @@ import net.minecraft.core.entity.animal.MobChicken;
 import net.minecraft.core.entity.animal.MobFireflyCluster;
 import net.minecraft.core.entity.animal.MobWolf;
 import net.minecraft.core.entity.animal.MobSquid;
-import net.minecraft.core.entity.monster.MobCreeper;
-import net.minecraft.core.entity.monster.MobSkeleton;
-import net.minecraft.core.entity.monster.MobSlime;
-import net.minecraft.core.entity.monster.MobZombie;
-import net.minecraft.core.entity.monster.MobZombieArmored;
+import net.minecraft.core.entity.monster.*;
 import net.minecraft.core.entity.projectile.ProjectileCannonball;
 import net.minecraft.core.entity.projectile.ProjectileEgg;
 import net.minecraft.core.entity.projectile.ProjectileFireball;
 import net.minecraft.core.entity.projectile.ProjectileSnowball;
 import net.minecraft.core.entity.vehicle.EntityBoat;
-import net.minecraft.core.entity.vehicle.MobGhastVehicle;
 import net.minecraft.core.item.Items;
 import org.lwjgl.opengl.GL11;
 import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.camera.ICamera;
-import net.minecraft.client.render.model.ModelPig;
-import net.minecraft.client.render.model.ModelSheepOverlay;
-import net.minecraft.client.render.model.ModelSheepWool;
-import net.minecraft.client.render.model.ModelSlime;
-import net.minecraft.client.render.model.ModelWolf;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.Global;
 import net.minecraft.core.entity.Entity;
@@ -49,16 +33,10 @@ import net.minecraft.core.entity.EntityPrimedTNT;
 import net.minecraft.core.entity.animal.MobCow;
 import net.minecraft.core.entity.animal.MobPig;
 import net.minecraft.core.entity.animal.MobSheep;
-import net.minecraft.core.entity.monster.MobGhast;
-import net.minecraft.core.entity.monster.MobGiant;
-import net.minecraft.core.entity.monster.MobHuman;
-import net.minecraft.core.entity.monster.MobScorpion;
-import net.minecraft.core.entity.monster.MobSnowman;
-import net.minecraft.core.entity.monster.MobSpider;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.projectile.ProjectileArrow;
 import net.minecraft.core.entity.projectile.ProjectilePebble;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.world.World;
 
 public class EntityRenderDispatcher
@@ -76,6 +54,7 @@ public class EntityRenderDispatcher
         renderers.put(MobCreeper.class, new MobRendererCreeper());
         renderers.put(MobSkeleton.class, new MobRendererBipedArmored<>(new ModelSkeleton(), new ModelZombie(1.0f), new ModelZombie(0.5f), 0.5F));
         renderers.put(MobZombie.class, new MobRendererBipedArmored<>(new ModelZombie(), new ModelZombie(1.0f), new ModelZombie(0.5f), 0.5F));
+        renderers.put(MobZombiePig.class, new MobRendererBipedArmored<>(new ModelZombiePigman(), new ModelZombie(1.0f), new ModelZombie(0.5f), 0.5F));
         renderers.put(MobSnowman.class, new MobRendererBiped<>(new ModelZombie(), 0.5F));
         renderers.put(MobZombieArmored.class, new MobRendererZombieArmored(new ModelZombie(), 0.5F));
         renderers.put(MobSlime.class, new MobRendererSlime(new ModelSlime(16), new ModelSlime(0), 0.25F));
@@ -83,7 +62,6 @@ public class EntityRenderDispatcher
         renderers.put(MobHuman.class, new MobRendererHuman());
         renderers.put(MobGiant.class, new MobRendererGiant(new ModelZombie(), 0.5F, 6F));
         renderers.put(MobGhast.class, new MobRendererGhast());
-        renderers.put(MobGhastVehicle.class, new MobRendererGhast());
         renderers.put(MobSquid.class, new MobRendererSquid(new ModelSquid(), 0.7F));
         renderers.put(Mob.class, new MobRenderer<>(new ModelBiped(), 0.5F));
         renderers.put(Entity.class, new EntityRendererDefault());
@@ -95,7 +73,7 @@ public class EntityRenderDispatcher
         renderers.put(EntityItem.class, new EntityRendererItem());
         renderers.put(EntityPrimedTNT.class, new EntityRendererTNT());
         renderers.put(EntityFallingBlock.class, new EntityRendererFallingBlock());
-        renderers.put(MinecartEntity.class, new EntityRendererMinecart());
+        renderers.put(EntityMinecart.class, new EntityRendererMinecart());
         renderers.put(EntityBoat.class, new EntityRendererBoat());
         renderers.put(EntityFishingBobber.class, new EntityRendererFishingBobber());
         renderers.put(MobFireflyCluster.class, new MobRendererFireflyCluster());
diff --git a/game/client/src/main/java/net/minecraft/client/render/FogManager.java b/game/client/src/main/java/net/minecraft/client/render/FogManager.java
index 2d5be81e9..9888c7fb7 100644
--- a/game/client/src/main/java/net/minecraft/client/render/FogManager.java
+++ b/game/client/src/main/java/net/minecraft/client/render/FogManager.java
@@ -41,7 +41,7 @@ public class FogManager {
     public void updateBrightness() {
         fogBrightnessOld = fogBrightness;
 
-        float fogModifier = mc.currentWorld.getCurrentWeather() != null ? mc.currentWorld.getCurrentWeather().fogDistance : 1.0f;
+        float fogModifier = mc.currentWorld.getCurrentWeather() != null ? mc.currentWorld.getCurrentWeather().getFogDistanceMultiplier() : 1.0f;
         fogModifier = (1.0f - ((1.0f - fogModifier) * mc.currentWorld.weatherManager.getWeatherIntensity() * mc.currentWorld.weatherManager.getWeatherPower()));
 
         float brightnessAtCamera = mc.currentWorld.getLightBrightness(MathHelper.floor(mc.activeCamera.getX(1f)), MathHelper.floor(mc.activeCamera.getY(1f)), MathHelper.floor(mc.activeCamera.getZ(1f)));
@@ -73,7 +73,7 @@ public class FogManager {
             float maxFogDistance = RenderDistance.EXTREME.chunks * 16;
             float fogDistance = farPlaneDistance;
 
-            float fogModifier = mc.currentWorld.getCurrentWeather() != null ? mc.currentWorld.getCurrentWeather().fogDistance : 1.0f;
+            float fogModifier = mc.currentWorld.getCurrentWeather() != null ? mc.currentWorld.getCurrentWeather().getFogDistanceMultiplier() : 1.0f;
             fogModifier = (1.0f - ((1.0f - fogModifier) * mc.currentWorld.weatherManager.getWeatherIntensity() * mc.currentWorld.weatherManager.getWeatherPower()));
 
             if (fogDistance > maxFogDistance * fogModifier) fogDistance = maxFogDistance * fogModifier;
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 8044d2c89..3c9e7d855 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
@@ -1,10 +1,7 @@
 package net.minecraft.client.render;
 
 import net.minecraft.client.entity.player.PlayerLocal;
-import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.core.block.Blocks;
-import net.minecraft.core.item.Item;
-import net.minecraft.core.item.block.ItemBlock;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.Minecraft;
@@ -21,8 +18,8 @@ import net.minecraft.core.block.material.Material;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.util.helper.Side;
 import org.lwjgl.opengl.GL12;
+import org.useless.dragonfly.DisplayPos;
 
 import static org.lwjgl.opengl.GL11.GL_ALPHA_TEST;
 import static org.lwjgl.opengl.GL11.GL_BLEND;
@@ -41,7 +38,6 @@ public class ItemRenderer
         itemToRender = null;
         height = 0.0F;
         oHeight = 0.0F;
-        renderBlocksInstance = new RenderBlocks();
         lastSlot = -1;
         mc = minecraft;
     }
@@ -49,14 +45,6 @@ public class ItemRenderer
         return oHeight + (height - oHeight) * partialTick;
     }
 
-    public int getItemColorFromMetadata(Item item, int metadata) {
-        if (item instanceof ItemBlock) {
-            Block<?> block = ((ItemBlock<?>)item).getBlock();
-            return BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
-        }
-        return 0xFFFFFF;
-    }
-
     public void renderItemInFirstPerson(float partialTick)
     {
         float equipProgress = getEquippedProgress(partialTick);
@@ -68,17 +56,24 @@ public class ItemRenderer
         Lighting.enableLight();
         GL11.glPopMatrix();
         ItemStack itemstack = itemToRender;
-        GL11.glPushMatrix();
         if(itemstack != null)
         {
-            ItemModelDispatcher.getInstance().getDispatch(itemstack.getItem()).renderItemFirstPerson(Tessellator.instance,this, player, itemstack, partialTick);
-        } else
-        {
+            float brightness = 1.0f;
+            if(LightmapHelper.isLightmapEnabled() || mc.fullbright) {
+                LightmapHelper.setLightmapCoord(mc.thePlayer.getLightmapCoord(partialTick));
+            }else {
+                brightness = mc.currentWorld.getLightBrightness(MathHelper.floor(player.x), MathHelper.floor(player.y), MathHelper.floor(player.z));
+            }
+            ItemModelDispatcher.getInstance().getDispatch(itemstack.getItem()).renderFirstPerson(Tessellator.instance, this,player, itemstack, brightness, 1f, partialTick);
+        } else {
+
+            GL11.glPushMatrix();
+            GL11.glEnable(GL12.GL_RESCALE_NORMAL);
         	float brightness = 1.0f;
         	if(LightmapHelper.isLightmapEnabled() || mc.fullbright) {
         		LightmapHelper.setLightmapCoord(mc.thePlayer.getLightmapCoord(partialTick));
         	}else if(mc.fullbright) {
-        		
+
         	}else {
         		brightness = mc.currentWorld.getLightBrightness(MathHelper.floor(player.x), MathHelper.floor(player.y), MathHelper.floor(player.z));
         	}
@@ -86,26 +81,53 @@ public class ItemRenderer
             EntityRenderer<? extends Entity> render = EntityRenderDispatcher.instance.getRenderer(mc.thePlayer);
             MobRendererPlayer playerRenderer = (MobRendererPlayer)render;
             if (player.getHeldObject() == null) {
-                float f6 = 0.8F;
-                float swingProgress = player.getSwingProgress(partialTick);
-                float f14 = MathHelper.sin(swingProgress * MathHelper.PI);
-                float f18 = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
-                GL11.glTranslatef(-f18 * 0.3F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.4F, -f14 * 0.4F);
-                GL11.glTranslatef(0.8F * f6, -0.75F * f6 - (1.0F - equipProgress) * 0.6F, -0.9F * f6);
-                GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
-                GL11.glEnable(GL12.GL_RESCALE_NORMAL);
-                f14 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
-                f18 = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
-                GL11.glRotatef(f18 * 70F, 0.0F, 1.0F, 0.0F);
-                GL11.glRotatef(-f14 * 20F, 0.0F, 0.0F, 1.0F);
-                mc.textureManager.bindDownloadableTexture(mc.thePlayer.skinURL, mc.thePlayer.getEntityTexture(), PlayerSkinParser.instance);
-                GL11.glTranslatef(-1F, 3.6F, 3.5F);
-                GL11.glRotatef(120F, 0.0F, 0.0F, 1.0F);
-                GL11.glRotatef(200F, 1.0F, 0.0F, 0.0F);
-                GL11.glRotatef(-135F, 0.0F, 1.0F, 0.0F);
-                GL11.glScalef(1.0F, 1.0F, 1.0F);
-                GL11.glTranslatef(5.6F, 0.0F, 0.0F);
-                playerRenderer.drawFirstPersonHand(mc.thePlayer, false);
+                if (player.isLeftHanded()) {
+                    float f6 = 0.8F;
+                    float swingProgress = player.getSwingProgress(partialTick);
+                    float f14 = MathHelper.sin(swingProgress * MathHelper.PI);
+                    float f18 = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
+
+                    GL11.glScalef(-1, 1, 1);
+                    GL11.glTranslatef(-f18 * 0.3F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.4F, -f14 * 0.4F);
+                    GL11.glTranslatef(0.8F * f6, -0.75F * f6 - (1.0F - equipProgress) * 0.6F, -0.9F * f6);
+                    GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
+                    f14 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
+                    f18 = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
+
+                    GL11.glRotatef(f18 * 70F, 0.0F, 1.0F, 0.0F);
+                    GL11.glRotatef(-f14 * 20F, 0.0F, 0.0F, 1.0F);
+                    mc.textureManager.bindDownloadableTexture(mc.thePlayer.skinURL, mc.thePlayer.getEntityTexture(), PlayerSkinParser.instance);
+
+                    GL11.glTranslatef(-1F, 3.6F, 3.5F);
+                    GL11.glRotatef(120F, 0.0F, 0.0F, 1.0F);
+                    GL11.glRotatef(200F, 1.0F, 0.0F, 0.0F);
+                    GL11.glRotatef(-135F, 0.0F, 1.0F, 0.0F);
+                    GL11.glTranslatef(5.6F, 0.0F, 0.0F);
+
+                    GL11.glPushMatrix();
+                    GL11.glScalef(-1, 1, 1);
+                    playerRenderer.drawFirstPersonHand(mc.thePlayer, true);
+                    GL11.glPopMatrix();
+                } else {
+                    float f6 = 0.8F;
+                    float swingProgress = player.getSwingProgress(partialTick);
+                    float f14 = MathHelper.sin(swingProgress * MathHelper.PI);
+                    float f18 = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
+                    GL11.glTranslatef(-f18 * 0.3F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.4F, -f14 * 0.4F);
+                    GL11.glTranslatef(0.8F * f6, -0.75F * f6 - (1.0F - equipProgress) * 0.6F, -0.9F * f6);
+                    GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
+                    f14 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
+                    f18 = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
+                    GL11.glRotatef(f18 * 70F, 0.0F, 1.0F, 0.0F);
+                    GL11.glRotatef(-f14 * 20F, 0.0F, 0.0F, 1.0F);
+                    mc.textureManager.bindDownloadableTexture(mc.thePlayer.skinURL, mc.thePlayer.getEntityTexture(), PlayerSkinParser.instance);
+                    GL11.glTranslatef(-1F, 3.6F, 3.5F);
+                    GL11.glRotatef(120F, 0.0F, 0.0F, 1.0F);
+                    GL11.glRotatef(200F, 1.0F, 0.0F, 0.0F);
+                    GL11.glRotatef(-135F, 0.0F, 1.0F, 0.0F);
+                    GL11.glTranslatef(5.6F, 0.0F, 0.0F);
+                    playerRenderer.drawFirstPersonHand(mc.thePlayer, false);
+                }
             } else {
                 GL11.glPushMatrix();
                 float swingProgress = player.getSwingProgress(partialTick);
@@ -115,9 +137,9 @@ public class ItemRenderer
                 playerRenderer.drawHeldObject(mc.thePlayer, partialTick);
                 GL11.glPopMatrix();
             }
+            GL11.glPopMatrix();
+            GL11.glDisable(GL12.GL_RESCALE_NORMAL);
         }
-        GL11.glPopMatrix();
-        GL11.glDisable(GL12.GL_RESCALE_NORMAL);
         Lighting.disable();
     }
 
@@ -142,7 +164,7 @@ public class ItemRenderer
             Block<?> block = Blocks.blocksList[id];
             BlockModel<?> model = BlockModelDispatcher.getInstance().getDispatch(block);
 			if(mc.currentWorld.isBlockNormalCube(blockX, blockY, blockZ)) {
-				renderInsideOfBlock(partialTicks, model.getBlockTextureFromSideAndMetadata(Side.NORTH, meta));
+				renderInsideOfBlock(partialTicks, model.getOverlayTexture(meta));
 			} else {
                 id = 0;
 				for (int i = 0; i < 8; i++) {
@@ -162,7 +184,7 @@ public class ItemRenderer
 				}
                 if(Blocks.blocksList[id] != null) {
                     model = BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[id]);
-                    renderInsideOfBlock(partialTicks, model.getBlockTextureFromSideAndMetadata(Side.NORTH, meta));
+                    renderInsideOfBlock(partialTicks, model.getOverlayTexture(meta));
                 }
 			}
 
@@ -315,6 +337,5 @@ public class ItemRenderer
     private ItemStack itemToRender;
     private float height;
     private float oHeight;
-    public RenderBlocks renderBlocksInstance;
     private int lastSlot;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/Lighting.java b/game/client/src/main/java/net/minecraft/client/render/Lighting.java
index 8afaf7acc..360bfc54d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/Lighting.java
+++ b/game/client/src/main/java/net/minecraft/client/render/Lighting.java
@@ -20,11 +20,20 @@ public class Lighting {
 	}
 
 	public static void enableInventoryLight() {
+		// TODO this needed to change alot in the item rendering rewrite this is probably really wrong in some way
 		glPushMatrix();
-		glRotatef(-30.0f, 0.0F, 1.0F, 0.0F);
-		glRotatef(155.0f, 1.0F, 0.0F, 0.0F);
-		enableLight(0.4f, 0.5f);
+		glRotatef(90, 1, 0, 0);
+		glRotatef(105, 0, 1, 0);
+		glRotatef(90, 0, 0, 1);
+		enableLight(0.1f, 3.5f);
 		glPopMatrix();
+
+//		Original
+//		glPushMatrix();
+//		glRotatef(-30.0f, 0.0F, 1.0F, 0.0F);
+//		glRotatef(155.0f, 1.0F, 0.0F, 0.0F);
+//		enableLight(0.4f, 0.5f);
+//		glPopMatrix();
 	}
 
 	public static void enableLight() {
diff --git a/game/client/src/main/java/net/minecraft/client/render/RenderBlockCache.java b/game/client/src/main/java/net/minecraft/client/render/LightingCache.java
similarity index 98%
rename from game/client/src/main/java/net/minecraft/client/render/RenderBlockCache.java
rename to game/client/src/main/java/net/minecraft/client/render/LightingCache.java
index 188f03851..77050245e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/RenderBlockCache.java
+++ b/game/client/src/main/java/net/minecraft/client/render/LightingCache.java
@@ -7,7 +7,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.WorldSource;
 
-final public class RenderBlockCache {
+final public class LightingCache {
     private final Minecraft mc = Minecraft.getMinecraft();
     
     private static final int CACHE_RANGE = 1;
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 a41faa6bf..26f24c9fd 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
@@ -345,6 +345,10 @@ public class LightmapHelper {
 	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);
@@ -394,9 +398,17 @@ public class LightmapHelper {
 	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/MapItemRenderer.java b/game/client/src/main/java/net/minecraft/client/render/MapItemRenderer.java
index bb083313d..13a77552e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/MapItemRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/MapItemRenderer.java
@@ -3,9 +3,9 @@ package net.minecraft.client.render;
 import java.awt.image.BufferedImage;
 import java.util.Iterator;
 
+import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.texture.TextureBuffered;
 
-import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.material.MaterialColor;
 import net.minecraft.core.util.helper.Color;
@@ -22,22 +22,15 @@ public class MapItemRenderer
 
     private final int[] mapImageData;
     private TextureBuffered mapTexture;
-    private final GameSettings gameSettings;
-    private final TextureManager textureManager;
-    private Font font;
 
-
-    public MapItemRenderer(Font font, GameSettings gamesettings, TextureManager textureManager)
+    public MapItemRenderer()
     {
         mapImageData = new int[IMAGE_AREA];
-        gameSettings = gamesettings;
-        this.textureManager = textureManager;
-        this.font = font;
     }
 
     public void preRender() {
         if (mapTexture == null) {
-            mapTexture = textureManager.loadBufferedTexture(new BufferedImage(128, 128, 2));
+            mapTexture = Minecraft.getMinecraft().textureManager.loadBufferedTexture(new BufferedImage(128, 128, 2));
             for(int i = 0; i < IMAGE_AREA; i++)
             {
                 mapImageData[i] = 0;
@@ -45,9 +38,10 @@ public class MapItemRenderer
         }
     }
 
-    public void renderMap(TextureManager textureManager, ItemMapSavedData data, float brightness)
+    public void renderMap(Tessellator tessellator, ItemMapSavedData data, float brightness)
     {
         preRender();
+        TextureManager textureManager = Minecraft.getMinecraft().textureManager;
         for(int i = 0; i < IMAGE_AREA; i++)
         {
             int colorIndex = data.colors[i];
@@ -85,17 +79,16 @@ public class MapItemRenderer
         textureManager.updateTextureData(mapImageData, 128, 128, mapTexture.id());
         int j = 0;
         int k = 0;
-        Tessellator tessellator = Tessellator.instance;
         float f = 0.0F;
         //renders the map
         mapTexture.bind();
         GL11.glEnable(GL11.GL_BLEND);
         GL11.glDisable(GL11.GL_ALPHA_TEST);
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV((float)(j + 0) + f, (float)(k + 128) - f, -0.01D, 0.0D, 1.0D);
+        tessellator.addVertexWithUV((float)(j) + f, (float)(k + 128) - f, -0.01D, 0.0D, 1.0D);
         tessellator.addVertexWithUV((float)(j + 128) - f, (float)(k + 128) - f, -0.01D, 1.0D, 1.0D);
-        tessellator.addVertexWithUV((float)(j + 128) - f, (float)(k + 0) + f, -0.01D, 1.0D, 0.0D);
-        tessellator.addVertexWithUV((float)(j + 0) + f, (float)(k + 0) + f, -0.01D, 0.0D, 0.0D);
+        tessellator.addVertexWithUV((float)(j + 128) - f, (float)(k) + f, -0.01D, 1.0D, 0.0D);
+        tessellator.addVertexWithUV((float)(j) + f, (float)(k) + f, -0.01D, 0.0D, 0.0D);
         tessellator.draw();
         GL11.glEnable(GL11.GL_ALPHA_TEST);
         GL11.glDisable(GL11.GL_BLEND);
@@ -105,7 +98,7 @@ public class MapItemRenderer
         {
             MapWaypoint mapWaypoint = iterator.next();
             GL11.glPushMatrix();
-            GL11.glTranslatef((float)j + (float)mapWaypoint.mapCoordX / 2.0F + 64F, (float)k + (float)mapWaypoint.mapCoordZ / 2.0F + 64F, -0.02F);
+            GL11.glTranslatef((float)j + (float)mapWaypoint.mapCoordX / 2.0F + 64, (float)k + (float)mapWaypoint.mapCoordZ / 2.0F + 64, -0.02F);
             GL11.glRotatef((float)(8 * 360) / 16F , 0.0F, 0.0F, 1.0F);
             GL11.glScalef(4F, 4F, 3F);
             GL11.glTranslatef(-0.125F, 0.125F, 0.0F);
@@ -127,7 +120,7 @@ public class MapItemRenderer
         {
             ItemMapSavedData.MapDecoration decoration = iterator.next();
             GL11.glPushMatrix();
-            GL11.glTranslatef((float)j + (float)decoration.x / 2.0F + 64F, (float)k + (float)decoration.y / 2.0F + 64F, -0.02F);
+            GL11.glTranslatef((float)j + (float)decoration.x / 2.0F + 64, (float)k + (float)decoration.y / 2.0F + 64, -0.02F);
             GL11.glRotatef((decoration.rot * 360F) / ItemMapSavedData.MapDecoration.ROTATION_STEPS, 0.0F, 0.0F, 1.0F);
             GL11.glScalef(4F, 4F, 3F);
             GL11.glTranslatef(-0.125F, 0.125F, 0.0F);
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 90cf78a48..03915e02f 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
@@ -77,7 +77,6 @@ public class RenderGlobal
     private int renderChunksDeep;
     private int glRenderListBase;
     private final Minecraft mc;
-    private RenderBlocks globalRenderBlocks;
     private IntBuffer glOcclusionQueryBase;
     private boolean occlusionEnabled;
     private float lastCloudOffsetX = 0;
@@ -259,7 +258,6 @@ public class RenderGlobal
         EntityRenderDispatcher.instance.unloadEntityRenderers();
         EntityRenderDispatcher.instance.setWorld(world);
         worldObj = world;
-        globalRenderBlocks = new RenderBlocks(world);
         auroraBrightness = 0.0f;
         targetAuroraBrightness = Float.NaN;
         if(world != null)
@@ -467,7 +465,7 @@ public class RenderGlobal
             renderEntitiesStartupCounter--;
             return;
         }
-        BlockEntityRenderDispatcher.instance.cacheActiveRenderInfo(worldObj, textureManager, mc.font, camera, partialTick);
+        TileEntityRenderDispatcher.instance.cacheActiveRenderInfo(worldObj, textureManager, mc.font, camera, partialTick);
         EntityRenderDispatcher.instance.cacheActiveRenderInfo(worldObj, textureManager, mc.font, camera, mc.gameSettings, partialTick);
         countEntitiesTotal = 0;
         countEntitiesRendered = 0;
@@ -475,9 +473,9 @@ public class RenderGlobal
         EntityRenderDispatcher.renderPosX = camera.getX(partialTick);
         EntityRenderDispatcher.renderPosY = camera.getY(partialTick);
         EntityRenderDispatcher.renderPosZ = camera.getZ(partialTick);
-        BlockEntityRenderDispatcher.renderPosX = camera.getX(partialTick);
-        BlockEntityRenderDispatcher.renderPosY = camera.getY(partialTick);
-        BlockEntityRenderDispatcher.renderPosZ = camera.getZ(partialTick);
+        TileEntityRenderDispatcher.renderPosX = camera.getX(partialTick);
+        TileEntityRenderDispatcher.renderPosY = camera.getY(partialTick);
+        TileEntityRenderDispatcher.renderPosZ = camera.getZ(partialTick);
         List<Entity> loadedEntities = worldObj.getLoadedEntityList();
         countEntitiesTotal = loadedEntities.size();
         Tessellator tessellator = Tessellator.instance;
@@ -526,7 +524,7 @@ public class RenderGlobal
 
         for (TileEntity tileEntity : tileEntities)
         {
-            BlockEntityRenderDispatcher.instance.renderTileEntity(tessellator, tileEntity, partialTick);
+            TileEntityRenderDispatcher.instance.renderTileEntity(tessellator, tileEntity, partialTick);
         }
     }
 
@@ -1381,16 +1379,15 @@ public class RenderGlobal
             	// Make sure it's active to prevent crash if a model doesnt enable it
             	tessellator.setLightmapCoord(LightmapHelper.getLightmapCoord(15, 0));
             }
-            BlockModel.setRenderBlocks(globalRenderBlocks);
             BlockModelDispatcher.getInstance()
                 .getDispatch(block)
                 .renderWithOverrideTexture(
                     tessellator,
+                    worldObj,
                     hitResult.x,
                     hitResult.y,
                     hitResult.z,
-                    breakingAnimation[MathHelper.clamp((int)(damagePartialTime * 10F), 0, breakingAnimation.length - 1)]
-                );
+                    breakingAnimation[MathHelper.clamp((int)(damagePartialTime * 10F), 0, breakingAnimation.length - 1)]);
             tessellator.draw();
             tessellator.setTranslation(0.0D, 0.0D, 0.0D);
             GL11.glDisable(GL11.GL_ALPHA_TEST);
diff --git a/game/client/src/main/java/net/minecraft/client/render/BlockEntityRenderDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java
similarity index 95%
rename from game/client/src/main/java/net/minecraft/client/render/BlockEntityRenderDispatcher.java
rename to game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java
index ff3db3266..06044da4e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/BlockEntityRenderDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java
@@ -4,17 +4,17 @@ import java.util.*;
 
 import net.minecraft.client.render.camera.ICamera;
 import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.client.render.blockentity.*;
+import net.minecraft.client.render.tileentity.*;
 import net.minecraft.core.Global;
 import net.minecraft.core.block.entity.*;
 import net.minecraft.core.block.piston.TileEntityMovingPistonBlock;
 import net.minecraft.core.world.World;
 import org.lwjgl.opengl.GL11;
 
-public class BlockEntityRenderDispatcher
+public class TileEntityRenderDispatcher
 {
 
-    private BlockEntityRenderDispatcher()
+    private TileEntityRenderDispatcher()
     {
         renderers = new HashMap<>();
         renderers.put(TileEntitySign.class, new TileEntityRendererSign());
@@ -126,7 +126,7 @@ public class BlockEntityRenderDispatcher
     }
 
     private final Map<Class<?>, TileEntityRenderer<?>> renderers;
-    public static BlockEntityRenderDispatcher instance = new BlockEntityRenderDispatcher();
+    public static TileEntityRenderDispatcher instance = new TileEntityRenderDispatcher();
     private Font font;
     public static double renderPosX;
     public static double renderPosY;
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 bb6ced0e5..fa03f360a 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
@@ -11,6 +11,8 @@ import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.weather.IPrecipitation;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.util.glu.GLU;
@@ -579,8 +581,15 @@ public class WorldRenderer
             }
             mc.currentScreen.setDesiredCursor(CursorShape.ARROW);
             mc.currentScreen.render(mouseX, mouseY, partialTick);
-            if (mc.currentScreen != null && mc.gameWindow.getCursorShape() != mc.currentScreen.getDesiredCursor()) {
-                mc.gameWindow.setCursorShape(mc.currentScreen.getDesiredCursor());
+
+            if (mc.currentScreen != null) {
+                CursorShape newCursor = mc.currentScreen.getDesiredCursor();
+                if(!mc.gameSettings.dynamicCursor.value) {
+                    newCursor = CursorShape.ARROW;
+                }
+                if (mc.gameWindow.getCursorShape() != newCursor) {
+                    mc.gameWindow.setCursorShape(newCursor);
+                }
             }
             if(mc.inputType == InputType.CONTROLLER && mc.currentScreen != null) {
                 mc.currentScreen.drawControllerCursor();
@@ -765,8 +774,8 @@ public class WorldRenderer
     private void addRainParticles()
     {
         Weather weather = mc.currentWorld.getCurrentWeather();
-        if (weather == null || !weather.spawnRainParticles) return;
-        
+        if (!(weather instanceof IPrecipitation) || !((IPrecipitation) weather).spawnRainParticles()) return;
+
         float f = mc.currentWorld.weatherManager.getWeatherIntensity() * mc.currentWorld.weatherManager.getWeatherPower();
         
         if(mc.gameSettings.fancyGraphics.value != 1)
@@ -841,7 +850,9 @@ public class WorldRenderer
     protected void renderRainSnow(float partialTick)
     {
         Weather weather = mc.currentWorld.getCurrentWeather();
-        if (weather == null || !weather.isPrecipitation) return;
+        if (!(weather instanceof IPrecipitation)) return;
+
+        final @NotNull IPrecipitation precipitation = (IPrecipitation) weather;
         
         World world = mc.currentWorld;
         int posX = MathHelper.floor(mc.activeCamera.getX());
@@ -854,7 +865,7 @@ public class WorldRenderer
         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         glAlphaFunc(516, 0.01F);
 
-        mc.textureManager.loadTexture(weather.getPrecipitationTexture(world)).bind();
+        mc.textureManager.loadTexture(precipitation.getPrecipitationTexturePath(world.weatherManager.getWeatherPower(), world.weatherManager.getWeatherIntensity())).bind();
         
         double nextPosX = mc.activeCamera.getX(partialTick);
         double nextPosY = mc.activeCamera.getY(partialTick);
@@ -862,7 +873,7 @@ public class WorldRenderer
         int floorPosY = MathHelper.floor(nextPosY);
         int radiusEffect = 10;
 
-        if (weather.precipitationType == 1)
+        if (precipitation.getPrecipitationType() == IPrecipitation.Type.SNOW_LIKE)
         {
             for(int x = posX - radiusEffect; x <= posX + radiusEffect; x++) {
                 blockedWeather:
@@ -919,7 +930,7 @@ public class WorldRenderer
 
             }
         }
-        else if (weather.precipitationType == 0)
+        else if (precipitation.getPrecipitationType() == IPrecipitation.Type.RAIN_LIKE)
         {
             for(int x = posX - radiusEffect; x <= posX + radiusEffect; x++) {
                 blockedWeather:
@@ -966,7 +977,7 @@ public class WorldRenderer
 
             }
         }
-        else if (weather.precipitationType == 2)
+        else if (precipitation.getPrecipitationType() == IPrecipitation.Type.INVERTED_RAIN_LIKE)
         {
             for(int x = posX - radiusEffect; x <= posX + radiusEffect; x++)
             {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColor.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColor.java
index c25805577..1647148dd 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColor.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColor.java
@@ -4,7 +4,7 @@ import net.minecraft.core.world.WorldSource;
 
 public abstract class BlockColor
 {
-    public abstract int getFallbackColor(int meta);
+    public abstract int getFallbackColor(int meta, int tintIndex);
 
-    public abstract int getWorldColor(WorldSource world, int x, int y, int z);
+    public abstract int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex);
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
index 914bcdba7..c14f23a9a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCrystal.java
@@ -13,7 +13,7 @@ public class BlockColorCrystal extends BlockColorCustom{
     }
     protected static ImprovedNoise crystalPerlinNoise = new ImprovedNoise(new Random(0));
     @Override
-    public int getWorldColor(WorldSource world, int x, int y, int z) {
+    public int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex) {
 
         int color = 0xc40e26;
 //        float offsetR = (float) (crystalPerlinNoise.getValue(x / 10f, z / 10f)) * 0.5f;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCustom.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCustom.java
index a0fcdb374..a0a63f884 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCustom.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorCustom.java
@@ -16,12 +16,12 @@ public class BlockColorCustom extends BlockColor {
 	}
 	
 	@Override
-	public int getFallbackColor(int meta) {
+	public int getFallbackColor(int meta, int tintIndex) {
 		return colorizer.getDefaultColor(1.0, 0.7);
 	}
 
 	@Override
-	public int getWorldColor(WorldSource world, int x, int y, int z) {
+	public int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex) {
 		return colorizer.getColor(world, x, y, z);
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorDefault.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorDefault.java
index 00083c5eb..daea781e4 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorDefault.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorDefault.java
@@ -6,13 +6,13 @@ public class BlockColorDefault
     extends BlockColor
 {
     @Override
-    public int getFallbackColor(int meta)
+    public int getFallbackColor(int meta, int tintIndex)
     {
         return 0xFFFFFF;
     }
 
     @Override
-    public int getWorldColor(WorldSource world, int x, int y, int z)
+    public int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex)
     {
         return 0xFFFFFF;
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorLeavesOak.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorLeavesOak.java
index 337c93425..ab76b451c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorLeavesOak.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorLeavesOak.java
@@ -17,8 +17,8 @@ public class BlockColorLeavesOak extends BlockColorCustom {
 	}
 	
 	@Override
-	public int getWorldColor(WorldSource world, int x, int y, int z) {
-		int color = super.getWorldColor(world, x, y, z);
+	public int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex) {
+		int color = super.getWorldColor(world, x, y, z, tintIndex);
 		
 		Season season = world.getSeasonManager().getCurrentSeason();
 		if(season != null) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorPortal.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorPortal.java
index c616f4420..a854a0bd2 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorPortal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorPortal.java
@@ -5,12 +5,12 @@ import net.minecraft.core.world.WorldSource;
 
 public class BlockColorPortal extends BlockColor{
     @Override
-    public int getFallbackColor(int meta) {
+    public int getFallbackColor(int meta, int tintIndex) {
         return Colors.allPortalColors[(meta >> 4) & 0xF].getARGB();
     }
 
     @Override
-    public int getWorldColor(WorldSource world, int x, int y, int z) {
+    public int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex) {
         return Colors.allPortalColors[(world.getBlockMetadata(x, y, z) >> 4) & 0xF].getARGB();
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorTallGrass.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorTallGrass.java
index ec0b2daa8..14e018f9d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorTallGrass.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorTallGrass.java
@@ -16,7 +16,7 @@ public class BlockColorTallGrass extends BlockColorCustom {
 	}
 	
 	@Override
-	public int getWorldColor(WorldSource world, int x, int y, int z) {
+	public int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex) {
 
 		double localTemperature = world.getBlockTemperature(x, z);
 		double localHumidity = world.getBlockHumidity(x, z);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWater.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWater.java
index f11708a46..44d929a40 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWater.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWater.java
@@ -13,19 +13,19 @@ public class BlockColorWater extends BlockColorCustom {
 	}
 	
 	@Override
-	public int getFallbackColor(int meta) {
+	public int getFallbackColor(int meta, int tintIndex) {
 		if(!mc.gameSettings.biomeWater.value || (mc.currentWorld != null && mc.currentWorld.isRetro())) {
 			return 0xFFFFFFFF;
 		}
-		return super.getFallbackColor(meta);
+		return super.getFallbackColor(meta, tintIndex);
 	}
 	
 	@Override
-	public int getWorldColor(WorldSource world, int x, int y, int z) {
+	public int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex) {
 		if(!mc.gameSettings.biomeWater.value || world.isRetro()) {
 			return 0xFFFFFFFF;
 		}
-		return super.getWorldColor(world, x, y, z);
+		return super.getWorldColor(world, x, y, z, tintIndex);
 	}
 
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWireRedstone.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWireRedstone.java
index 78483a675..9eea2d4f5 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWireRedstone.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorWireRedstone.java
@@ -8,13 +8,13 @@ public class BlockColorWireRedstone
 {
 
     @Override
-    public int getFallbackColor(int meta)
+    public int getFallbackColor(int meta, int tintIndex)
     {
         return Colors.allRedstoneColors[15].getARGB();
     }
 
     @Override
-    public int getWorldColor(WorldSource world, int x, int y, int z)
+    public int getWorldColor(WorldSource world, int x, int y, int z, int tintIndex)
     {
         // Colored by renderer
     	return Colors.allRedstoneColors[15].getARGB();
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 283fbcc7a..9fe9c3bb5 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
@@ -1,141 +1,47 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
-import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.useless.dragonfly.DisplayPos;
 
 public abstract class BlockModel<T extends BlockLogic>
 {
-    public static RenderBlocks renderBlocks;
+    public static boolean ENABLE_DIRECTIONAL_LIGHTING = true;
+    public static final float[] SIDE_LIGHT_MULTIPLIER = {0.5f, 1.0f, 0.8f, 0.8f, 0.6f, 0.6f};
+    public static final float FULL_CUBE_THRESHOLD = 1.0f / 16.0f;
+
     public final Block<T> block;
     public BlockModel(Block<T> block){
         this.block = block;
     }
-    public abstract boolean render(Tessellator tessellator, int x, int y, int z);
-    public boolean renderNoCulling(Tessellator tessellator, int x, int y, int z) {
-        renderBlocks.renderAllFaces = true;
-        boolean result = render(tessellator, x, y, z);
-        renderBlocks.renderAllFaces = false;
-        return result;
-    }
-    public boolean renderWithOverrideTexture(Tessellator tessellator, int x, int y, int z, IconCoordinate textureIndex) {
-        renderBlocks.overrideBlockTexture = textureIndex;
-        boolean result = render(tessellator, x, y, z);
-        renderBlocks.overrideBlockTexture = null;
-        return result;
-    }
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, @Nullable Integer lightmapCoordinate){
-        renderBlockOnInventory(tessellator, metadata, brightness, 1f, lightmapCoordinate);
-    }
-    public abstract void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate);
+    public abstract boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z);
+    public abstract boolean renderOverbright(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z);
+    public abstract boolean renderNoCulling(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z);
+    public abstract boolean renderWithOverrideTexture(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z, IconCoordinate textureIndex);
+    public abstract void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate);
+
     public abstract boolean shouldItemRender3d();
-    public abstract float getItemRenderScale();
+    public abstract @NotNull DisplayPos getItemDisplayPos(@NotNull String id);
 
     public int renderLayer() {
         return 0;
     }
 
-    public abstract IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side);
-    public abstract IconCoordinate getBlockOverbrightTexture(WorldSource blockAccess, int x, int y, int z, int side);
-    public abstract IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data);
-    public abstract IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data);
-    public abstract IconCoordinate getParticleTexture(Side side, int meta);
-    public abstract boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side, int meta);
-    public abstract boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side);
-    public abstract boolean shouldSideBeColored(WorldSource blockAccess, int x, int y, int z, int side, int meta);
-    public AABB getBlockBoundsForItemRender(){
-        return block.getBounds();
-    }
+    public abstract @Nullable IconCoordinate getParticleTexture(@NotNull Side side, int meta);
+    public abstract @Nullable IconCoordinate getOverlayTexture(int meta);
+    public abstract int particleColorIndex(@NotNull WorldSource worldSource, int x, int y, int z, @NotNull Side side, int meta);
+
     public boolean hasOverbright(){
         return false;
     }
     public boolean isRetro() {
         return Minecraft.getMinecraft().currentWorld != null && Minecraft.getMinecraft().currentWorld.isRetro();
     }
-    // Everything below is utility
-    public static void setRenderBlocks(RenderBlocks rb)
-    {
-        renderBlocks = rb;
-    }
-    public void resetRenderBlocks(){
-        renderBlocks.renderAllFaces = false;
-        renderBlocks.enableAO = false;
-//        renderBlocks.overbright = false;
-        renderBlocks.useInventoryTint = true;
-        renderBlocks.flipTexture = false;
-        renderBlocks.overrideBlockTexture = null;
-        renderBlocks.uvRotateEast = 0;
-        renderBlocks.uvRotateWest = 0;
-        renderBlocks.uvRotateSouth = 0;
-        renderBlocks.uvRotateNorth = 0;
-        renderBlocks.uvRotateTop = 0;
-        renderBlocks.uvRotateBottom = 0;
-        renderBlocks.field_22352_G = 1;
-        renderBlocks.renderBitMask = 0;
-        renderBlocks.forceAO = false;
-    }
-    public void setRenderSide(Side side, boolean shouldRender){
-        if (!shouldRender){
-            renderBlocks.renderBitMask |= (byte) (1 << side.getId());
-        } else {
-            renderBlocks.renderBitMask &= (byte) ~(1 << side.getId());
-        }
-    }
-    public float getBlockBrightness(WorldSource blockAccess, int x, int y, int z){
-        return renderBlocks.getBlockBrightness(blockAccess, x, y ,z);
-    }
-
-    public final boolean renderStandardBlock(Tessellator tessellator, AABB bounds, int x, int y, int z){
-        return renderBlocks.renderStandardBlock(tessellator, this, bounds, x, y, z);
-    }
-    public final boolean renderStandardBlock(Tessellator tessellator, AABB bounds, int x, int y, int z, float r, float g, float b){
-        return renderBlocks.renderStandardBlock(tessellator, this, bounds, x, y, z, r, g, b);
-    }
-    public final boolean renderSide(Tessellator tessellator,  AABB bounds, int x, int y, int z, Side side, int meta){
-        return renderBlocks.renderSide(tessellator, this, bounds, x, y, z, 1, 1, 1, side, meta);
-    }
-    public final boolean renderSide(Tessellator tessellator,  AABB bounds, int x, int y, int z, float r, float g, float b, Side side, int meta){
-        return renderBlocks.renderSide(tessellator, this, bounds, x, y, z, r, g, b, side, meta);
-    }
-    public final boolean renderSide(Tessellator tessellator,  AABB bounds, int x, int y, int z, float r, float g, float b, int side, int meta,
-                                    int dirX, int dirY, int dirZ, float depth,
-                                    int topX, int topY, int topZ, float topP, float botP,
-                                    int lefX, int lefY, int lefZ, float lefP, float rigP
-    ){
-        return renderBlocks.renderSide(tessellator, this, bounds, x, y, z, r, g, b, side, meta,
-                dirX, dirY, dirZ, depth,
-                topX, topY, topZ, topP, botP,
-                lefX, lefY, lefZ, lefP, rigP);
-    }
-
-    public final void renderBottomFace(Tessellator tessellator, AABB bounds, double x, double y, double z, IconCoordinate tex){
-        renderBlocks.renderBottomFace(tessellator, bounds, x, y, z, tex);
-    }
-
-    public final void renderTopFace(Tessellator tessellator, AABB bounds, double x, double y, double z, IconCoordinate tex){
-        renderBlocks.renderTopFace(tessellator, bounds, x, y, z, tex);
-    }
-
-    public final void renderNorthFace(Tessellator tessellator, AABB bounds, double x, double y, double z, IconCoordinate tex){
-        renderBlocks.renderNorthFace(tessellator, bounds, x, y, z, tex);
-    }
-
-    public final void renderSouthFace(Tessellator tessellator, AABB bounds, double x, double y, double z, IconCoordinate tex){
-        renderBlocks.renderSouthFace(tessellator, bounds, x, y, z, tex);
-    }
-
-    public final void renderWestFace(Tessellator tessellator, AABB bounds, double x, double y, double z, IconCoordinate tex){
-        renderBlocks.renderWestFace(tessellator, bounds, x, y, z, tex);
-    }
-
-    public final void renderEastFace(Tessellator tessellator, AABB bounds, double x, double y, double z, IconCoordinate tex){
-        renderBlocks.renderEastFace(tessellator, bounds, x, y, z, tex);
-    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelActivator.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelActivator.java
index 6ce62dc91..01e2d00c4 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelActivator.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelActivator.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicActivator;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelActivator<T extends BlockLogic> extends BlockModelVeryRotatable<T> {
     public final IconCoordinate[] poweredTextures = {
@@ -32,7 +33,7 @@ public class BlockModelActivator<T extends BlockLogic> extends BlockModelVeryRot
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if ((data & BlockLogicActivator.MASK_POWERED) != 0) {
             return poweredTextures[getRotatedSide(side, data).getId()];
@@ -42,7 +43,7 @@ public class BlockModelActivator<T extends BlockLogic> extends BlockModelVeryRot
     }
 
     @Override
-    public IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data)
+    public @Nullable IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data)
     {
         boolean isPowered = (data & BlockLogicActivator.MASK_POWERED) != 0;
         if (!isPowered) return null;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelAlgae.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelAlgae.java
index a7f25cb71..a55617fa6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelAlgae.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelAlgae.java
@@ -9,6 +9,7 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelAlgae<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelAlgae(Block<T> block) {
@@ -16,24 +17,24 @@ public class BlockModelAlgae<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        AABB bounds = block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        AABB bounds = block.getBlockBoundsFromState(worldSource, x, y, z);
         float brightness = 1.0f;
         if(!LightmapHelper.isLightmapEnabled()) {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }else {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }
 
-        int color = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(renderBlocks.blockAccess, x, y, z);
+        int color = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(worldSource, x, y, z, 0);
         float red = (float)(color >> 16 & 0xff) / 255F;
         float green = (float)(color >> 8 & 0xff) / 255F;
         float blue = (float)(color & 0xff) / 255F;
 
         tessellator.setColorOpaque_F(red * brightness, green * brightness, blue * brightness);
-        IconCoordinate tex = getBlockTextureFromSideAndMetadata(Side.TOP, renderBlocks.blockAccess.getBlockMetadata(x, y, z));
-        renderTopFace(tessellator, bounds, x, y - 0.1125, z, tex);
-        renderBottomFace(tessellator, bounds, x, y + 0.0125, z, tex);
+        IconCoordinate tex = getBlockTextureFromSideAndMetadata(Side.TOP, worldSource.getBlockMetadata(x, y, z));
+        renderBlocks.renderTopFace(tessellator, bounds, x, y - 0.1125, z, tex);
+        renderBlocks.renderBottomFace(tessellator, bounds, x, y + 0.0125, z, tex);
 
         return true;
     }
@@ -42,9 +43,9 @@ public class BlockModelAlgae<T extends BlockLogic> extends BlockModelStandard<T>
         return false;
     }
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side)
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side)
     {
-        if(side == 1)
+        if(side == Side.TOP)
         {
             return true;
         } else
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelAxisAligned.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelAxisAligned.java
index 4770216a6..a4133ec8c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelAxisAligned.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelAxisAligned.java
@@ -9,6 +9,9 @@ import net.minecraft.core.block.BlockLogicAxisAligned;
 import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.helper.Sides;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelAxisAligned<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelAxisAligned(Block<T> block) {
@@ -16,8 +19,8 @@ public class BlockModelAxisAligned<T extends BlockLogic> extends BlockModelStand
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int meta = worldSource.getBlockMetadata(x, y, z);
         Axis axis = BlockLogicAxisAligned.metaToAxis(meta);
         switch(axis)
         {
@@ -40,14 +43,14 @@ public class BlockModelAxisAligned<T extends BlockLogic> extends BlockModelStand
                 renderBlocks.uvRotateBottom = 1;
                 break;
         }
-        renderStandardBlock(tessellator, block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z), x, y, z);
-        resetRenderBlocks();
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBlockBoundsFromState(worldSource, x, y, z), x, y, z);
+        renderBlocks.resetRenderBlocks();
 
         return true;
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if ((6 * (data & 3) + side.getId()) >= Sides.orientationLookUpXYZAligned.length) return TextureRegistry.getTexture("minecraft:block/grass_top");
         return super.getBlockTextureFromSideAndMetadata(Side.getSideById(Sides.orientationLookUpXYZAligned[6 * (data & 3) + side.getId()]), data);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBasket.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBasket.java
index b95b4ed92..d80fe57bf 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBasket.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBasket.java
@@ -7,6 +7,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicBasket;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelBasket<T extends BlockLogicBasket> extends BlockModelStandard<T> {
     protected IconCoordinate fillTexture = TextureRegistry.getTexture("minecraft:block/basket/fill");
@@ -15,7 +17,7 @@ public class BlockModelBasket<T extends BlockLogicBasket> extends BlockModelStan
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         AABB bounds = block.getBounds();
         // Render basket
         final float onePix = 1.0f / 16;
@@ -23,32 +25,32 @@ public class BlockModelBasket<T extends BlockLogicBasket> extends BlockModelStan
 
         // Basket walls
         bounds.set(0, 0, 0, 1, onePix, 1);
-        renderStandardBlock(tessellator, bounds, x, y, z); // Bottom
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z); // Bottom
 
-        setRenderSide(Side.EAST, false);
-        setRenderSide(Side.WEST, false);
-        setRenderSide(Side.BOTTOM, false);
+        renderBlocks.setRenderSide(Side.EAST, false);
+        renderBlocks.setRenderSide(Side.WEST, false);
+        renderBlocks.setRenderSide(Side.BOTTOM, false);
         bounds.set(0, 0, 0, 1, basketHeight, onePix);
-        renderStandardBlock(tessellator, bounds, x, y, z); // North
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z); // North
         bounds.set(0, 0, 1 - onePix, 1, basketHeight, 1); // south
-        renderStandardBlock(tessellator, bounds, x, y, z); // South
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z); // South
         renderBlocks.renderBitMask = 0;
 
-        setRenderSide(Side.NORTH, false);
-        setRenderSide(Side.SOUTH, false);
-        setRenderSide(Side.BOTTOM, false);
+        renderBlocks.setRenderSide(Side.NORTH, false);
+        renderBlocks.setRenderSide(Side.SOUTH, false);
+        renderBlocks.setRenderSide(Side.BOTTOM, false);
         bounds.set(0, 0, 0, onePix, basketHeight, 1);
-        renderStandardBlock(tessellator, bounds, x, y, z); // West
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z); // West
         bounds.set(1 - onePix, 0, 0, 1, basketHeight, 1);
-        renderStandardBlock(tessellator, bounds, x, y, z); // East
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z); // East
         bounds.set(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
         renderBlocks.renderBitMask = 0;
 
-        final int height = block.getLogic().getFillLevel(renderBlocks.blockAccess, x, y, z);
+        final int height = block.getLogic().getFillLevel(worldSource, x, y, z);
         // Interior
         if (height > 0)
         {
-            renderTopFace(tessellator, bounds, x, (y - 1) + onePix + onePix * height, z, fillTexture);
+            renderBlocks.renderTopFace(tessellator, bounds, x, (y - 1) + onePix + onePix * height, z, fillTexture);
         }
 
         bounds.set(0, 0, 0, 1, basketHeight, 1);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBed.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBed.java
index 3976bc5cf..1287366f8 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBed.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBed.java
@@ -8,6 +8,9 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicBed;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelBed<T extends BlockLogic> extends BlockModelStandard<T> {
     protected IconCoordinate underTexture = TextureRegistry.getTexture("minecraft:block/bed/bottom");
@@ -24,18 +27,18 @@ public class BlockModelBed<T extends BlockLogic> extends BlockModelStandard<T> {
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        AABB bounds = block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        AABB bounds = block.getBlockBoundsFromState(worldSource, x, y, z);
         renderBlocks.enableAO = true;
-        renderBlocks.cache.setupCache(block, renderBlocks.blockAccess, x, y, z);
+        renderBlocks.cache.setupCache(block, worldSource, x, y, z);
 
-        final int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+        final int meta = worldSource.getBlockMetadata(x, y, z);
         final int direction = BlockLogicBed.getDirection(meta);
         final boolean isFootOfBed = BlockLogicBed.isBlockFootOfBed(meta);
 
         final double minY = bounds.minY;
         bounds.minY += 0.1875D;
-        renderSide(tessellator, bounds, x, y, z, 1f, 1f, 1f, Side.BOTTOM, meta);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1f, 1f, 1f, Side.BOTTOM, meta);
         bounds.minY = minY;
 
         if(direction == 0)
@@ -50,35 +53,35 @@ public class BlockModelBed<T extends BlockLogic> extends BlockModelStandard<T> {
         {
             renderBlocks.uvRotateTop = 3;
         }
-        renderSide(tessellator, bounds, x, y, z, Side.TOP, meta);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.TOP, meta);
 
         renderBlocks.uvRotateTop = 0;
         final int f17 = isFootOfBed ? BlockLogicBed.headOfBedMap[BlockLogicBed.footToHeadMap[direction]] : BlockLogicBed.headOfBedMap[direction];
 
-        if(f17 != 2 && (renderBlocks.renderAllFaces || shouldSideBeRendered(renderBlocks.blockAccess, bounds, x, y, z - 1, 2)))
+        if(f17 != 2 && (renderBlocks.renderAllFaces || shouldSideBeRendered(worldSource, bounds, x, y, z - 1, Side.NORTH)))
         {
             renderBlocks.flipTexture = direction == 3;
-            renderSide(tessellator, bounds, x, y, z, Side.NORTH, meta);
+            renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.NORTH, meta);
         }
 
-        if(f17 != 3 && (renderBlocks.renderAllFaces || shouldSideBeRendered(renderBlocks.blockAccess, bounds, x, y, z + 1, 3)))
+        if(f17 != 3 && (renderBlocks.renderAllFaces || shouldSideBeRendered(worldSource, bounds, x, y, z + 1, Side.SOUTH)))
         {
             renderBlocks.flipTexture = direction == 1;
-            renderSide(tessellator, bounds, x, y, z, Side.SOUTH, meta);
+            renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.SOUTH, meta);
         }
 
-        if(f17 != 4 && (renderBlocks.renderAllFaces || shouldSideBeRendered(renderBlocks.blockAccess, bounds, x - 1, y, z, 4)))
+        if(f17 != 4 && (renderBlocks.renderAllFaces || shouldSideBeRendered(worldSource, bounds, x - 1, y, z, Side.WEST)))
         {
             renderBlocks.flipTexture = direction == 2;
-            renderSide(tessellator, bounds, x, y, z, Side.WEST, meta);
+            renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.WEST, meta);
         }
 
-        if(f17 != 5 && (renderBlocks.renderAllFaces || shouldSideBeRendered(renderBlocks.blockAccess, bounds, x + 1, y, z, 5)))
+        if(f17 != 5 && (renderBlocks.renderAllFaces || shouldSideBeRendered(worldSource, bounds, x + 1, y, z, Side.EAST)))
         {
             renderBlocks.flipTexture = direction == 0;
-            renderSide(tessellator, bounds, x, y, z, Side.EAST, meta);
+            renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.EAST, meta);
         }
-        resetRenderBlocks();
+        renderBlocks.resetRenderBlocks();
         return true;
     }
     @Override
@@ -87,7 +90,7 @@ public class BlockModelBed<T extends BlockLogic> extends BlockModelStandard<T> {
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         if(side == Side.BOTTOM) {
             return underTexture;
         }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBrazier.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBrazier.java
index e19c412a0..48144a44c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBrazier.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelBrazier.java
@@ -9,6 +9,7 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -23,36 +24,36 @@ public class BlockModelBrazier<T extends BlockLogicBrazier>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         tessellator.setColorOpaque_I(0xFFFFFF);
 
         renderBlocks.enableAO = true;
-        renderBlocks.cache.setupCache(block, renderBlocks.blockAccess, x, y, z);
+        renderBlocks.cache.setupCache(block, worldSource, x, y, z);
         AABB bounds = block.getBounds();
-        renderSide(tessellator, bounds, x, y, z, Side.NORTH, 0);
-        renderSide(tessellator, bounds, x, y, z, Side.SOUTH, 0);
-        renderSide(tessellator, bounds, x, y, z, Side.EAST, 0);
-        renderSide(tessellator, bounds, x, y, z, Side.WEST, 0);
-        renderSide(tessellator, bounds, x, y, z, Side.BOTTOM, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.NORTH, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.SOUTH, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.EAST, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.WEST, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.BOTTOM, 0);
 
         final double zFightOffset = 0.005;
         bounds.set(-zFightOffset, -zFightOffset, -zFightOffset, 1 + zFightOffset, 1 + zFightOffset, 1 + zFightOffset);
-        renderSide(tessellator, bounds, x, y, z + 1, Side.NORTH, 0);
-        renderSide(tessellator, bounds, x, y, z - 1, Side.SOUTH, 0);
-        renderSide(tessellator, bounds, x - 1, y, z, Side.EAST, 0);
-        renderSide(tessellator, bounds, x + 1, y, z, Side.WEST, 0);
-        renderSide(tessellator, bounds, x, y - 1, z, Side.TOP, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z + 1, 0, 0, 0, Side.NORTH, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z - 1, 0, 0, 0, Side.SOUTH, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x - 1, y, z, 0, 0, 0, Side.EAST, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x + 1, y, z, 0, 0, 0, Side.WEST, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y - 1, z, 0, 0, 0, Side.TOP, 0);
         renderBlocks.enableAO = false;
 
         if (block.getLogic().isBurning()) {
-            fireModel.render(tessellator, x, y, z);
+            fireModel.render(tessellator, worldSource, x, y, z);
         }
 
         return true;
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         AABB bounds = block.getBounds();
         GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
 
@@ -60,59 +61,59 @@ public class BlockModelBrazier<T extends BlockLogicBrazier>
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, -1F, 0.0F);
-        renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, baseTexture);
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, baseTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        renderTopFace(tessellator, bounds, 0.0D, -1.0D, 0.0D, baseTexture);
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0D, -1.0D, 0.0D, baseTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, sideTexture);
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, sideTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 1.0D, sideTexture);
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 1.0D, sideTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, sideTexture);
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, sideTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, -1.0D, sideTexture);
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, -1.0D, sideTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, sideTexture);
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, sideTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 1.0D, 0.0D, 0.0D, sideTexture);
+        renderBlocks.renderWestFace(tessellator, bounds, 1.0D, 0.0D, 0.0D, sideTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, sideTexture);
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, sideTexture);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, -1.0D, 0.0D, 0.0D, sideTexture);
+        renderBlocks.renderEastFace(tessellator, bounds, -1.0D, 0.0D, 0.0D, sideTexture);
         tessellator.draw();
 
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
     }
 
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side) {
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side) {
         return true;
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCactus.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCactus.java
index 44b362410..55dd58cd8 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCactus.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCactus.java
@@ -6,6 +6,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -15,29 +17,29 @@ public class BlockModelCactus<T extends BlockLogic> extends BlockModelStandard<T
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         final float sidesOffset = 0.0625F;
 
         AABB bounds = block.getBounds();
         bounds.set(sidesOffset, 0, 0, 1 - sidesOffset, 1, 1);
-        setRenderSide(Side.SOUTH, false);
-        setRenderSide(Side.NORTH, false);
-        renderStandardBlock(tessellator, bounds, x, y, z);
+        renderBlocks.setRenderSide(Side.SOUTH, false);
+        renderBlocks.setRenderSide(Side.NORTH, false);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         renderBlocks.renderBitMask = 0b111111;
 
         bounds.set(0, 0, sidesOffset, 1, 1, 1 - sidesOffset);
-        setRenderSide(Side.SOUTH, true);
-        setRenderSide(Side.NORTH, true);
-        renderStandardBlock(tessellator, bounds, x, y, z);
+        renderBlocks.setRenderSide(Side.SOUTH, true);
+        renderBlocks.setRenderSide(Side.NORTH, true);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         renderBlocks.renderBitMask = 0;
 
         return true;
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate){
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate){
         if(renderBlocks.useInventoryTint)
         {
-            int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+            int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
             float r = (float)(color >> 16 & 0xff) / 255F;
             float g = (float)(color >> 8 & 0xff) / 255F;
             float b = (float)(color & 0xff) / 255F;
@@ -51,39 +53,39 @@ public class BlockModelCactus<T extends BlockLogic> extends BlockModelStandard<T
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, -1F, 0.0F);
-        renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
         tessellator.offsetTranslation(0.0F, 0.0F, sidesOffset);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
         tessellator.offsetTranslation(0.0F, 0.0F, -sidesOffset);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
         tessellator.offsetTranslation(0.0F, 0.0F, -sidesOffset);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
         tessellator.offsetTranslation(0.0F, 0.0F, sidesOffset);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
         tessellator.offsetTranslation(sidesOffset, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
         tessellator.offsetTranslation(-sidesOffset, 0.0F, 0.0F);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
         tessellator.offsetTranslation(-sidesOffset, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
         tessellator.offsetTranslation(sidesOffset, 0.0F, 0.0F);
         tessellator.draw();
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCake.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCake.java
index 47b31a82d..6086aa3ab 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCake.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCake.java
@@ -5,6 +5,7 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelCake<T extends BlockLogic> extends BlockModelStandard<T> {
     protected IconCoordinate cakeInner = TextureRegistry.getTexture("minecraft:block/cake/inner");
@@ -16,7 +17,7 @@ public class BlockModelCake<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if(data > 0 && side == Side.WEST)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCandle.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCandle.java
index 074da2f85..eb60a4427 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCandle.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCandle.java
@@ -5,6 +5,8 @@ import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelCandle<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelCandle(Block<T> block) {
@@ -12,9 +14,9 @@ public class BlockModelCandle<T extends BlockLogic> extends BlockModelStandard<T
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        boolean isLit = (renderBlocks.blockAccess.getBlockMetadata(x, y, z) & 0b00000001) == 0;
-        float brightness = isLit ? 1.0f : getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        boolean isLit = (worldSource.getBlockMetadata(x, y, z) & 0b00000001) == 0;
+        float brightness = isLit ? 1.0f : renderBlocks.getBlockBrightness(worldSource, x, y, z);
 
         float minX = x + 0.5f - (1.5f / 16f);
         float minY = y + 0f;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelChest.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelChest.java
index ab6f709d6..b753a6136 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelChest.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelChest.java
@@ -8,8 +8,15 @@ import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelChest<T extends BlockLogic> extends BlockModelStandard<T> {
+    protected static final DisplayPos CHEST_GUI = new DisplayPos(0, 0, 0, 30, 45, 0, 0.625f, 0.625f, 0.625f);
+    protected static final DisplayPos CHEST_HEAD = new DisplayPos(0, 0, 0, 0, -180, 0, 1f, 1f, 1f);
+    protected static final DisplayPos CHEST_FIRST_PERSON_RIGHT_HAND = new DisplayPos(0, 0, 0, 0, -45, 0, 0.4f, 0.4f, 0.4f);
+
     protected IconCoordinate chestFrontSingle;
     protected IconCoordinate chestFrontLeft;
     protected IconCoordinate chestFrontRight;
@@ -30,17 +37,20 @@ public class BlockModelChest<T extends BlockLogic> extends BlockModelStandard<T>
         chestBackRight = TextureRegistry.getTexture(rootKey + "right_back");
         chestSide = TextureRegistry.getTexture(rootKey + "side");
         chestTop = TextureRegistry.getTexture(rootKey + "top");
+
+        setDisplayPos(DisplayPos.GUI, CHEST_GUI);
+        setDisplayPos(DisplayPos.HEAD, CHEST_HEAD);
+        setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, CHEST_FIRST_PERSON_RIGHT_HAND);
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int meta = worldSource.getBlockMetadata(x, y, z);
         final Direction dir = BlockLogicChest.getDirectionFromMeta(meta);
         switch (dir) {
             case NORTH:
                 renderBlocks.uvRotateTop = 3;
                 break;
-
             case EAST:
                 renderBlocks.uvRotateTop = 2;
                 break;
@@ -50,13 +60,13 @@ public class BlockModelChest<T extends BlockLogic> extends BlockModelStandard<T>
                 break;
         }
 
-        renderStandardBlock(tessellator, block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z), x, y, z);
-        resetRenderBlocks();
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBlockBoundsFromState(worldSource, x, y, z), x, y, z);
+        renderBlocks.resetRenderBlocks();
         return true;
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side) {
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side) {
         int meta = blockAccess.getBlockMetadata(x, y, z);
 
         Side facing = BlockLogicChest.getDirectionFromMeta(meta).getSide();
@@ -107,7 +117,7 @@ public class BlockModelChest<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         if (side == Side.SOUTH) return chestFrontSingle;
         if (side.isHorizontal()) return chestSide;
         return chestTop;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelChestPainted.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelChestPainted.java
index 785cc6e31..f2b7c1592 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelChestPainted.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelChestPainted.java
@@ -9,6 +9,7 @@ import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelChestPainted<T extends BlockLogic> extends BlockModelChest<T> {
     public static final IconCoordinate[][] texCoords = new IconCoordinate[DyeColor.COLOR_AMOUNT][];
@@ -42,7 +43,7 @@ public class BlockModelChestPainted<T extends BlockLogic> extends BlockModelChes
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side) {
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side) {
         int meta = blockAccess.getBlockMetadata(x, y, z);
         int color = meta >> 4;
 
@@ -90,7 +91,7 @@ public class BlockModelChestPainted<T extends BlockLogic> extends BlockModelChes
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         int color = data >> 4;
         if (side == Side.SOUTH) return texCoords[color][TEX_SINGLE_FRONT];
         if (side.isHorizontal()) return texCoords[color][TEX_SIDE];
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsPumpkin.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsPumpkin.java
index 3a332973e..af2bcd3d6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsPumpkin.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsPumpkin.java
@@ -7,6 +7,9 @@ import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelCropsPumpkin<T extends BlockLogic> extends BlockModelStandard<T> {
     public static final IconCoordinate[] GROWTH_STAGE_TEXTURES_TOP = {
@@ -29,16 +32,16 @@ public class BlockModelCropsPumpkin<T extends BlockLogic> extends BlockModelStan
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
 
-        final int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+        final int meta = worldSource.getBlockMetadata(x, y, z);
         IconCoordinate leafTexture = LEAF_TEXTURE;
         if(renderBlocks.overrideBlockTexture != null)
         {
@@ -75,7 +78,7 @@ public class BlockModelCropsPumpkin<T extends BlockLogic> extends BlockModelStan
         tessellator.addVertexWithUV(xMin, yMin, zMax, uMin, vMax);
         tessellator.addVertexWithUV(xMin, yMin, zMin, uMax, vMax);
         tessellator.addVertexWithUV(xMax + extra, yMax, zMin, uMax, vMin);
-        if (meta >= 1) renderStandardBlock(tessellator, block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z), x, y, z);
+        if (meta >= 1) renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBlockBoundsFromState(worldSource, x, y, z), x, y, z);
         return true;
     }
     @Override
@@ -84,7 +87,7 @@ public class BlockModelCropsPumpkin<T extends BlockLogic> extends BlockModelStan
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         if (data < 1 || data > 4) {
             data = 1;
         }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsWheat.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsWheat.java
index 0b50edcf6..0f6b485c7 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsWheat.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsWheat.java
@@ -9,6 +9,9 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicCropsWheat;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelCropsWheat<T extends BlockLogic> extends BlockModelStandard<T> {
     public final IconCoordinate[] growthStageTextures = {
@@ -28,16 +31,16 @@ public class BlockModelCropsWheat<T extends BlockLogic> extends BlockModelStanda
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
 
-        IconCoordinate texture = getBlockTextureFromSideAndMetadata(Side.BOTTOM, renderBlocks.blockAccess.getBlockMetadata(x, y, z));
+        IconCoordinate texture = getBlockTextureFromSideAndMetadata(Side.BOTTOM, worldSource.getBlockMetadata(x, y, z));
         if(renderBlocks.overrideBlockTexture != null)
         {
             texture = renderBlocks.overrideBlockTexture;
@@ -97,7 +100,7 @@ public class BlockModelCropsWheat<T extends BlockLogic> extends BlockModelStanda
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         return growthStageTextures[MathHelper.clamp(data, 0, BlockLogicCropsWheat.MAX_GROWTH_STATE)];
     }
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 fbabfa513..c0a0ff117 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
@@ -8,15 +8,18 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelCrossedSquares(Block<T> block) {
         super(block);
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         if (LightmapHelper.isLightmapEnabled()){
             brightness = 1f;
         }
@@ -27,10 +30,10 @@ public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelSt
         GL11.glColor4f(1f, 1f, 1f,1f);
         if(renderBlocks.useInventoryTint)
         {
-            int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
-             r = (float)(color >> 16 & 0xff) / 255F;
-             g = (float)(color >> 8 & 0xff) / 255F;
-             b = (float)(color & 0xff) / 255F;
+            int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
+            r = (float)(color >> 16 & 0xff) / 255F;
+            g = (float)(color >> 8 & 0xff) / 255F;
+            b = (float)(color & 0xff) / 255F;
         }
         final float yOffset = 0.0F;
 
@@ -48,9 +51,6 @@ public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelSt
 
         tessellator.startDrawingQuads();
         tessellator.setColorRGBA_F(r * brightness, g * brightness, b * brightness, alpha);
-        if (!LightmapHelper.isLightmapEnabled()) { // TODO figure out what the hell is wrong with normals when lightmap is enabled
-            tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        }
         if (LightmapHelper.isLightmapEnabled() && lightmapCoordinate != null){
             tessellator.setLightmapCoord(lightmapCoordinate);
         }
@@ -87,15 +87,15 @@ public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelSt
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         float brightness = 1.0f;
         if(!LightmapHelper.isLightmapEnabled()) {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }else {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }
         
-        int color = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(renderBlocks.blockAccess, x, y, z);
+        int color = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(worldSource, x, y, z, 0);
         float r = (float)(color >> 16 & 0xff) / 255F;
         float g = (float)(color >> 8 & 0xff) / 255F;
         float b = (float)(color & 0xff) / 255F;
@@ -115,7 +115,7 @@ public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelSt
             zd += ((double)((float)(dRandom >> 24 & 15L) / 15F) - 0.5D) * 0.5D;
         }
 
-        int metadata = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+        int metadata = worldSource.getBlockMetadata(x, y, z);
         IconCoordinate texIndex = getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata);
         if(renderBlocks.overrideBlockTexture != null)
         {
@@ -156,8 +156,4 @@ public class BlockModelCrossedSquares<T extends BlockLogic> extends BlockModelSt
     public boolean shouldItemRender3d() {
         return false;
     }
-    @Override
-    public float getItemRenderScale() {
-        return 0.5f;
-    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrystal.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrystal.java
deleted file mode 100644
index 8a337f278..000000000
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrystal.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.minecraft.client.render.block.model;
-
-import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.core.block.Block;
-import net.minecraft.core.block.BlockLogic;
-
-public class BlockModelCrystal<T extends BlockLogic> extends BlockModelTransparent<T>{
-    public BlockModelCrystal(Block<T> block, boolean renderInside) {
-        super(block, renderInside);
-    }
-
-    @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        renderBlocks.forceAO = true;
-        boolean flag = super.render(tessellator, x, y, z);
-        renderBlocks.forceAO = false;
-        return flag;
-    }
-}
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrystallineNetherrack.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrystallineNetherrack.java
index ef7308b5d..866218565 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrystallineNetherrack.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelCrystallineNetherrack.java
@@ -1,15 +1,14 @@
 package net.minecraft.client.render.block.model;
 
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
-import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -21,22 +20,22 @@ public class BlockModelCrystallineNetherrack<T extends BlockLogic> extends Block
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        AABB bounds = block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z);
-        renderStandardBlock(tessellator, bounds, x, y, z, 1.0f, 1.0f, 1.0f);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        AABB bounds = block.getBlockBoundsFromState(worldSource, x, y, z);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z, 1.0f, 1.0f, 1.0f);
         renderBlocks.overrideBlockTexture = overlay;
-        renderStandardBlock(tessellator, bounds, x, y, z);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         renderBlocks.overrideBlockTexture = null;
         return true;
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         renderBlocks.useInventoryTint = false;
-        super.renderBlockOnInventory(tessellator, metadata, brightness, alpha, lightmapCoordinate);
+        super.renderStandalone(tessellator, metadata, brightness, alpha, lightmapCoordinate);
         renderBlocks.useInventoryTint = true;
         GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
 
-        int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+        int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
         float r = (float)(color >> 16 & 0xff) / 255F;
         float g = (float)(color >> 8 & 0xff) / 255F;
         float b = (float)(color & 0xff) / 255F;
@@ -47,27 +46,27 @@ public class BlockModelCrystallineNetherrack<T extends BlockLogic> extends Block
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, -1F, 0.0F);
-        renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, coord);
         tessellator.draw();
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
     }
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 6159348c8..40e937881 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
@@ -1,10 +1,15 @@
 package net.minecraft.client.render.block.model;
 
+import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.util.dispatch.Dispatcher;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.NotNull;
+import org.useless.dragonfly.data.block.mojang.BlockModelMojangData;
+
+import java.util.Objects;
 
 import static net.minecraft.client.render.block.model.BlockModelStandard.BLOCK_TEXTURES;
 import static net.minecraft.client.render.block.model.BlockModelStandard.OVERBRIGHT_TEXTURES;
@@ -39,9 +44,20 @@ public class BlockModelDispatcher
     {
         return modelEmpty;
     }
-    private BlockModelDispatcher()
-    {
+
+    private @NotNull BlockModelMojangData loadDataModel(@NotNull String id) {
+        Minecraft mc = Minecraft.getMinecraft();
+        return Objects.requireNonNull(BlockModelMojangData.Cache.loadModelData(mc.texturePackList, id), "Cannot find model for id '" + id + "'!");
+    }
+
+    private BlockModelDispatcher() {
         instance = this;
+        reload();
+    }
+
+    public void reload() {
+        BlockModelMojangData.Cache.resetCache();
+        dispatches.clear();
         addDispatch(new BlockModelStandard<>(Blocks.STONE).setAllTextures(BLOCK_TEXTURES, "minecraft:block/stone"));
         addDispatch(new BlockModelStandard<>(Blocks.BASALT).setAllTextures(BLOCK_TEXTURES, "minecraft:block/basalt"));
         addDispatch(new BlockModelStandard<>(Blocks.LIMESTONE).setAllTextures(BLOCK_TEXTURES, "minecraft:block/limestone"));
@@ -621,13 +637,15 @@ public class BlockModelDispatcher
             .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/bottom", Side.BOTTOM)
             .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/idle_front", Side.NORTH)
             .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/idle_back", Side.SOUTH)
-            .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/side", Side.WEST, Side.EAST));
+            .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/side", Side.WEST)
+            .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/side_slot", Side.EAST));
         addDispatch(new BlockModelHorizontalRotation<>(Blocks.TROMMEL_ACTIVE)
             .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/top", Side.TOP)
             .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/bottom", Side.BOTTOM)
             .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/active_front", Side.NORTH)
             .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/active_back", Side.SOUTH)
-            .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/side", Side.WEST, Side.EAST, Side.SOUTH));
+            .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/side", Side.WEST)
+            .setTex(BLOCK_TEXTURES, "minecraft:block/trommel/side_slot", Side.EAST));
 
         addDispatch(new BlockModelStandard<>(Blocks.CHEST_LEGACY).setAllTextures(BLOCK_TEXTURES, "minecraft:block/chest/planks/top"));
         addDispatch(new BlockModelStandard<>(Blocks.CHEST_LEGACY_PAINTED).setAllTextures(BLOCK_TEXTURES, "minecraft:block/chest/planks/top"));
@@ -650,7 +668,7 @@ public class BlockModelDispatcher
             .setTex(BLOCK_TEXTURES, "minecraft:block/slate_side", S_SIDES));
         addDispatch(new BlockModelLayer<>(Blocks.LAYER_ASH).setAllTextures(BLOCK_TEXTURES, "minecraft:block/block_ash"));
 
-        addDispatch(new BlockModelIce<>(Blocks.ICE).onRenderLayer(1).setAllTextures(BLOCK_TEXTURES, "minecraft:block/ice"));
+        addDispatch(new BlockModelTransparent<>(Blocks.ICE, false).onRenderLayer(1).setAllTextures(BLOCK_TEXTURES, "minecraft:block/ice"));
         addDispatch(new BlockModelStandard<>(Blocks.PERMAICE).setAllTextures(BLOCK_TEXTURES, "minecraft:block/permaice"));
 
         addDispatch(new BlockModelStandard<>(Blocks.BLOCK_SNOW).setAllTextures(BLOCK_TEXTURES, "minecraft:block/block_snow"));
@@ -762,6 +780,17 @@ public class BlockModelDispatcher
 
         addDispatch(new BlockModelEmpty<>(Blocks.STATUE_STONE_LOWER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/stone"));
         addDispatch(new BlockModelEmpty<>(Blocks.STATUE_STONE_UPPER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/stone"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_BASALT_LOWER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/basalt"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_BASALT_UPPER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/basalt"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_LIMESTONE_LOWER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/limestone"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_LIMESTONE_UPPER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/limestone"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_GRANITE_LOWER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/granite"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_GRANITE_UPPER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/granite"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_MARBLE_LOWER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/marble"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_MARBLE_UPPER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/marble"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_PIGMAN_LOWER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/pigman"));
+        addDispatch(new BlockModelEmpty<>(Blocks.STATUE_PIGMAN_UPPER).setAllTextures(BLOCK_TEXTURES, "minecraft:block/pigman"));
+
     }
 }
 
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 fa3bdb76e..6f9ac3165 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,108 +1,109 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicDoor;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelDoor<T extends BlockLogicDoor> extends BlockModelStandard<T> {
     public BlockModelDoor(Block<T> block) {
         super(block);
     }
     
-    public void setBrightness(Tessellator tessellator, int x, int y, int z, float sideBrightness) {
+    public void setBrightness(Tessellator tessellator, WorldSource worldSource, int x, int y, int z, float sideBrightness) {
     	float brightness = sideBrightness;
     	if(LightmapHelper.isLightmapEnabled()) {
-    		tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+    		tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
     	}else {
-    		brightness *= renderBlocks.getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+    		brightness *= renderBlocks.getBlockBrightness(worldSource, x, y, z);
     	}
     	tessellator.setColorOpaque_F(brightness, brightness, brightness);
     }
     
     @Override
-	public boolean render(Tessellator tessellator, int x, int y, int z) {
+	public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
     	if(LightmapHelper.isLightmapEnabled()) {
     		tessellator.setLightmapCoord(LightmapHelper.getLightmapCoord(15, 15));
     	}
     	tessellator.setColorOpaque_F(1.0f, 1.0f, 1.0f);
 
-		AABB bounds = block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z);
+		AABB bounds = block.getBlockBoundsFromState(worldSource, x, y, z);
 
 		float sideBottom = 1.0f;
 		float sideTop = 1.0f;
 		float sideNorthSouth = 1.0f;
 		float sideEastWest = 1.0f;
-		if(RenderBlocks.enableDirectionalLight) {
+		if(ENABLE_DIRECTIONAL_LIGHTING) {
 			sideBottom = 0.5f;
 			sideTop = 1.0f;
 			sideNorthSouth = 0.8f;
 			sideEastWest = 0.6f;
 		}
 		
-		boolean aboveIsDoor = Block.hasLogicClass(renderBlocks.blockAccess.getBlock(x, y + 1, z), BlockLogicDoor.class);
-		boolean belowIsDoor = Block.hasLogicClass(renderBlocks.blockAccess.getBlock(x, y - 1, z), BlockLogicDoor.class);
+		boolean aboveIsDoor = Block.hasLogicClass(worldSource.getBlock(x, y + 1, z), BlockLogicDoor.class);
+		boolean belowIsDoor = Block.hasLogicClass(worldSource.getBlock(x, y - 1, z), BlockLogicDoor.class);
 
-		int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+		int meta = worldSource.getBlockMetadata(x, y, z);
 		
 		// Bottom
 		if(!belowIsDoor) {
-			setBrightness(tessellator, x, y - 1, z, sideBottom);
-			renderBottomFace(tessellator, bounds, x, y, z, getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.BOTTOM));
+			setBrightness(tessellator, worldSource, x, y - 1, z, sideBottom);
+			renderBlocks.renderBottomFace(tessellator, bounds, x, y, z, getBlockTexture(worldSource, x, y, z, Side.BOTTOM));
 		}
 		
 		// Top
 		if(!aboveIsDoor) {
-			setBrightness(tessellator, x, y + 1, z, sideTop);
-			renderTopFace(tessellator, bounds, x, y, z, getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.TOP));
+			setBrightness(tessellator, worldSource, x, y + 1, z, sideTop);
+			renderBlocks.renderTopFace(tessellator, bounds, x, y, z, getBlockTexture(worldSource, x, y, z, Side.TOP));
 		}
 		
 		// North
-		if(bounds.minZ > RenderBlocks.FULL_CUBE_THRESHOLD) {
-			setBrightness(tessellator, x, y, z, sideNorthSouth);
+		if(bounds.minZ > FULL_CUBE_THRESHOLD) {
+			setBrightness(tessellator, worldSource, x, y, z, sideNorthSouth);
 		}else {
-			setBrightness(tessellator, x, y, z - 1, sideNorthSouth);
+			setBrightness(tessellator, worldSource, x, y, z - 1, sideNorthSouth);
 		}
 		renderBlocks.flipTexture = shouldFlipTexture(Side.NORTH, meta);
-		IconCoordinate texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.NORTH);
-		renderNorthFace(tessellator, bounds, x, y, z, texture);
+		IconCoordinate texture = getBlockTexture(worldSource, x, y, z, Side.NORTH);
+		renderBlocks.renderNorthFace(tessellator, bounds, x, y, z, texture);
 		renderBlocks.flipTexture = false;
 		
 		// South
-		if(bounds.maxZ < 1.0f - RenderBlocks.FULL_CUBE_THRESHOLD) {
-			setBrightness(tessellator, x, y, z, sideNorthSouth);
+		if(bounds.maxZ < 1.0f - FULL_CUBE_THRESHOLD) {
+			setBrightness(tessellator, worldSource, x, y, z, sideNorthSouth);
 		}else {
-			setBrightness(tessellator, x, y, z + 1, sideNorthSouth);
+			setBrightness(tessellator, worldSource, x, y, z + 1, sideNorthSouth);
 		}
 		renderBlocks.flipTexture = shouldFlipTexture(Side.SOUTH, meta);
-		texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.SOUTH);
-		renderSouthFace(tessellator, bounds, x, y, z, texture);
+		texture = getBlockTexture(worldSource, x, y, z, Side.SOUTH);
+		renderBlocks.renderSouthFace(tessellator, bounds, x, y, z, texture);
 		renderBlocks.flipTexture = false;
 		
 		// West
-		if(bounds.minX > RenderBlocks.FULL_CUBE_THRESHOLD) {
-			setBrightness(tessellator, x, y, z, sideEastWest);
+		if(bounds.minX > FULL_CUBE_THRESHOLD) {
+			setBrightness(tessellator, worldSource, x, y, z, sideEastWest);
 		}else {
-			setBrightness(tessellator, x - 1, y, z, sideEastWest);
+			setBrightness(tessellator, worldSource, x - 1, y, z, sideEastWest);
 		}
 		renderBlocks.flipTexture = shouldFlipTexture(Side.WEST, meta);
-		texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.WEST);
-		renderWestFace(tessellator, bounds, x, y, z, texture);
+		texture = getBlockTexture(worldSource, x, y, z, Side.WEST);
+		renderBlocks.renderWestFace(tessellator, bounds, x, y, z, texture);
 		renderBlocks.flipTexture = false;
 		
 		// East
-		if(bounds.maxX < 1.0f - RenderBlocks.FULL_CUBE_THRESHOLD) {
-			setBrightness(tessellator, x, y, z, sideEastWest);
+		if(bounds.maxX < 1.0f - FULL_CUBE_THRESHOLD) {
+			setBrightness(tessellator, worldSource, x, y, z, sideEastWest);
 		}else {
-			setBrightness(tessellator, x + 1, y, z, sideEastWest);
+			setBrightness(tessellator, worldSource, x + 1, y, z, sideEastWest);
 		}
 		renderBlocks.flipTexture = shouldFlipTexture(Side.EAST, meta);
-		texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.EAST);
-		renderEastFace(tessellator, bounds, x, y, z, texture);
+		texture = getBlockTexture(worldSource, x, y, z, Side.EAST);
+		renderBlocks.renderEastFace(tessellator, bounds, x, y, z, texture);
 		renderBlocks.flipTexture = false;
 		return true;
 	}
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDoorPainted.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDoorPainted.java
index 8eca872ad..5e9e61c16 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDoorPainted.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDoorPainted.java
@@ -7,6 +7,7 @@ import net.minecraft.core.block.BlockLogicDoor;
 import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelDoorPainted<T extends BlockLogicDoor> extends BlockModelDoor<T> {
     public static final IconCoordinate[] doorBottomTextures = new IconCoordinate[DyeColor.COLOR_AMOUNT];
@@ -26,7 +27,7 @@ public class BlockModelDoorPainted<T extends BlockLogicDoor> extends BlockModelD
         this.isTop = isTop;
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         int color = (data >> 4) & DyeColor.MASK_COLOR;
         if (side.getAxis() == Axis.Y){
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 8c01dacce..1c3644656 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
@@ -5,6 +5,8 @@ import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class BlockModelEmpty<T extends BlockLogic> extends BlockModelStandard<T> {
@@ -13,17 +15,17 @@ public class BlockModelEmpty<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         return false;
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
 
     }
 
     @Override
-    public IconCoordinate getParticleTexture(Side side, int meta) {
+    public @Nullable IconCoordinate getParticleTexture(@NotNull Side side, int meta) {
         return null;
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFarmland.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFarmland.java
index f15b2aa0a..d3e746ab6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFarmland.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFarmland.java
@@ -6,8 +6,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicFarmland;
 import net.minecraft.core.util.helper.Side;
-import net.minecraft.core.util.phys.AABB;
-import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelFarmland<T extends BlockLogic> extends BlockModelStandard<T> {
     protected IconCoordinate topWet = TextureRegistry.getTexture("minecraft:block/farmland/wet_top");
@@ -21,7 +20,7 @@ public class BlockModelFarmland<T extends BlockLogic> extends BlockModelStandard
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, final int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, final int data)
     {
         boolean isWet = BlockLogicFarmland.isWet(data);
         boolean isFertilized = BlockLogicFarmland.isFertilized(data);
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 28346c6b2..4b1b4ccf9 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
@@ -6,35 +6,43 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicFence;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelFence<T  extends BlockLogicFence> extends BlockModelStandard<T> {
+    protected static final DisplayPos FENCE_GUI = new DisplayPos(0, 0, 0, 30, 225 - 90, 0, 0.625f, 0.625f, 0.625f);
+    protected static final DisplayPos FENCE_HEAD = new DisplayPos(0, 0, 0, 0, 90, 0, 1f, 1f, 1f);
     public BlockModelFence(Block<T> block) {
         super(block);
+
+        setDisplayPos(DisplayPos.GUI, FENCE_GUI);
+        setDisplayPos(DisplayPos.HEAD, FENCE_HEAD);
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         final float f = 0.375F;
         final float f1 = 0.625F;
         AABB bounds = AABB.getTemporaryBB(f, 0.0F, f, f1, 1.0F, f1);
-        renderStandardBlock(tessellator, bounds, x, y, z);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         boolean flag1 = false;
         boolean flag2 = false;
         BlockLogicFence fence = block.getLogic();
-        if(fence.canConnectTo(renderBlocks.blockAccess, x - 1, y, z) || fence.canConnectTo(renderBlocks.blockAccess, x + 1, y, z))
+        if(fence.canConnectTo(worldSource, x - 1, y, z) || fence.canConnectTo(worldSource, x + 1, y, z))
         {
             flag1 = true;
         }
-        if(fence.canConnectTo(renderBlocks.blockAccess, x, y, z - 1) || fence.canConnectTo(renderBlocks.blockAccess, x, y, z + 1))
+        if(fence.canConnectTo(worldSource, x, y, z - 1) || fence.canConnectTo(worldSource, x, y, z + 1))
         {
             flag2 = true;
         }
-        boolean flag3 = fence.canConnectTo(renderBlocks.blockAccess, x - 1, y, z);
-        boolean flag4 = fence.canConnectTo(renderBlocks.blockAccess, x + 1, y, z);
-        boolean flag5 = fence.canConnectTo(renderBlocks.blockAccess, x, y, z - 1);
-        boolean flag6 = fence.canConnectTo(renderBlocks.blockAccess, x, y, z + 1);
+        boolean flag3 = fence.canConnectTo(worldSource, x - 1, y, z);
+        boolean flag4 = fence.canConnectTo(worldSource, x + 1, y, z);
+        boolean flag5 = fence.canConnectTo(worldSource, x, y, z - 1);
+        boolean flag6 = fence.canConnectTo(worldSource, x, y, z + 1);
         if(!flag1 && !flag2)
         {
             flag1 = true;
@@ -50,33 +58,33 @@ public class BlockModelFence<T  extends BlockLogicFence> extends BlockModelStand
         if(flag1)
         {
             bounds.set(f4, f2, f8, f5, f3, f9);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if(flag2)
         {
             bounds.set(f8, f2, f6, f9, f3, f7);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         final float f10 = 0.375F;
         final float f11 = 0.5625F;
         if(flag1)
         {
             bounds.set(f4, f10, f8, f5, f11, f9);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if(flag2)
         {
             bounds.set(f8, f10, f6, f9, f11, f7);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         return true;
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         if(renderBlocks.useInventoryTint)
         {
-            int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+            int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
             float r = (float)(color >> 16 & 0xff) / 255F;
             float g = (float)(color >> 8 & 0xff) / 255F;
             float b = (float)(color & 0xff) / 255F;
@@ -109,32 +117,32 @@ public class BlockModelFence<T  extends BlockLogicFence> extends BlockModelStand
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, -1F, 0.0F);
-            renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
+            renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 1.0F, 0.0F);
-            renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
+            renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, -1F);
-            renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
+            renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, 1.0F);
-            renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
+            renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(-1F, 0.0F, 0.0F);
-            renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
+            renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(1.0F, 0.0F, 0.0F);
-            renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
+            renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
             tessellator.draw();
         }
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
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 7adc7272d..fcc30d43d 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
@@ -6,19 +6,27 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicFenceGate;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelFenceGate<T extends BlockLogicFenceGate> extends BlockModelStandard<T> {
+    protected static final DisplayPos FENCE_GUI = new DisplayPos(0, 0, 0, 30, 225 - 90, 0, 0.625f, 0.625f, 0.625f);
+    protected static final DisplayPos FENCE_HEAD = new DisplayPos(0, 0, 0, 0, 90, 0, 1f, 1f, 1f);
     public BlockModelFenceGate(Block<T> block) {
         super(block);
+
+        setDisplayPos(DisplayPos.GUI, FENCE_GUI);
+        setDisplayPos(DisplayPos.HEAD, FENCE_HEAD);
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         AABB bounds = block.getBounds();
         boolean flag = true;
-        int l = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+        int l = worldSource.getBlockMetadata(x, y, z);
         boolean flag1 = BlockLogicFenceGate.isOpen(l);
         int i1 = BlockLogicFenceGate.getDirection(l);
         if(i1 == 3 || i1 == 1)
@@ -28,11 +36,11 @@ public class BlockModelFenceGate<T extends BlockLogicFenceGate> extends BlockMod
             float f8 = 0.0F;
             float f12 = 0.125F;
             bounds.set(f, 0.3125F, f8, f4, 1.0F, f12);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             f8 = 0.875F;
             f12 = 1.0F;
             bounds.set(f, 0.3125F, f8, f4, 1.0F, f12);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         } else
         {
             float f1 = 0.0F;
@@ -40,11 +48,11 @@ public class BlockModelFenceGate<T extends BlockLogicFenceGate> extends BlockMod
             float f9 = 0.4375F;
             float f13 = 0.5625F;
             bounds.set(f1, 0.3125F, f9, f5, 1.0F, f13);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             f1 = 0.875F;
             f5 = 1.0F;
             bounds.set(f1, 0.3125F, f9, f5, 1.0F, f13);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if(!flag1)
         {
@@ -55,23 +63,23 @@ public class BlockModelFenceGate<T extends BlockLogicFenceGate> extends BlockMod
                 float f10 = 0.375F;
                 float f14 = 0.5F;
                 bounds.set(f2, 0.375F, f10, f6, 0.9375F, f14);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 f10 = 0.5F;
                 f14 = 0.625F;
                 bounds.set(f2, 0.375F, f10, f6, 0.9375F, f14);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 f10 = 0.625F;
                 f14 = 0.875F;
                 bounds.set(f2, 0.375F, f10, f6, 0.5625F, f14);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 bounds.set(f2, 0.75F, f10, f6, 0.9375F, f14);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 f10 = 0.125F;
                 f14 = 0.375F;
                 bounds.set(f2, 0.375F, f10, f6, 0.5625F, f14);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 bounds.set(f2, 0.75F, f10, f6, 0.9375F, f14);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             } else
             {
                 float f3 = 0.375F;
@@ -79,93 +87,93 @@ public class BlockModelFenceGate<T extends BlockLogicFenceGate> extends BlockMod
                 float f11 = 0.4375F;
                 float f15 = 0.5625F;
                 bounds.set(f3, 0.375F, f11, f7, 0.9375F, f15);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 f3 = 0.5F;
                 f7 = 0.625F;
                 bounds.set(f3, 0.375F, f11, f7, 0.9375F, f15);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 f3 = 0.625F;
                 f7 = 0.875F;
                 bounds.set(f3, 0.375F, f11, f7, 0.5625F, f15);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 bounds.set(f3, 0.75F, f11, f7, 0.9375F, f15);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 f3 = 0.125F;
                 f7 = 0.375F;
                 bounds.set(f3, 0.375F, f11, f7, 0.5625F, f15);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
                 bounds.set(f3, 0.75F, f11, f7, 0.9375F, f15);
-                renderStandardBlock(tessellator, bounds, x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             }
         } else
         if(i1 == 3)
         {
             bounds.set(0.8125F, 0.375F, 0.0F, 0.9375F, 0.9375F, 0.125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.8125F, 0.375F, 0.875F, 0.9375F, 0.9375F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.5625F, 0.375F, 0.0F, 0.8125F, 0.5625F, 0.125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.5625F, 0.375F, 0.875F, 0.8125F, 0.5625F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.5625F, 0.75F, 0.0F, 0.8125F, 0.9375F, 0.125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.5625F, 0.75F, 0.875F, 0.8125F, 0.9375F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         } else
         if(i1 == 1)
         {
             bounds.set(0.0625F, 0.375F, 0.0F, 0.1875F, 0.9375F, 0.125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.0625F, 0.375F, 0.875F, 0.1875F, 0.9375F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.1875F, 0.375F, 0.0F, 0.4375F, 0.5625F, 0.125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.1875F, 0.375F, 0.875F, 0.4375F, 0.5625F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.1875F, 0.75F, 0.0F, 0.4375F, 0.9375F, 0.125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.1875F, 0.75F, 0.875F, 0.4375F, 0.9375F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         } else
         if(i1 == 0)
         {
             bounds.set(0.0F, 0.375F, 0.8125F, 0.125F, 0.9375F, 0.9375F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.875F, 0.375F, 0.8125F, 1.0F, 0.9375F, 0.9375F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.0F, 0.375F, 0.5625F, 0.125F, 0.5625F, 0.8125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.875F, 0.375F, 0.5625F, 1.0F, 0.5625F, 0.8125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.0F, 0.75F, 0.5625F, 0.125F, 0.9375F, 0.8125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.875F, 0.75F, 0.5625F, 1.0F, 0.9375F, 0.8125F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         } else
         if(i1 == 2)
         {
             bounds.set(0.0F, 0.375F, 0.0625F, 0.125F, 0.9375F, 0.1875F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.875F, 0.375F, 0.0625F, 1.0F, 0.9375F, 0.1875F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.0F, 0.375F, 0.1875F, 0.125F, 0.5625F, 0.4375F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.875F, 0.375F, 0.1875F, 1.0F, 0.5625F, 0.4375F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.0F, 0.75F, 0.1875F, 0.125F, 0.9375F, 0.4375F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.875F, 0.75F, 0.1875F, 1.0F, 0.9375F, 0.4375F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         return flag;
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         if(renderBlocks.useInventoryTint)
         {
-            int j = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+            int j = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
             float f1 = (float)(j >> 16 & 0xff) / 255F;
             float f3 = (float)(j >> 8 & 0xff) / 255F;
             float f5 = (float)(j & 0xff) / 255F;
@@ -190,32 +198,32 @@ public class BlockModelFenceGate<T extends BlockLogicFenceGate> extends BlockMod
             GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, -1F, 0.0F);
-            renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
+            renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 1.0F, 0.0F);
-            renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
+            renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, -1F);
-            renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
+            renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, 1.0F);
-            renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
+            renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(-1F, 0.0F, 0.0F);
-            renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
+            renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(1.0F, 0.0F, 0.0F);
-            renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
+            renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
             tessellator.draw();
             GL11.glTranslatef(0.5F, 0.5F, 0.5F);
         }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceGatePainted.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceGatePainted.java
index ab9ed48ad..e8b5811dc 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceGatePainted.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceGatePainted.java
@@ -4,6 +4,7 @@ import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicFenceGate;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelFenceGatePainted<T extends BlockLogicFenceGate> extends BlockModelFenceGate<T> {
     public BlockModelFenceGatePainted(Block<T> block) {
@@ -11,7 +12,7 @@ public class BlockModelFenceGatePainted<T extends BlockLogicFenceGate> extends B
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
         meta = meta >> 4;
         return BlockModelPlanksPainted.texCoords[meta & 0x0F];
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFencePainted.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFencePainted.java
index ed0480db3..d953a6520 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFencePainted.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFencePainted.java
@@ -4,6 +4,7 @@ import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicFence;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelFencePainted<T extends BlockLogicFence> extends BlockModelFence<T> {
 
@@ -13,7 +14,7 @@ public class BlockModelFencePainted<T extends BlockLogicFence> extends BlockMode
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
         return BlockModelPlanksPainted.texCoords[meta & 15];
     }
 }
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 416c521bc..30eeb51bd 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
@@ -1,7 +1,6 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
@@ -9,10 +8,14 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicFenceThin;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockModelStandard<T> {
+    protected static final DisplayPos FENCE_THIN_FIRST_PERSON_RIGHT_HAND = new DisplayPos(0, 0, 0, 0, 45 - 90, 0, 0.4f, 0.4f, 0.4f);
     private final IconCoordinate texIndex;
     private final IconCoordinate bottomTexIndex;
     private final IconCoordinate topTexIndex;
@@ -24,14 +27,16 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
         this.bottomTexIndex = bottomTexIndex;
         this.topTexIndex = topTexIndex;
         this.columnTexIndex = columnTexIndex;
+
+        setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, FENCE_THIN_FIRST_PERSON_RIGHT_HAND);
     }
     @Override
-    public boolean render(Tessellator t, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator t, @NotNull WorldSource worldSource, int x, int y, int z) {
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	t.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	t.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }
         t.setColorOpaque_F(brightness, brightness, brightness);
         
@@ -39,17 +44,17 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
 		float cTop = 1.0f;
 		float cNorthSouth = 1.0f;
 		float cEastWest = 1.0f;
-		if(RenderBlocks.enableDirectionalLight) {
+		if(ENABLE_DIRECTIONAL_LIGHTING) {
 			cBottom = 0.5f;
 			cTop = 1.0f;
 			cNorthSouth = 0.8f;
 			cEastWest = 0.6f;
 		}
         BlockLogicFenceThin thin = block.getLogic();
-        boolean connectNorth = thin.canConnectTo(renderBlocks.blockAccess, x + Direction.NORTH.getOffsetX(), y + Direction.NORTH.getOffsetY(), z + Direction.NORTH.getOffsetZ());
-        boolean connectSouth = thin.canConnectTo(renderBlocks.blockAccess, x + Direction.SOUTH.getOffsetX(), y + Direction.SOUTH.getOffsetY(), z + Direction.SOUTH.getOffsetZ());
-        boolean connectEast = thin.canConnectTo(renderBlocks.blockAccess, x + Direction.EAST.getOffsetX(), y + Direction.EAST.getOffsetY(), z + Direction.EAST.getOffsetZ());
-        boolean connectWest = thin.canConnectTo(renderBlocks.blockAccess, x + Direction.WEST.getOffsetX(), y + Direction.WEST.getOffsetY(), z + Direction.WEST.getOffsetZ());
+        boolean connectNorth = thin.canConnectTo(worldSource, x + Direction.NORTH.getOffsetX(), y + Direction.NORTH.getOffsetY(), z + Direction.NORTH.getOffsetZ());
+        boolean connectSouth = thin.canConnectTo(worldSource, x + Direction.SOUTH.getOffsetX(), y + Direction.SOUTH.getOffsetY(), z + Direction.SOUTH.getOffsetZ());
+        boolean connectEast = thin.canConnectTo(worldSource, x + Direction.EAST.getOffsetX(), y + Direction.EAST.getOffsetY(), z + Direction.EAST.getOffsetZ());
+        boolean connectWest = thin.canConnectTo(worldSource, x + Direction.WEST.getOffsetX(), y + Direction.WEST.getOffsetY(), z + Direction.WEST.getOffsetZ());
 
         boolean lineNorthSouth = connectNorth && connectSouth;
         boolean lineEastWest = connectEast && connectWest;
@@ -85,19 +90,19 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
         double fenceBottommostMaxU = fenceBottommostTex.getSubIconU(onePix * 16);
         double fenceBottommostMaxV = fenceBottommostTex.getSubIconV(onePix * 16);
 
-        Block<?> blockAbove = renderBlocks.blockAccess.getBlock(x, y + 1, z);
-        boolean connectUpNorth = blockAbove == block && thin.canConnectTo(renderBlocks.blockAccess, x + Direction.NORTH.getOffsetX(), y + Direction.NORTH.getOffsetY() + 1, z + Direction.NORTH.getOffsetZ());
-        boolean connectUpSouth = blockAbove == block && thin.canConnectTo(renderBlocks.blockAccess, x + Direction.SOUTH.getOffsetX(), y + Direction.SOUTH.getOffsetY() + 1, z + Direction.SOUTH.getOffsetZ());
-        boolean connectUpEast = blockAbove == block && thin.canConnectTo(renderBlocks.blockAccess, x + Direction.EAST.getOffsetX(), y + Direction.EAST.getOffsetY() + 1, z + Direction.EAST.getOffsetZ());
-        boolean connectUpWest = blockAbove == block && thin.canConnectTo(renderBlocks.blockAccess, x + Direction.WEST.getOffsetX(), y + Direction.WEST.getOffsetY() + 1, z + Direction.WEST.getOffsetZ());
+        Block<?> blockAbove = worldSource.getBlock(x, y + 1, z);
+        boolean connectUpNorth = blockAbove == block && thin.canConnectTo(worldSource, x + Direction.NORTH.getOffsetX(), y + Direction.NORTH.getOffsetY() + 1, z + Direction.NORTH.getOffsetZ());
+        boolean connectUpSouth = blockAbove == block && thin.canConnectTo(worldSource, x + Direction.SOUTH.getOffsetX(), y + Direction.SOUTH.getOffsetY() + 1, z + Direction.SOUTH.getOffsetZ());
+        boolean connectUpEast = blockAbove == block && thin.canConnectTo(worldSource, x + Direction.EAST.getOffsetX(), y + Direction.EAST.getOffsetY() + 1, z + Direction.EAST.getOffsetZ());
+        boolean connectUpWest = blockAbove == block && thin.canConnectTo(worldSource, x + Direction.WEST.getOffsetX(), y + Direction.WEST.getOffsetY() + 1, z + Direction.WEST.getOffsetZ());
 
-        Block<?> blockBelow = renderBlocks.blockAccess.getBlock(x, y - 1, z);
-        boolean connectDownNorth = blockBelow == block && thin.canConnectTo(renderBlocks.blockAccess, x + Direction.NORTH.getOffsetX(), y + Direction.NORTH.getOffsetY() - 1, z + Direction.NORTH.getOffsetZ());
-        boolean connectDownSouth = blockBelow == block && thin.canConnectTo(renderBlocks.blockAccess, x + Direction.SOUTH.getOffsetX(), y + Direction.SOUTH.getOffsetY() - 1, z + Direction.SOUTH.getOffsetZ());
-        boolean connectDownEast = blockBelow == block && thin.canConnectTo(renderBlocks.blockAccess, x + Direction.EAST.getOffsetX(), y + Direction.EAST.getOffsetY() - 1, z + Direction.EAST.getOffsetZ());
-        boolean connectDownWest = blockBelow == block && thin.canConnectTo(renderBlocks.blockAccess, x + Direction.WEST.getOffsetX(), y + Direction.WEST.getOffsetY() - 1, z + Direction.WEST.getOffsetZ());
+        Block<?> blockBelow = worldSource.getBlock(x, y - 1, z);
+        boolean connectDownNorth = blockBelow == block && thin.canConnectTo(worldSource, x + Direction.NORTH.getOffsetX(), y + Direction.NORTH.getOffsetY() - 1, z + Direction.NORTH.getOffsetZ());
+        boolean connectDownSouth = blockBelow == block && thin.canConnectTo(worldSource, x + Direction.SOUTH.getOffsetX(), y + Direction.SOUTH.getOffsetY() - 1, z + Direction.SOUTH.getOffsetZ());
+        boolean connectDownEast = blockBelow == block && thin.canConnectTo(worldSource, x + Direction.EAST.getOffsetX(), y + Direction.EAST.getOffsetY() - 1, z + Direction.EAST.getOffsetZ());
+        boolean connectDownWest = blockBelow == block && thin.canConnectTo(worldSource, x + Direction.WEST.getOffsetX(), y + Direction.WEST.getOffsetY() - 1, z + Direction.WEST.getOffsetZ());
 
-        if (thin.shouldDrawColumn(renderBlocks.blockAccess, x, y, z))
+        if (thin.shouldDrawColumn(worldSource, x, y, z))
         {
             double sidesMinU = columnTexIndex.getIconUMin();
             double sidesMinV = columnTexIndex.getIconVMin();
@@ -350,10 +355,10 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         if(renderBlocks.useInventoryTint)
         {
-            int j = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+            int j = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
             float f1 = (float)(j >> 16 & 0xff) / 255F;
             float f3 = (float)(j >> 8 & 0xff) / 255F;
             float f5 = (float)(j & 0xff) / 255F;
@@ -374,32 +379,32 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
             GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, -1F, 0.0F);
-            renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
+            renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 1.0F, 0.0F);
-            renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
+            renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, -1F);
-            renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
+            renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, 1.0F);
-            renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
+            renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(-1F, 0.0F, 0.0F);
-            renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
+            renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(1.0F, 0.0F, 0.0F);
-            renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
+            renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, columnTexIndex);
             tessellator.draw();
             GL11.glPopMatrix();
         }
@@ -409,7 +414,7 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
         bounds.set(0, 0, 0, 0.5f, 1, 1);
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0, 0, 0, texIndex);
+        renderBlocks.renderEastFace(tessellator, bounds, 0, 0, 0, texIndex);
         tessellator.draw();
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
     }
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 92c7ab6e3..dd4bbef8f 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
@@ -8,6 +8,8 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicFire;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T> {
     private final boolean overrideRender;
@@ -21,17 +23,17 @@ public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        IconCoordinate tex = getBlockTextureFromSideAndMetadata(Side.BOTTOM, renderBlocks.blockAccess.getBlockMetadata(x, y, z));
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        IconCoordinate tex = getBlockTextureFromSideAndMetadata(Side.BOTTOM, worldSource.getBlockMetadata(x, y, z));
         if(renderBlocks.overrideBlockTexture != null)
         {
             tex = renderBlocks.overrideBlockTexture;
         }
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	tessellator.setLightmapCoord(LightmapHelper.getOverbrightLightmapCoord(renderBlocks.blockAccess.getSavedLightValue(LightLayer.Sky, x, y, z)));
+        	tessellator.setLightmapCoord(LightmapHelper.getOverbrightLightmapCoord(worldSource.getSavedLightValue(LightLayer.Sky, x, y, z)));
         }else {
-        	brightness = renderBlocks.getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
         double uMin = tex.getIconUMin();
@@ -39,7 +41,7 @@ public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T>
         double vMin = tex.getIconVMin();
         double vMax = tex.getIconVMax();
         final float yOffset = 1.4F;
-        if(overrideRender || renderBlocks.blockAccess.isBlockNormalCube(x, y - 1, z) || BlockLogicFire.canBurn(renderBlocks.blockAccess, x, y - 1, z))
+        if(overrideRender || worldSource.isBlockNormalCube(x, y - 1, z) || BlockLogicFire.canBurn(worldSource, x, y - 1, z))
         {
             double d8 = (double)x + 0.5D + 0.2D;
             double d9 = ((double)x + 0.5D) - 0.2D;
@@ -114,7 +116,7 @@ public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T>
                 uMax = uMin;
                 uMin = d10;
             }
-            if(BlockLogicFire.canBurn(renderBlocks.blockAccess, x - 1, y, z))
+            if(BlockLogicFire.canBurn(worldSource, x - 1, y, z))
             {
                 tessellator.addVertexWithUV((float)x + f3, (float)y + yOffset + f4, z + 1, uMax, vMin);
                 tessellator.addVertexWithUV(x, (float)(y) + f4, z + 1, uMax, vMax);
@@ -125,7 +127,7 @@ public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T>
                 tessellator.addVertexWithUV(x, (float)(y) + f4, z + 1, uMax, vMax);
                 tessellator.addVertexWithUV((float)x + f3, (float)y + yOffset + f4, z + 1, uMax, vMin);
             }
-            if(BlockLogicFire.canBurn(renderBlocks.blockAccess, x + 1, y, z))
+            if(BlockLogicFire.canBurn(worldSource, x + 1, y, z))
             {
                 tessellator.addVertexWithUV((float)(x + 1) - f3, (float)y + yOffset + f4, z, uMin, vMin);
                 tessellator.addVertexWithUV((x + 1), (float)(y) + f4, z, uMin, vMax);
@@ -136,7 +138,7 @@ public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T>
                 tessellator.addVertexWithUV((x + 1), (float)(y) + f4, z, uMin, vMax);
                 tessellator.addVertexWithUV((float)(x + 1) - f3, (float)y + yOffset + f4, z, uMin, vMin);
             }
-            if(BlockLogicFire.canBurn(renderBlocks.blockAccess, x, y, z - 1))
+            if(BlockLogicFire.canBurn(worldSource, x, y, z - 1))
             {
                 tessellator.addVertexWithUV(x, (float)y + yOffset + f4, (float)z + f3, uMax, vMin);
                 tessellator.addVertexWithUV(x, (float)(y) + f4, z, uMax, vMax);
@@ -147,7 +149,7 @@ public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T>
                 tessellator.addVertexWithUV(x, (float)(y) + f4, z, uMax, vMax);
                 tessellator.addVertexWithUV(x, (float)y + yOffset + f4, (float)z + f3, uMax, vMin);
             }
-            if(BlockLogicFire.canBurn(renderBlocks.blockAccess, x, y, z + 1))
+            if(BlockLogicFire.canBurn(worldSource, x, y, z + 1))
             {
                 tessellator.addVertexWithUV(x + 1, (float)y + yOffset + f4, (float)(z + 1) - f3, uMin, vMin);
                 tessellator.addVertexWithUV(x + 1, (float)(y) + f4, (z + 1), uMin, vMax);
@@ -158,7 +160,7 @@ public class BlockModelFire<T extends BlockLogic> extends BlockModelStandard<T>
                 tessellator.addVertexWithUV(x + 1, (float)(y) + f4, (z + 1), uMin, vMax);
                 tessellator.addVertexWithUV(x + 1, (float)y + yOffset + f4, (float)(z + 1) - f3, uMin, vMin);
             }
-            if(BlockLogicFire.canBurn(renderBlocks.blockAccess, x, y + 1, z))
+            if(BlockLogicFire.canBurn(worldSource, x, y + 1, z))
             {
                 double d11 = (double)x + 0.5D + 0.5D;
                 double d13 = ((double)x + 0.5D) - 0.5D;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFlowerStackable.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFlowerStackable.java
index 2c600d299..9c7e400f1 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFlowerStackable.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFlowerStackable.java
@@ -5,6 +5,7 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicFlowerStackable;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelFlowerStackable<T extends BlockLogicFlowerStackable> extends BlockModelCrossedSquares<T> {
     private final IconCoordinate[] ICONS;
@@ -19,7 +20,7 @@ public class BlockModelFlowerStackable<T extends BlockLogicFlowerStackable> exte
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         final int stackCount = T.getStackCount(data);
         if (stackCount > T.MAX_STACK_COUNT) {
             return ICONS[0];
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 783fe0b99..0ff1ed113 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
@@ -12,6 +12,7 @@ import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelFluid<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelFluid(Block<T> block) {
@@ -19,21 +20,21 @@ public class BlockModelFluid<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int color = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(renderBlocks.blockAccess, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int color = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(worldSource, x, y, z, 0);
         float r = (float)(color >> 16 & 0xff) / 255F;
         float g = (float)(color >> 8 & 0xff) / 255F;
         float b = (float)(color & 0xff) / 255F;
 
-        AABB bounds = block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z);
+        AABB bounds = block.getBlockBoundsFromState(worldSource, x, y, z);
 
-        boolean renderTop = shouldSideBeRendered(renderBlocks.blockAccess, bounds, x, y + 1, z, 1);
-        boolean flag1 = shouldSideBeRendered(renderBlocks.blockAccess, bounds, x, y - 1, z, 0);
+        boolean renderTop = shouldSideBeRendered(worldSource, bounds, x, y + 1, z, Side.TOP);
+        boolean flag1 = shouldSideBeRendered(worldSource, bounds, x, y - 1, z, Side.BOTTOM);
         boolean[] aflag = new boolean[4];
-        aflag[0] = shouldSideBeRendered(renderBlocks.blockAccess, bounds, x, y, z - 1, 2);
-        aflag[1] = shouldSideBeRendered(renderBlocks.blockAccess, bounds, x, y, z + 1, 3);
-        aflag[2] = shouldSideBeRendered(renderBlocks.blockAccess, bounds, x - 1, y, z, 4);
-        aflag[3] = shouldSideBeRendered(renderBlocks.blockAccess, bounds, x + 1, y, z, 5);
+        aflag[0] = shouldSideBeRendered(worldSource, bounds, x, y, z - 1, Side.NORTH);
+        aflag[1] = shouldSideBeRendered(worldSource, bounds, x, y, z + 1, Side.SOUTH);
+        aflag[2] = shouldSideBeRendered(worldSource, bounds, x - 1, y, z, Side.WEST);
+        aflag[3] = shouldSideBeRendered(worldSource, bounds, x + 1, y, z, Side.EAST);
         if(!renderTop && !flag1 && !aflag[0] && !aflag[1] && !aflag[2] && !aflag[3])
         {
             return false;
@@ -47,16 +48,16 @@ public class BlockModelFluid<T extends BlockLogic> extends BlockModelStandard<T>
 
         final float yOff = 0.001f;
         Material material = block.getMaterial();
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
-        float f7 = BlockLogicFluid.getFluidHeight(renderBlocks.blockAccess, x, y, z, material);
-        float f8 = BlockLogicFluid.getFluidHeight(renderBlocks.blockAccess, x, y, z + 1, material);
-        float f9 = BlockLogicFluid.getFluidHeight(renderBlocks.blockAccess, x + 1, y, z + 1, material);
-        float f10 = BlockLogicFluid.getFluidHeight(renderBlocks.blockAccess, x + 1, y, z, material);
+        int meta = worldSource.getBlockMetadata(x, y, z);
+        float f7 = BlockLogicFluid.getFluidHeight(worldSource, x, y, z, material);
+        float f8 = BlockLogicFluid.getFluidHeight(worldSource, x, y, z + 1, material);
+        float f9 = BlockLogicFluid.getFluidHeight(worldSource, x + 1, y, z + 1, material);
+        float f10 = BlockLogicFluid.getFluidHeight(worldSource, x + 1, y, z, material);
         if(renderBlocks.renderAllFaces || renderTop)
         {
             didRender = true;
             IconCoordinate texture = getBlockTextureFromSideAndMetadata(Side.TOP, meta);
-            float rotation = (float) BlockLogicFluid.getSlopeAngle(renderBlocks.blockAccess, x, y, z, material);
+            float rotation = (float) BlockLogicFluid.getSlopeAngle(worldSource, x, y, z, material);
             if(rotation > -999F)
             {
                 texture = getBlockTextureFromSideAndMetadata(Side.NORTH, meta);
@@ -65,12 +66,12 @@ public class BlockModelFluid<T extends BlockLogic> extends BlockModelStandard<T>
             }
             float blockBrightness = 1.0f;
             if(LightmapHelper.isLightmapEnabled()) {
-            	int light = block.getLightmapCoord(renderBlocks.blockAccess, x, y, z);
-            	int lightUp = block.getLightmapCoord(renderBlocks.blockAccess, x, y + 1, z);
+            	int light = block.getLightmapCoord(worldSource, x, y, z);
+            	int lightUp = block.getLightmapCoord(worldSource, x, y + 1, z);
             	
             	tessellator.setLightmapCoord(LightmapHelper.max(light, lightUp));
             }else {
-            	blockBrightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            	blockBrightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
             }
             if (texture.namespaceId.toString().contains("_flowing")){
                 double centerU = texture.getSubIconU(0.5);
@@ -101,9 +102,9 @@ public class BlockModelFluid<T extends BlockLogic> extends BlockModelStandard<T>
         {
             float brightness = 1.0f;
             if(LightmapHelper.isLightmapEnabled()) {
-            	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y - 1, z));
+            	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y - 1, z));
             }else {
-            	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y - 1, z);
+            	brightness = renderBlocks.getBlockBrightness(worldSource, x, y - 1, z);
             }
             tessellator.setColorOpaque_F(sideBottom * brightness * r, sideBottom * brightness * g, sideBottom * brightness * b);
 
@@ -192,9 +193,9 @@ public class BlockModelFluid<T extends BlockLogic> extends BlockModelStandard<T>
             double d8 = texture.getSubIconV(0.5F + vOff);
 			float brightness = 1.0f;
 			if(LightmapHelper.isLightmapEnabled()) {
-				tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, xB, yB, zB));
+				tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, xB, yB, zB));
 			}else {
-				brightness = getBlockBrightness(renderBlocks.blockAccess, xB, yB, zB);
+				brightness = renderBlocks.getBlockBrightness(worldSource, xB, yB, zB);
 			}
 			if(side < 2) {
 				brightness *= sideNorthSouth;
@@ -216,7 +217,7 @@ public class BlockModelFluid<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side)
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side)
     {
         Material material = blockAccess.getBlockMaterial(x, y, z);
         if(material == block.getMaterial())
@@ -227,7 +228,7 @@ public class BlockModelFluid<T extends BlockLogic> extends BlockModelStandard<T>
         {
             return true;
         }
-        if(side == Side.TOP.getId())
+        if(side == Side.TOP)
         {
             return true;
         }
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 411126ea4..0db8d6a2a 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
@@ -7,6 +7,8 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicFullyRotatable;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class BlockModelFullyRotatable<T extends BlockLogic> extends BlockModelStandard<T> {
@@ -15,8 +17,8 @@ public class BlockModelFullyRotatable<T extends BlockLogic> extends BlockModelSt
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        final int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        final int meta = worldSource.getBlockMetadata(x, y, z);
         final Direction dir = BlockLogicFullyRotatable.metaToDirection(meta);
 
         switch (dir) {
@@ -53,20 +55,20 @@ public class BlockModelFullyRotatable<T extends BlockLogic> extends BlockModelSt
                 renderBlocks.uvRotateBottom = 2;
                 break;
         }
-        final boolean result = renderStandardBlock(tessellator, block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z), x, y, z);
-        resetRenderBlocks();
+        final boolean result = renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBlockBoundsFromState(worldSource, x, y, z), x, y, z);
+        renderBlocks.resetRenderBlocks();
 
         return result;
     }
 
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
-        super.renderBlockOnInventory(tessellator, 1, brightness, alpha, lightmapCoordinate);
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+        super.renderStandalone(tessellator, 1, brightness, alpha, lightmapCoordinate);
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         final Direction dir = BlockLogicFullyRotatable.metaToDirection(data);
         if (side == dir.getSide()) {
             return blockTextures.get(Side.TOP);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFurnace.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFurnace.java
index a1f862167..592b70f97 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFurnace.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFurnace.java
@@ -8,6 +8,7 @@ import net.minecraft.core.player.inventory.container.Container;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.helper.Sides;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelFurnace<T extends BlockLogic>
     extends BlockModelHorizontalRotation<T> {
@@ -17,13 +18,13 @@ public class BlockModelFurnace<T extends BlockLogic>
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side) {
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side) {
         int data = blockAccess.getBlockMetadata(x, y, z);
         int index = Sides.orientationLookUpHorizontal[6 * Math.min(data, 5) + side.getId()];
         if (index >= Sides.orientationLookUpHorizontal.length) return blockTextures.get(Side.BOTTOM);
         if (index == Side.NORTH.getId()) {
             IconCoordinate originalFront = blockTextures.get(Side.NORTH);
-            Container container = (Container) blockAccess.getBlockEntity(x, y, z);
+            Container container = (Container) blockAccess.getTileEntity(x, y, z);
             if (container != null) {
                 boolean hasOutput = container.getItem(2) != null;
                 if (hasOutput) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelGeneric.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelGeneric.java
new file mode 100644
index 000000000..f6c098ddb
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelGeneric.java
@@ -0,0 +1,102 @@
+package net.minecraft.client.render.block.model;
+
+import net.minecraft.client.render.block.color.BlockColorDispatcher;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockLogic;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.useless.dragonfly.DisplayPos;
+import org.useless.dragonfly.data.block.BlockModelData;
+import org.useless.dragonfly.models.block.StaticBlockModel;
+
+public class BlockModelGeneric<T extends BlockLogic> extends BlockModel<T>{
+    private final StaticBlockModel staticModel;
+
+    public BlockModelGeneric(@NotNull Block<T> block, @NotNull StaticBlockModel staticModel) {
+        super(block);
+        this.staticModel = staticModel;
+    }
+
+    public BlockModelGeneric(@NotNull Block<T> block, @NotNull BlockModelData staticModel) {
+        super(block);
+        this.staticModel = staticModel.asModel();
+    }
+
+    @Override
+    public boolean renderNoCulling(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        return staticModel.renderAttached(this,
+            tessellator,
+            worldSource, x,
+            y,
+            z,
+            0, 0, 0, false, null);
+    }
+
+    @Override
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        return staticModel.renderAttached(this,
+            tessellator,
+            worldSource, x,
+            y,
+            z,
+            0, 0, 0, true, null);
+    }
+
+    @Override
+    public boolean renderOverbright(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean renderWithOverrideTexture(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z, IconCoordinate textureIndex) {
+        return staticModel.renderAttached(this,
+            tessellator,
+            worldSource, x,
+            y,
+            z,
+            0, 0, 0, true, textureIndex);
+    }
+
+    @Override
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+        staticModel.renderStandalone(this,
+            tessellator, 0, 0, 0,
+            metadata,
+            BlockColorDispatcher.getInstance().getDispatch(block),
+            brightness, alpha);
+    }
+
+    @Override
+    public boolean shouldItemRender3d() {
+        return true;
+    }
+
+    @Override
+    public @NotNull DisplayPos getItemDisplayPos(@NotNull String id) {
+        return staticModel.getItemDisplayPos(id);
+    }
+
+    @Override
+    public int renderLayer() {
+        return staticModel.renderLayer();
+    }
+
+    @Override
+    public @Nullable IconCoordinate getParticleTexture(@NotNull Side side, int meta) {
+        return staticModel.getParticle(side);
+    }
+
+    @Override
+    public @Nullable IconCoordinate getOverlayTexture(int meta) {
+        return staticModel.getOverlay();
+    }
+
+    @Override
+    public int particleColorIndex(@NotNull WorldSource worldSource, int x, int y, int z, @NotNull Side side, int meta) {
+        return staticModel.particleColorIndex(side);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelGrass.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelGrass.java
index 6c36c8811..e1a58925b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelGrass.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelGrass.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.block.model;
 
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
@@ -12,10 +11,12 @@ import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
 public class BlockModelGrass<T extends BlockLogic> extends BlockModelStandard<T> {
+    public static boolean fancyGrass = false;
     public static boolean useOverlay = false;
     private static final IconCoordinate[] overlayIndices = new IconCoordinate[]{
             null,
@@ -30,18 +31,18 @@ public class BlockModelGrass<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         AABB bounds = block.getBounds();
-        boolean didRender = isRetro() ? renderStandardBlock(tessellator, bounds, x, y, z, 1, 1, 1) : renderStandardBlock(tessellator, bounds, x, y, z);
-        if (RenderBlocks.fancyGrass && !(retroBlockTextures.hasTexture() && isRetro())){
+        boolean didRender = isRetro() ? renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1) : renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
+        if (fancyGrass && !(retroBlockTextures.hasTexture() && isRetro())){
             useOverlay = true;
-            didRender |= renderStandardBlock(tessellator, bounds, x, y, z);
+            didRender |= renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             useOverlay = false;
         }
         return didRender;
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         GL11.glColor4f(brightness, brightness, brightness, alpha);
         float yOffset = 0.5F;
 
@@ -49,31 +50,31 @@ public class BlockModelGrass<T extends BlockLogic> extends BlockModelStandard<T>
         GL11.glTranslatef(-0.5F, 0.0F - yOffset, -0.5F);
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, -1F, 0.0F);
-        renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
         tessellator.draw();
         if(renderBlocks.useInventoryTint && !isRetro())
         {
-            int l = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+            int l = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
             float f4 = (float)(l >> 16 & 0xff) / 255F;
             float f8 = (float)(l >> 8 & 0xff) / 255F;
             float f9 = (float)(l & 0xff) / 255F;
@@ -81,32 +82,32 @@ public class BlockModelGrass<T extends BlockLogic> extends BlockModelStandard<T>
         }
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
         tessellator.draw();
-        if (RenderBlocks.fancyGrass && !isRetro()){
+        if (fancyGrass && !isRetro()){
             useOverlay = true;
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, -1F);
-            renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
+            renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
             tessellator.draw();
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, 1.0F);
-            renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
+            renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
             tessellator.draw();
             tessellator.startDrawingQuads();
             tessellator.setNormal(-1F, 0.0F, 0.0F);
-            renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
+            renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
             tessellator.draw();
             tessellator.startDrawingQuads();
             tessellator.setNormal(1.0F, 0.0F, 0.0F);
-            renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
+            renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
             tessellator.draw();
             useOverlay = false;
         }
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
     }
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
     {
         Material material = blockAccess.getBlockMaterial(x, y + 1, z);
         if ((material == Material.topSnow || material == Material.snow) && (side.getAxis() != Axis.Y)) {
@@ -114,7 +115,7 @@ public class BlockModelGrass<T extends BlockLogic> extends BlockModelStandard<T>
         } else return super.getBlockTexture(blockAccess, x, y, z, side);
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if (useOverlay){
             return overlayIndices[side.getId()];
@@ -122,11 +123,11 @@ public class BlockModelGrass<T extends BlockLogic> extends BlockModelStandard<T>
         return super.getBlockTextureFromSideAndMetadata(side, data);
     }
     @Override
-    public boolean shouldSideBeColored(WorldSource blockAccess, int x, int y, int z, int side, int meta){
-        Material material = blockAccess.getBlockMaterial(x, y + 1, z);
+    public boolean shouldSideBeColored(@NotNull WorldSource worldSource, int x, int y, int z, @NotNull Side side, int meta){
+        Material material = worldSource.getBlockMaterial(x, y + 1, z);
         if (material == Material.topSnow || material == Material.snow) {
             return false;
         }
-        return useOverlay || side == Side.TOP.getId();
+        return useOverlay || side == Side.TOP;
     }
 }
\ No newline at end of file
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelHorizontalRotation.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelHorizontalRotation.java
index ce5d2d110..7c9aab868 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelHorizontalRotation.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelHorizontalRotation.java
@@ -6,21 +6,31 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicRotatable;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.helper.Sides;
+import org.jetbrains.annotations.Nullable;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelHorizontalRotation<T extends BlockLogic> extends BlockModelStandard<T> {
+    protected static final DisplayPos ROTATABLE_GUI = new DisplayPos(0, 0, 0, 30, 45, 0, 0.625f, 0.625f, 0.625f);
+    protected static final DisplayPos ROTATABLE_HEAD = new DisplayPos(0, 0, 0, 0, -180, 0, 1f, 1f, 1f);
+    protected static final DisplayPos ROTATABLE_FIRST_PERSON_RIGHT_HAND = new DisplayPos(0, 0, 0, 0, -45, 0, 0.4f, 0.4f, 0.4f);
+
     public BlockModelHorizontalRotation(Block<T> block) {
         super(block);
+
+        setDisplayPos(DisplayPos.GUI, ROTATABLE_GUI);
+        setDisplayPos(DisplayPos.HEAD, ROTATABLE_HEAD);
+        setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, ROTATABLE_FIRST_PERSON_RIGHT_HAND);
     }
 
     @Override
-    public IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data) {
+    public @Nullable IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data) {
         int index = Sides.orientationLookUpHorizontal[6 * Math.min(data & BlockLogicRotatable.MASK_DIRECTION, 5) + side.getId()];
         if (index >= Sides.orientationLookUpHorizontal.length) return overbrightTextures.get(Side.BOTTOM);
         return super.getBlockOverbrightTextureFromSideAndMeta(Side.getSideById(index), data);
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         int index = Sides.orientationLookUpHorizontal[6 * Math.min(data & BlockLogicRotatable.MASK_DIRECTION, 5) + side.getId()];
         if (index >= Sides.orientationLookUpHorizontal.length) return blockTextures.get(Side.BOTTOM);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelIce.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelIce.java
deleted file mode 100644
index 0c6221b2e..000000000
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelIce.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.minecraft.client.render.block.model;
-
-import net.minecraft.core.block.Block;
-import net.minecraft.core.block.BlockLogic;
-import net.minecraft.core.util.phys.AABB;
-import net.minecraft.core.world.WorldSource;
-
-public class BlockModelIce<T extends BlockLogic> extends BlockModelTransparent<T> {
-    public BlockModelIce(Block<T> block) {
-        super(block, false);
-    }
-
-    @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side)
-    {
-        return super.shouldSideBeRendered(blockAccess, bounds, x, y, z, 1 - side);
-    }
-}
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelJar.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelJar.java
index e644dd943..8332ef277 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelJar.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelJar.java
@@ -7,6 +7,9 @@ import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelJar<T extends BlockLogic> extends BlockModelStandard<T> {
     protected IconCoordinate jarEmpty = TextureRegistry.getTexture("minecraft:block/jar");
@@ -16,16 +19,16 @@ public class BlockModelJar<T extends BlockLogic> extends BlockModelStandard<T> {
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         // todo: yes, i know this is horrible.
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }
         float yOffset = 0f;
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+        int meta = worldSource.getBlockMetadata(x, y, z);
 
         float extMinX = x + 0.5f - (3f / 16f);
         float extMinY = y + yOffset;
@@ -142,7 +145,7 @@ public class BlockModelJar<T extends BlockLogic> extends BlockModelStandard<T> {
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta)
     {
         if(meta == 1)
             return jarFull;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelJarButterfly.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelJarButterfly.java
index 16ff1dd3c..4198dd0ee 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelJarButterfly.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelJarButterfly.java
@@ -7,6 +7,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicJarButterfly;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelJarButterfly<T extends BlockLogic> extends BlockModelStandard<T>{
 
@@ -15,16 +17,16 @@ public class BlockModelJarButterfly<T extends BlockLogic> extends BlockModelStan
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, WorldSource worldSource, int x, int y, int z) {
+        int meta = worldSource.getBlockMetadata(x, y, z);
         boolean isHanging = (meta & BlockLogicJarButterfly.MASK_HANGING) == 0;
         boolean isAngled = (meta & BlockLogicJarButterfly.MASK_ANGLED) != 0;
 
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-            tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+            tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
-            brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLadder.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLadder.java
index eeb5ea75f..afd16a355 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLadder.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLadder.java
@@ -6,6 +6,8 @@ import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelLadder<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelLadder(Block<T> block) {
@@ -13,8 +15,8 @@ public class BlockModelLadder<T extends BlockLogic> extends BlockModelStandard<T
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int k1 = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int k1 = worldSource.getBlockMetadata(x, y, z);
         IconCoordinate l = getBlockTextureFromSideAndMetadata(Side.BOTTOM, k1);
         if(renderBlocks.overrideBlockTexture != null)
         {
@@ -22,9 +24,9 @@ public class BlockModelLadder<T extends BlockLogic> extends BlockModelStandard<T
         }
         float brightness = 1.0f;
         if(!LightmapHelper.isLightmapEnabled()) {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }else {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
         double d = l.getIconUMin();
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLamp.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLamp.java
index 44b125a73..790ddaf82 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLamp.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLamp.java
@@ -7,6 +7,7 @@ import net.minecraft.core.block.BlockLogicLamp;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelLamp<T extends BlockLogicLamp> extends BlockModelStandard<T> {
     private static final IconCoordinate[] texCoordsInactive = new IconCoordinate[DyeColor.COLOR_AMOUNT];
@@ -24,7 +25,7 @@ public class BlockModelLamp<T extends BlockLogicLamp> extends BlockModelStandard
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource worldSource, int x, int y, int z, Side side)
+    public @Nullable IconCoordinate getBlockTexture(WorldSource worldSource, int x, int y, int z, Side side)
     {
         int color = worldSource.getBlockMetadata(x, y, z) & DyeColor.MASK_COLOR;
         if (block.getLogic().isActive) {
@@ -35,7 +36,7 @@ public class BlockModelLamp<T extends BlockLogicLamp> extends BlockModelStandard
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         return texCoordsActive[data & DyeColor.MASK_COLOR];
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLantern.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLantern.java
index ea2ba175e..d839f33a6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLantern.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLantern.java
@@ -7,6 +7,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicLanternFirefly;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelLantern<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelLantern(Block<T> block) {
@@ -14,16 +16,16 @@ public class BlockModelLantern<T extends BlockLogic> extends BlockModelStandard<
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int meta = worldSource.getBlockMetadata(x, y, z);
         boolean isHanging = (meta & BlockLogicLanternFirefly.MASK_HANGING) == 0;
 //        boolean isAngled = (meta & BlockLogicLanternFirefly.MASK_ANGLED) != 0;
 
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
 
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 eb749ae44..54209d1ff 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
@@ -3,8 +3,10 @@ package net.minecraft.client.render.block.model;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -14,15 +16,15 @@ public class BlockModelLayer<T extends BlockLogic> extends BlockModelStandard<T>
         withCustomItemBounds(0.0f, 0.0f, 0.0f, 1.0f, 2 / 16F, 1.0f);
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         GL11.glTranslatef(0, 0.25f, 0);
-        super.renderBlockOnInventory(tessellator, metadata, brightness, alpha, lightmapCoordinate);
+        super.renderStandalone(tessellator, metadata, brightness, alpha, lightmapCoordinate);
     }
 
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side, int meta)
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side, int meta)
     {
-        if(side > 1 && blockAccess.getBlockId(x, y, z) == block.id() && blockAccess.getBlockMetadata(x, y, z) == meta){
+        if(!side.isVertical() && blockAccess.getBlockId(x, y, z) == block.id() && blockAccess.getBlockMetadata(x, y, z) == meta){
             return false;
         }
         return super.shouldSideBeRendered(blockAccess, bounds, x, y, z, side);
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 6a6fa7905..6454f3867 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
@@ -8,6 +8,7 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class BlockModelLeaves<T extends BlockLogic> extends BlockModelStandard<T> {
@@ -35,23 +36,23 @@ public class BlockModelLeaves<T extends BlockLogic> extends BlockModelStandard<T
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         boolean invTint = renderBlocks.useInventoryTint;
         renderBlocks.useInventoryTint = !canBeRetro || !isRetro();
-        super.renderBlockOnInventory(tessellator, metadata, brightness, alpha, lightmapCoordinate);
+        super.renderStandalone(tessellator, metadata, brightness, alpha, lightmapCoordinate);
         renderBlocks.useInventoryTint = invTint;
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         if (canBeRetro && isRetro()) {
-            return renderStandardBlock(tessellator, block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z), x, y, z, 1, 1, 1);
+            return renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBlockBoundsFromState(worldSource, x, y, z), x, y, z, 1, 1, 1);
         }
-        return super.render(tessellator, x, y, z);
+        return super.render(tessellator, worldSource, x, y, z);
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if (canBeRetro && isRetro()) {
             return fancyGraphics ? retroLeavesFancy : retroLeaves;
@@ -59,7 +60,7 @@ public class BlockModelLeaves<T extends BlockLogic> extends BlockModelStandard<T
         return fancyGraphics ? fancyLeavesTexture : super.getBlockTextureFromSideAndMetadata(side, data);
     }
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side)
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side)
     {
         int i1 = blockAccess.getBlockId(x, y, z);
         if(!fancyGraphics && i1 == block.id())
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeavesCacao.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeavesCacao.java
index 69e9a846d..26dd801ef 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeavesCacao.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeavesCacao.java
@@ -8,6 +8,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicLeavesCacao;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -23,21 +25,21 @@ public class BlockModelLeavesCacao<T extends BlockLogic> extends BlockModelLeave
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        super.render(tessellator, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        super.render(tessellator, worldSource, x, y, z);
 
         AABB bounds = block.getBounds();
 
-        final int growthRate = BlockLogicLeavesCacao.getGrowthRate(renderBlocks.blockAccess.getBlockMetadata(x, y, z));
+        final int growthRate = BlockLogicLeavesCacao.getGrowthRate(worldSource.getBlockMetadata(x, y, z));
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-            int lmc = block.getLightmapCoord(renderBlocks.blockAccess, x, y, z);
+            int lmc = block.getLightmapCoord(worldSource, x, y, z);
             if(block.emission > 0) {
                 lmc = LightmapHelper.setBlocklightValue(lmc, 15);
             }
             tessellator.setLightmapCoord(lmc);
         }else {
-            brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
             if(block.emission > 0) {
                 brightness = 1.0f;
             }
@@ -48,19 +50,19 @@ public class BlockModelLeavesCacao<T extends BlockLogic> extends BlockModelLeave
         if (growthRate > 0) {
             renderBlocks.overrideBlockTexture = growthStages[Math.min(growthRate - 1, BlockLogicLeavesCacao.MAX_GROWTH_STATE - 1)];
             tessellator.setColorOpaque_F(cNorthSouth * brightness, cNorthSouth * brightness, cNorthSouth * brightness);
-            renderNorthFace(tessellator, bounds, x, y, z, renderBlocks.overrideBlockTexture);
-            renderSouthFace(tessellator, bounds, x, y, z, renderBlocks.overrideBlockTexture);
+            renderBlocks.renderNorthFace(tessellator, bounds, x, y, z, renderBlocks.overrideBlockTexture);
+            renderBlocks.renderSouthFace(tessellator, bounds, x, y, z, renderBlocks.overrideBlockTexture);
             tessellator.setColorOpaque_F(cEastWest * brightness, cEastWest * brightness, cEastWest * brightness);
-            renderEastFace(tessellator, bounds, x, y, z, renderBlocks.overrideBlockTexture);
-            renderWestFace(tessellator, bounds, x, y, z, renderBlocks.overrideBlockTexture);
+            renderBlocks.renderEastFace(tessellator, bounds, x, y, z, renderBlocks.overrideBlockTexture);
+            renderBlocks.renderWestFace(tessellator, bounds, x, y, z, renderBlocks.overrideBlockTexture);
             renderBlocks.overrideBlockTexture = null;
         }
 
         return true;
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
-        super.renderBlockOnInventory(tessellator, metadata, brightness, alpha, lightmapCoordinate);
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+        super.renderStandalone(tessellator, metadata, brightness, alpha, lightmapCoordinate);
         GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
 
         AABB bounds = block.getBounds();
@@ -70,32 +72,32 @@ public class BlockModelLeavesCacao<T extends BlockLogic> extends BlockModelLeave
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, -1F, 0.0F);
-        renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cacaoCoord);
         tessellator.draw();
 
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeavesCherryFlowering.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeavesCherryFlowering.java
index fbd3b8034..b832795d9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeavesCherryFlowering.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLeavesCherryFlowering.java
@@ -7,6 +7,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicLeavesCherryFlowering;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -18,24 +20,24 @@ public class BlockModelLeavesCherryFlowering<T extends BlockLogic> extends Block
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        super.render(tessellator, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        super.render(tessellator, worldSource, x, y, z);
 
-        int growthRate = BlockLogicLeavesCherryFlowering.getGrowthRate(renderBlocks.blockAccess.getBlockMetadata(x, y, z));
+        int growthRate = BlockLogicLeavesCherryFlowering.getGrowthRate(worldSource.getBlockMetadata(x, y, z));
         if(growthRate > 0) {
             renderBlocks.overrideBlockTexture = grownCherryOverlay;
         } else {
             renderBlocks.overrideBlockTexture = floweringCherryOverlay;
         }
 
-        renderStandardBlock(tessellator, block.getBoundsRaw(), x, y, z, 1.0f, 1.0f, 1.0f);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBoundsRaw(), x, y, z, 1.0f, 1.0f, 1.0f);
         renderBlocks.overrideBlockTexture = null;
 
         return true;
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
-        super.renderBlockOnInventory(tessellator, metadata, brightness, alpha, lightmapCoordinate);
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+        super.renderStandalone(tessellator, metadata, brightness, alpha, lightmapCoordinate);
         GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
 
         AABB bounds = block.getBoundsRaw();
@@ -45,32 +47,32 @@ public class BlockModelLeavesCherryFlowering<T extends BlockLogic> extends Block
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, -1F, 0.0F);
-        renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, cherryCoord);
         tessellator.draw();
 
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
index 4d8f54e4f..451b907a5 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
@@ -3,14 +3,17 @@ package net.minecraft.client.render.block.model;
 import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicLever;
-import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelLever<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelLever(Block<T> block) {
@@ -18,14 +21,14 @@ public class BlockModelLever<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int l = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int l = worldSource.getBlockMetadata(x, y, z);
         int i1 = l & 15;
         boolean flag = (l & 16) > 0;
         boolean flag1 = renderBlocks.overrideBlockTexture != null;
         if(!flag1)
         {
-            renderBlocks.overrideBlockTexture = BlockModelDispatcher.getInstance().getDispatch(Blocks.COBBLE_STONE).getBlockTextureFromSideAndMetadata(Side.BOTTOM, l);
+            renderBlocks.overrideBlockTexture = TextureRegistry.getTexture("minecraft:block/cobbled_stone");
         }
         float f = 0.25F;
         float f1 = 0.1875F;
@@ -57,19 +60,19 @@ public class BlockModelLever<T extends BlockLogic> extends BlockModelStandard<T>
                 bounds.set(0.0F, 0.5F - f, 0.5F - f1, f2, 0.5F + f, 0.5F + f1);
                 break;
         }
-        renderStandardBlock(tessellator, bounds, x, y, z);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         if(!flag1)
         {
             renderBlocks.overrideBlockTexture = null;
         }
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
 			if(block.emission > 0) {
 				brightness = 1.0f;
 			}else {
-				brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+				brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
 			}
         }
         
@@ -218,8 +221,5 @@ public class BlockModelLever<T extends BlockLogic> extends BlockModelStandard<T>
     public boolean shouldItemRender3d() {
         return false;
     }
-    @Override
-    public float getItemRenderScale() {
-        return 0.5f;
-    }
+
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelOverlayLeaves.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelOverlayLeaves.java
index ab891b458..f65c25dd4 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelOverlayLeaves.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelOverlayLeaves.java
@@ -6,6 +6,8 @@ import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -17,18 +19,18 @@ public class BlockModelOverlayLeaves<T extends BlockLogic> extends BlockModelLea
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        super.render(tessellator, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        super.render(tessellator, worldSource, x, y, z);
 
         renderBlocks.overrideBlockTexture = overlayTexture;
-        renderStandardBlock(tessellator, block.getBoundsRaw(), x, y, z, 1.0f, 1.0f, 1.0f);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBoundsRaw(), x, y, z, 1.0f, 1.0f, 1.0f);
         renderBlocks.overrideBlockTexture = null;
 
         return true;
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
-        super.renderBlockOnInventory(tessellator, metadata, brightness, alpha, lightmapCoordinate);
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+        super.renderStandalone(tessellator, metadata, brightness, alpha, lightmapCoordinate);
         GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
 
         AABB bounds = block.getBounds();
@@ -38,32 +40,32 @@ public class BlockModelOverlayLeaves<T extends BlockLogic> extends BlockModelLea
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, -1F, 0.0F);
-        renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
         tessellator.draw();
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, overlayCoord);
         tessellator.draw();
 
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPebbles.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPebbles.java
index 1181804e2..62b54ba2a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPebbles.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPebbles.java
@@ -8,6 +8,9 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelPebbles<T extends BlockLogic> extends BlockModelStandard<T> {
     protected IconCoordinate[] pebbles = {
@@ -20,18 +23,18 @@ public class BlockModelPebbles<T extends BlockLogic> extends BlockModelStandard<
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	tessellator.setLightmapCoord(LightmapHelper.max(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z), block.getLightmapCoord(renderBlocks.blockAccess, x, y - 1, z)));
+        	tessellator.setLightmapCoord(LightmapHelper.max(block.getLightmapCoord(worldSource, x, y, z), block.getLightmapCoord(worldSource, x, y - 1, z)));
         }else {
-        	brightness = Math.max(getBlockBrightness(renderBlocks.blockAccess, x, y, z), getBlockBrightness(renderBlocks.blockAccess, x, y - 1, z));
+        	brightness = Math.max(renderBlocks.getBlockBrightness(worldSource, x, y, z), renderBlocks.getBlockBrightness(worldSource, x, y - 1, z));
         }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
-        renderTopFace(tessellator,
-            block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z),
+        renderBlocks.renderTopFace(tessellator,
+            block.getBlockBoundsFromState(worldSource, x, y, z),
             x, y, z,
-            getBlockTextureFromSideAndMetadata(Side.TOP, renderBlocks.blockAccess.getBlockMetadata(x, y, z)));
+            getBlockTextureFromSideAndMetadata(Side.TOP, worldSource.getBlockMetadata(x, y, z)));
 
         return true;
     }
@@ -40,7 +43,7 @@ public class BlockModelPebbles<T extends BlockLogic> extends BlockModelStandard<
         return false;
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         return pebbles[MathHelper.clamp(data, 0, 2)];
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiePumpkin.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiePumpkin.java
index 88fa02e4c..9a241f8f9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiePumpkin.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiePumpkin.java
@@ -7,6 +7,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicEdible;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelPiePumpkin<T extends BlockLogicEdible> extends BlockModelStandard<T> {
     protected IconCoordinate sideTexture = TextureRegistry.getTexture("minecraft:block/pumpkin_pie/side");
@@ -20,15 +22,15 @@ public class BlockModelPiePumpkin<T extends BlockLogicEdible> extends BlockModel
         withCustomItemBounds(f, 0.0F, f, 1.0F - f, f1, 1.0F - f);
     }
 
-    public void renderSliceSide(Tessellator tessellator, AABB bounds, int x, int y, int z, Side side, boolean overrideTex) {
+    public void renderSliceSide(Tessellator tessellator, WorldSource worldSource, AABB bounds, int x, int y, int z, Side side, boolean overrideTex) {
         if(overrideTex)
             renderBlocks.overrideBlockTexture = insideTexture;
-        renderSide(tessellator, bounds, x, y, z, side, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 0, 0, 0, side, 0);
         if(overrideTex)
             renderBlocks.overrideBlockTexture = null;
     }
 
-    private void renderSlice(Tessellator tessellator, AABB bounds, int x, int y, int z, int sliceX, int sliceZ) {
+    private void renderSlice(Tessellator tessellator, WorldSource worldSource, AABB bounds, int x, int y, int z, int sliceX, int sliceZ) {
 
         double onePix = 0.0625;
         double sliceWidth = onePix * 8;
@@ -50,30 +52,30 @@ public class BlockModelPiePumpkin<T extends BlockLogicEdible> extends BlockModel
 
         maxSlices = block.getLogic().maxBites;
         bounds.set(xMin + offsetXMin, 0.0F, zMin + offsetZMin, xMax - offsetXMax, 0.375F, zMax - offsetZMax);
-        renderSide(tessellator, bounds, x, y, z, Side.TOP, 0);
-        renderSide(tessellator, bounds, x, y, z, Side.BOTTOM, 0);
-        renderSliceSide(tessellator, bounds, x, y, z, Side.SOUTH, insideSouth);
-        renderSliceSide(tessellator, bounds, x, y, z, Side.WEST, insideWest);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.TOP, 0);
+        renderBlocks.renderSide(tessellator, worldSource, this, bounds, x, y, z, 1, 1, 1, Side.BOTTOM, 0);
+        renderSliceSide(tessellator, worldSource, bounds, x, y, z, Side.SOUTH, insideSouth);
+        renderSliceSide(tessellator, worldSource, bounds, x, y, z, Side.WEST, insideWest);
         renderBlocks.flipTexture = true;
-        renderSliceSide(tessellator, bounds, x, y, z, Side.NORTH, insideNorth);
-        renderSliceSide(tessellator, bounds, x, y, z, Side.EAST, insideEast);
+        renderSliceSide(tessellator, worldSource, bounds, x, y, z, Side.NORTH, insideNorth);
+        renderSliceSide(tessellator, worldSource, bounds, x, y, z, Side.EAST, insideEast);
         renderBlocks.flipTexture = false;
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        AABB bounds = block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        AABB bounds = block.getBlockBoundsFromState(worldSource, x, y, z);
 
-        final int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+        final int meta = worldSource.getBlockMetadata(x, y, z);
         renderBlocks.enableAO = true;
-        renderBlocks.cache.setupCache(block, renderBlocks.blockAccess, x, y, z);
+        renderBlocks.cache.setupCache(block, worldSource, x, y, z);
         int slices = 0;
         for(int xSlice = 0; xSlice < 2; xSlice++){
             for(int zSlice = 0; zSlice < 2; zSlice++) {
                 slices++;
                 if(meta >= slices)
                     continue;
-                renderSlice(tessellator, bounds, x, y, z, xSlice, zSlice);
+                renderSlice(tessellator, worldSource, bounds, x, y, z, xSlice, zSlice);
             }
         }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiston.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiston.java
index a81cd0632..a448df03a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiston.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiston.java
@@ -8,6 +8,8 @@ import net.minecraft.core.block.piston.BlockLogicPistonBase;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModelStandard<T> {
@@ -39,21 +41,21 @@ public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModel
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z){
-        return renderPistonBase(tessellator, x, y, z, false);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z){
+        return renderPistonBase(tessellator, worldSource, x, y, z, false);
     }
 
     private boolean headless = false;
-    public boolean renderHeadless(Tessellator tessellator, int x, int y, int z) {
+    public boolean renderHeadless(Tessellator tessellator, WorldSource worldSource, int x, int y, int z) {
         renderBlocks.renderAllFaces = true;
         headless = true;
-        boolean result = renderPistonBase(tessellator, x, y, z, true);
+        boolean result = renderPistonBase(tessellator, worldSource, x, y, z, true);
         headless = false;
         renderBlocks.renderAllFaces = false;
         return result;
     }
-    protected boolean renderPistonBase(Tessellator tessellator, int x, int y, int z, boolean noCulling) {
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    protected boolean renderPistonBase(Tessellator tessellator, WorldSource worldSource, int x, int y, int z, boolean noCulling) {
+        int meta = worldSource.getBlockMetadata(x, y, z);
         boolean extended = noCulling || (meta & 8) != 0;
         Direction direction = BlockLogicPistonBase.getDirection(meta);
         AABB bounds;
@@ -106,8 +108,8 @@ public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModel
                 default:
                     bounds = AABB.getTemporaryBB(0, 0, 0, 1, 1, 1);
             }
-            renderStandardBlock(tessellator, bounds, x, y, z);
-            resetRenderBlocks();
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
+            renderBlocks.resetRenderBlocks();
         } else
         {
             switch(direction)
@@ -145,14 +147,14 @@ public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModel
                     renderBlocks.uvRotateBottom = 2;
                     break;
             }
-            renderStandardBlock(tessellator, block.getBounds(), x, y, z);
-            resetRenderBlocks();
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBounds(), x, y, z);
+            renderBlocks.resetRenderBlocks();
         }
         return true;
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
-        super.renderBlockOnInventory(tessellator, 1, brightness, alpha, lightmapCoordinate);
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+        super.renderStandalone(tessellator, 1, brightness, alpha, lightmapCoordinate);
     }
     public IconCoordinate getFaceTexture()
     {
@@ -160,7 +162,7 @@ public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModel
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         Direction direction = BlockLogicPistonBase.getDirection(data);
         if (direction == Direction.NONE)
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPistonHead.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPistonHead.java
index 7a18fc5e2..5eaa60091 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPistonHead.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPistonHead.java
@@ -10,6 +10,8 @@ import net.minecraft.core.block.piston.BlockLogicPistonHead;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHead> {
@@ -32,25 +34,25 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        return renderPistonHead(tessellator, block, x, y, z, true);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        return renderPistonHead(tessellator, worldSource, block, x, y, z, true);
     }
-    public void renderPistonHeadNoCulling(Tessellator tessellator, Block<BlockLogicPistonHead> block, int x, int y, int z, boolean flag) {
+    public void renderPistonHeadNoCulling(Tessellator tessellator, WorldSource worldSource, Block<BlockLogicPistonHead> block, int x, int y, int z, boolean flag) {
         renderBlocks.renderAllFaces = true;
-        renderPistonHead(tessellator, block, x, y, z, flag);
+        renderPistonHead(tessellator, worldSource, block, x, y, z, flag);
         renderBlocks.renderAllFaces = false;
     }
     public void setFaceTextureOverride(@Nullable IconCoordinate faceTexture){
         faceTextureOverride = faceTexture;
     }
-    protected boolean renderPistonHead(Tessellator tessellator, Block<BlockLogicPistonHead> block, int x, int y, int z, boolean flag) {
-        int metadata = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    protected boolean renderPistonHead(Tessellator tessellator, WorldSource worldSource, Block<BlockLogicPistonHead> block, int x, int y, int z, boolean flag) {
+        int metadata = worldSource.getBlockMetadata(x, y, z);
         Direction direction = BlockLogicPistonHead.getDirectionFromMeta(metadata);
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
-        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
         }
         float f1 = flag ? 1.0F : 0.5F;
         double width = flag ? 1 : 1/2d;
@@ -61,7 +63,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 renderBlocks.uvRotateWest = 3;
                 renderBlocks.uvRotateSouth = 3;
                 renderBlocks.uvRotateNorth = 3;
-                renderStandardBlock(tessellator, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, headThickness, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, headThickness, 1.0F), x, y, z);
                 renderHeadTopBottom(tessellator, x + 0.375F, x + 0.625F, y + headThickness, y + headThickness + f1, z + 0.625F, z + 0.625F, brightness * 0.8F, width);
                 renderHeadTopBottom(tessellator, x + 0.625F, x + 0.375F, y + headThickness, y + headThickness + f1, z + 0.375F, z + 0.375F, brightness * 0.8F, width);
                 renderHeadTopBottom(tessellator, x + 0.375F, x + 0.375F, y + headThickness, y + headThickness + f1, z + 0.375F, z + 0.625F, brightness * 0.6F, width);
@@ -69,7 +71,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 break;
 
             case UP: // TOP
-                renderStandardBlock(tessellator, AABB.getTemporaryBB(0.0F, 1 - headThickness, 0.0F, 1.0F, 1.0F, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 1 - headThickness, 0.0F, 1.0F, 1.0F, 1.0F), x, y, z);
                 renderHeadTopBottom(tessellator, x + 0.375F, x + 0.625F, ((y - headThickness) + 1.0F) - f1, (y - headThickness) + 1.0F, z + 0.625F, z + 0.625F, brightness * 0.8F, width);
                 renderHeadTopBottom(tessellator, x + 0.625F, x + 0.375F, ((y - headThickness) + 1.0F) - f1, (y - headThickness) + 1.0F, z + 0.375F, z + 0.375F, brightness * 0.8F, width);
                 renderHeadTopBottom(tessellator, x + 0.375F, x + 0.375F, ((y - headThickness) + 1.0F) - f1, (y - headThickness) + 1.0F, z + 0.375F, z + 0.625F, brightness * 0.6F, width);
@@ -79,7 +81,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
             case NORTH: // NORTH
                 renderBlocks.uvRotateSouth = 1;
                 renderBlocks.uvRotateNorth = 2;
-                renderStandardBlock(tessellator, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, headThickness), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, headThickness), x, y, z);
                 renderHeadNorthSouth(tessellator, x + 0.375F, x + 0.375F, y + 0.625F, y + 0.375F, z + headThickness, z + headThickness + f1, brightness * 0.6F, width);
                 renderHeadNorthSouth(tessellator, x + 0.625F, x + 0.625F, y + 0.375F, y + 0.625F, z + headThickness, z + headThickness + f1, brightness * 0.6F, width);
                 renderHeadNorthSouth(tessellator, x + 0.375F, x + 0.625F, y + 0.375F, y + 0.375F, z + headThickness, z + headThickness + f1, brightness * 0.5F, width);
@@ -91,7 +93,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 renderBlocks.uvRotateNorth = 1;
                 renderBlocks.uvRotateTop = 3;
                 renderBlocks.uvRotateBottom = 3;
-                renderStandardBlock(tessellator, AABB.getTemporaryBB(0.0F, 0.0F, 1 - headThickness, 1.0F, 1.0F, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 1 - headThickness, 1.0F, 1.0F, 1.0F), x, y, z);
                 renderHeadNorthSouth(tessellator, x + 0.375F, x + 0.375F, y + 0.625F, y + 0.375F, ((z - headThickness) + 1.0F) - f1, (z - headThickness) + 1.0F, brightness * 0.6F, width);
                 renderHeadNorthSouth(tessellator, x + 0.625F, x + 0.625F, y + 0.375F, y + 0.625F, ((z - headThickness) + 1.0F) - f1, (z - headThickness) + 1.0F, brightness * 0.6F, width);
                 renderHeadNorthSouth(tessellator, x + 0.375F, x + 0.625F, y + 0.375F, y + 0.375F, ((z - headThickness) + 1.0F) - f1, (z - headThickness) + 1.0F, brightness * 0.5F, width);
@@ -103,7 +105,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 renderBlocks.uvRotateWest = 2;
                 renderBlocks.uvRotateTop = 2;
                 renderBlocks.uvRotateBottom = 1;
-                renderStandardBlock(tessellator, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, headThickness, 1.0F, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, headThickness, 1.0F, 1.0F), x, y, z);
                 renderHeadEastWest(tessellator, x + headThickness, x + headThickness + f1, y + 0.375F, y + 0.375F, z + 0.625F, z + 0.375F, brightness * 0.5F, width);
                 renderHeadEastWest(tessellator, x + headThickness, x + headThickness + f1, y + 0.625F, y + 0.625F, z + 0.375F, z + 0.625F, brightness, width);
                 renderHeadEastWest(tessellator, x + headThickness, x + headThickness + f1, y + 0.375F, y + 0.625F, z + 0.375F, z + 0.375F, brightness * 0.6F, width);
@@ -115,14 +117,14 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 renderBlocks.uvRotateWest = 1;
                 renderBlocks.uvRotateTop = 1;
                 renderBlocks.uvRotateBottom = 2;
-                renderStandardBlock(tessellator, AABB.getTemporaryBB(1 - headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(1 - headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F), x, y, z);
                 renderHeadEastWest(tessellator, ((x - headThickness) + 1.0F) - f1, (x - headThickness) + 1.0F, y + 0.375F, y + 0.375F, z + 0.625F, z + 0.375F, brightness * 0.5F, width);
                 renderHeadEastWest(tessellator, ((x - headThickness) + 1.0F) - f1, (x - headThickness) + 1.0F, y + 0.625F, y + 0.625F, z + 0.375F, z + 0.625F, brightness, width);
                 renderHeadEastWest(tessellator, ((x - headThickness) + 1.0F) - f1, (x - headThickness) + 1.0F, y + 0.375F, y + 0.625F, z + 0.375F, z + 0.375F, brightness * 0.6F, width);
                 renderHeadEastWest(tessellator, ((x - headThickness) + 1.0F) - f1, (x - headThickness) + 1.0F, y + 0.625F, y + 0.375F, z + 0.625F, z + 0.625F, brightness * 0.6F, width);
                 break;
         }
-        resetRenderBlocks();
+        renderBlocks.resetRenderBlocks();
         return true;
     }
     private void renderHeadTopBottom(Tessellator tessellator, double xMin, double xMax, double yMin, double yMax, double zMin, double zMax, float brightness, double width)
@@ -183,7 +185,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
         return false;
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         Direction direction = BlockLogicPistonHead.getDirectionFromMeta(data);
         if(side.getDirection() == direction)
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPlanksPainted.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPlanksPainted.java
index 51d5e8862..0937562b6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPlanksPainted.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPlanksPainted.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelPlanksPainted<T extends BlockLogic> extends BlockModelStandard<T> {
     public static final IconCoordinate[] texCoords = new IconCoordinate[DyeColor.COLOR_AMOUNT];
@@ -21,7 +22,7 @@ public class BlockModelPlanksPainted<T extends BlockLogic> extends BlockModelSta
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
         return texCoords[meta & DyeColor.MASK_COLOR];
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPortal.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPortal.java
index 7d14b6bd2..04576c568 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPortal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPortal.java
@@ -8,6 +8,8 @@ import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelPortal<T extends BlockLogicPortal> extends BlockModelTransparent<T> {
     protected IconCoordinate[] colors = new IconCoordinate[16];
@@ -19,7 +21,7 @@ public class BlockModelPortal<T extends BlockLogicPortal> extends BlockModelTran
         onRenderLayer(1);
     }
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side)
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side)
     {
         if(blockAccess.getBlockId(x, y, z) == block.id())
         {
@@ -29,7 +31,7 @@ public class BlockModelPortal<T extends BlockLogicPortal> extends BlockModelTran
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         return colors[block.getLogic().fromMetadata(data).blockMeta];
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPumice.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPumice.java
index d4caf3503..a1ce327dc 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPumice.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPumice.java
@@ -10,6 +10,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -20,24 +22,24 @@ public class BlockModelPumice<T extends BlockLogic> extends BlockModelStandard<T
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         lavaFlag = true;
         boolean ob = renderBlocks.overbright;
         renderBlocks.overbright = true;
 //        block.setBlockBounds(0.005, 0.005, 0.005, 0.995, 0.995, 0.995);
-        boolean rendered = super.render(tessellator, x, y, z);
+        boolean rendered = super.render(tessellator, worldSource, x, y, z);
 
         renderBlocks.overbright = ob;
         lavaFlag = false;
 //        block.setBlockBounds(0, 0, 0, 1, 1, 1);
-        rendered |= super.render(tessellator, x, y, z);
+        rendered |= super.render(tessellator, worldSource, x, y, z);
         return rendered;
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         if(renderBlocks.useInventoryTint) {
-            int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+            int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
             float r = (float) (color >> 16 & 0xff) / 255F;
             float g = (float) (color >> 8 & 0xff) / 255F;
             float b = (float) (color & 0xff) / 255F;
@@ -68,13 +70,13 @@ public class BlockModelPumice<T extends BlockLogic> extends BlockModelStandard<T
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         if (lavaFlag) return TextureRegistry.getTexture("minecraft:block/lava_still");
         return super.getBlockTextureFromSideAndMetadata(side, data);
     }
 
     @Override
-    public IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data) {
+    public @Nullable IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data) {
         if (lavaFlag) return TextureRegistry.getTexture("minecraft:block/lava_still");
         return super.getBlockOverbrightTextureFromSideAndMeta(side, data);
     }
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 23b3375e5..1f1c2e9b0 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
@@ -10,6 +10,8 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelRail<T extends BlockLogicRail> extends BlockModelStandard<T> {
     protected IconCoordinate railCurve = TextureRegistry.getTexture("minecraft:block/rail/turn");
@@ -27,8 +29,8 @@ public class BlockModelRail<T extends BlockLogicRail> extends BlockModelStandard
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int l = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int l = worldSource.getBlockMetadata(x, y, z);
         IconCoordinate i1 = getBlockTextureFromSideAndMetadata(Side.BOTTOM, l);
         if(renderBlocks.overrideBlockTexture != null)
         {
@@ -41,17 +43,17 @@ public class BlockModelRail<T extends BlockLogicRail> extends BlockModelStandard
 		float brightness = 1.0f;
 		if(LightmapHelper.isLightmapEnabled()) {
 			if(renderBlocks.overbright) {
-				tessellator.setLightmapCoord(LightmapHelper.getOverbrightLightmapCoord(renderBlocks.blockAccess.getSavedLightValue(LightLayer.Sky, x, y, z)));
+				tessellator.setLightmapCoord(LightmapHelper.getOverbrightLightmapCoord(worldSource.getSavedLightValue(LightLayer.Sky, x, y, z)));
 			}else {
-				tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+				tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
 			}
 		}else {
 			if(!renderBlocks.overbright) {
-				brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+				brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
 			}
 		}
 		if(renderBlocks.overbright) {
-			i1 = getBlockOverbrightTexture(renderBlocks.blockAccess, x, y, z, 0);
+			i1 = getBlockOverbrightTexture(worldSource, x, y, z, Side.BOTTOM);
 			if(i1 == null) {
 				return false;
 			}
@@ -120,7 +122,7 @@ public class BlockModelRail<T extends BlockLogicRail> extends BlockModelStandard
         return false;
     }
     @Override
-    public IconCoordinate getBlockOverbrightTexture(WorldSource blockAccess, int x, int y, int z, int side)
+    public @Nullable IconCoordinate getBlockOverbrightTexture(WorldSource blockAccess, int x, int y, int z, @NotNull Side side)
     {
         if (!block.getLogic().isPowered || (blockAccess.getBlockMetadata(x, y, z) & 8) == 0) return null;
 
@@ -128,7 +130,7 @@ public class BlockModelRail<T extends BlockLogicRail> extends BlockModelStandard
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if(block == Blocks.RAIL_POWERED && (data & 8) != 0)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRepeater.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRepeater.java
index debb189ba..7eb2acc04 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRepeater.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRepeater.java
@@ -6,8 +6,10 @@ import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicRepeater;
 import net.minecraft.core.block.Blocks;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelRepeater extends BlockModelStandard<BlockLogicRepeater> {
 	private static final BlockModelTorch<?> modelTorchActive = (BlockModelTorch<?>) BlockModelDispatcher.getInstance().getDispatch(Blocks.TORCH_REDSTONE_ACTIVE);
@@ -17,8 +19,8 @@ public class BlockModelRepeater extends BlockModelStandard<BlockLogicRepeater> {
         super(block);
     }
 
-    public boolean render(Tessellator tessellator, int x, int y, int z){
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z){
+        int meta = worldSource.getBlockMetadata(x, y, z);
         int i1 = meta & 3;
 
         switch(i1)
@@ -41,17 +43,17 @@ public class BlockModelRepeater extends BlockModelStandard<BlockLogicRepeater> {
         }
 
         int j1 = (meta & 0xc) >> 2;
-        renderStandardBlock(tessellator, block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z), x, y, z);
-        resetRenderBlocks();
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBlockBoundsFromState(worldSource, x, y, z), x, y, z);
+        renderBlocks.resetRenderBlocks();
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-        	int lmc = block.getLightmapCoord(renderBlocks.blockAccess, x, y, z);
+        	int lmc = block.getLightmapCoord(worldSource, x, y, z);
         	if(block.emission > 0) {
         		lmc = LightmapHelper.setBlocklightValue(lmc, 15);
         	}
         	tessellator.setLightmapCoord(lmc);
         }else {
-    		brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+    		brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
     		if(block.emission > 0 || Global.accessor.isFullbrightEnabled()) {
     			brightness = 1.0f;
     		}
@@ -100,7 +102,7 @@ public class BlockModelRepeater extends BlockModelStandard<BlockLogicRepeater> {
     }
 
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side)
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side)
     {
         return true;
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
index 5317450e0..10f2577dd 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
@@ -8,6 +8,7 @@ import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelRope<T extends BlockLogicRope>
 extends BlockModelStandard<T> {
@@ -16,8 +17,8 @@ extends BlockModelStandard<T> {
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        WorldSource world = renderBlocks.blockAccess;
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        WorldSource world = worldSource;
         Block<?> below;
         boolean hasFloor = (below = world.getBlock(x, y - 1, z)) != null && below.canPlaceOnSurface();
         boolean hasBlockNegX = canConnect(world, x, y, z, Side.WEST);
@@ -41,44 +42,44 @@ extends BlockModelStandard<T> {
         if (drawKnot)
         {
             bounds.set(0.5f - knotThickness, 0.5f - knotThickness, 0.5f - knotThickness, 0.5f + knotThickness, 0.5f + knotThickness, 0.5f + knotThickness);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
 
         if (hasBlockPosY)
         {
             bounds.set(0.5f - ropeThickness, 0.5f, 0.5f - ropeThickness, 0.5f + ropeThickness, 1, 0.5f + ropeThickness);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if (hasBlockNegY)
         {
             bounds.set(0.5f - ropeThickness, 0, 0.5f - ropeThickness, 0.5f + ropeThickness, 0.5f, 0.5f + ropeThickness);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if (hasBlockPosX)
         {
             bounds.set(0.5f, 0.5f - ropeThickness, 0.5f - ropeThickness, 1, 0.5f + ropeThickness, 0.5f + ropeThickness);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if (hasBlockNegX)
         {
             bounds.set(0, 0.5f - ropeThickness, 0.5f - ropeThickness, 0.5f, 0.5f + ropeThickness, 0.5f + ropeThickness);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if (hasBlockPosZ)
         {
             bounds.set(0.5f - ropeThickness, 0.5f - ropeThickness, 0.5f, 0.5f + ropeThickness, 0.5f + ropeThickness, 1);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if (hasBlockNegZ)
         {
             bounds.set(0.5f - ropeThickness, 0.5f - ropeThickness, 0f, 0.5f + ropeThickness, 0.5f + ropeThickness, 0.5f);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         if (hasFloor){
             bounds.set(0.5f - pileWidth, 0,0.5f - pileWidth, 0.5f + pileWidth, knotThickness, 0.5f + pileWidth);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.5f - knotThickness, 0,0.5f - knotThickness, 0.5f + knotThickness, ropeThickness * 3, 0.5f + knotThickness);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
 
         return true;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRotatable.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRotatable.java
index 16cf2cce7..78260b389 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRotatable.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRotatable.java
@@ -5,6 +5,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.helper.Sides;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelRotatable<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelRotatable(Block<T> block) {
@@ -12,7 +13,7 @@ public class BlockModelRotatable<T extends BlockLogic> extends BlockModelStandar
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         int index = Sides.orientationLookUp[6 * data + side.getId()];
         return blockTextures.get(Side.getSideById(index));
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSeat.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSeat.java
index de48d025c..4155a8f1f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSeat.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSeat.java
@@ -5,6 +5,8 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelSeat<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelSeat(Block<T> block) {
@@ -12,17 +14,17 @@ public class BlockModelSeat<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        AABB bounds = block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        AABB bounds = block.getBlockBoundsFromState(worldSource, x, y, z);
 
-        setRenderSide(Side.BOTTOM, false); // Set bottom face to not render
-        renderStandardBlock(tessellator, bounds, x, y, z); // Render seat
+        renderBlocks.setRenderSide(Side.BOTTOM, false); // Set bottom face to not render
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z); // Render seat
 
         // Set only the bottom face to render
         renderBlocks.renderBitMask = 0b111111;
-        setRenderSide(Side.BOTTOM, true);
+        renderBlocks.setRenderSide(Side.BOTTOM, true);
         bounds.minY += 0.1875D; // Shift the bottom face up
-        renderStandardBlock(tessellator, bounds, x, y, z); // Render Seat
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z); // Render Seat
 
         // Reset block values
         renderBlocks.renderBitMask = 0;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlab.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlab.java
index 483bf3a65..e8a6e1f00 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlab.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlab.java
@@ -5,6 +5,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicSlab;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelSlab<T extends BlockLogicSlab> extends BlockModelStandard<T> {
     protected BlockModelStandard<T> parentModel;
@@ -18,13 +19,13 @@ public class BlockModelSlab<T extends BlockLogicSlab> extends BlockModelStandard
         withCustomItemBounds(0, 0, 0, 1, 0.5d, 1);
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         return parentModel.getBlockTextureFromSideAndMetadata(side, block.getLogic().modelBlockMetadata);
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
     {
         return parentModel.getBlockTextureFromSideAndMetadata(side, block.getLogic().modelBlockMetadata);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlabMarble.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlabMarble.java
index cd9b156d6..b756ab8ae 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlabMarble.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlabMarble.java
@@ -7,6 +7,7 @@ import net.minecraft.core.block.BlockLogicSlab;
 import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelSlabMarble<T extends BlockLogicSlab> extends BlockModelSlab<T> {
     protected IconCoordinate slabSide = TextureRegistry.getTexture("minecraft:block/carved_marble");
@@ -15,12 +16,12 @@ public class BlockModelSlabMarble<T extends BlockLogicSlab> extends BlockModelSl
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
     {
         return getBlockTextureFromSideAndMetadata(side, blockAccess.getBlockMetadata(x, y, z));
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if(data != 1 && (side.getAxis() != Axis.Y))
         {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlabPainted.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlabPainted.java
index 8d3bd72f1..7fb6e7ce3 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlabPainted.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSlabPainted.java
@@ -5,6 +5,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicSlab;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelSlabPainted<T extends BlockLogicSlab> extends BlockModelSlab<T> {
     public BlockModelSlabPainted(Block<T> block) {
@@ -12,13 +13,13 @@ public class BlockModelSlabPainted<T extends BlockLogicSlab> extends BlockModelS
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
         meta = meta >> 4;
         return BlockModelPlanksPainted.texCoords[meta & 0x0F];
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
     {
         return getBlockTextureFromSideAndMetadata(side, blockAccess.getBlockMetadata(x, y, z));
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
index 44397d205..7cf1a1471 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
@@ -8,6 +8,9 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicSpikes;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelSpikes<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelSpikes(Block<T> block) {
@@ -15,22 +18,22 @@ public class BlockModelSpikes<T extends BlockLogic> extends BlockModelStandard<T
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int metaData = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int metaData = worldSource.getBlockMetadata(x, y, z);
         IconCoordinate texture = getBlockTextureFromSideAndMetadata(Side.EAST, metaData);
         if(renderBlocks.overrideBlockTexture != null)
         {
             texture = renderBlocks.overrideBlockTexture;
         }
 
-        renderStandardBlock(tessellator, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F), x, y, z);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F), x, y, z);
 
         if(BlockLogicSpikes.isSpikesUp(metaData)) {
             float brightness = 1.0f;
             if(LightmapHelper.isLightmapEnabled()) {
-            	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+            	tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
             }else {
-            	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            	brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
             }
             tessellator.setColorOpaque_F(brightness, brightness, brightness);
             double uMin = texture.getIconUMin();
@@ -106,8 +109,4 @@ public class BlockModelSpikes<T extends BlockLogic> extends BlockModelStandard<T
     public boolean shouldItemRender3d() {
         return false;
     }
-    @Override
-    public float getItemRenderScale() {
-        return 0.5f;
-    }
 }
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 563d440dd..9e79395c1 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
@@ -8,10 +8,15 @@ import net.minecraft.core.block.BlockLogicStairs;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelStairs<T extends BlockLogicStairs> extends BlockModelStandard<T> {
+    protected static final DisplayPos STAIRS_GUI = new DisplayPos(0, 0, 0, 30, 135, 0, 0.625f, 0.625f, 0.625f);
+    protected static final DisplayPos STAIRS_HEAD = new DisplayPos(0, 0, 0, 0, -90, 0, 1f, 1f, 1f);
+    protected static final DisplayPos STAIRS_THIRD_PERSON_LEFT_HAND = new DisplayPos(0, 2.5f/16f, 0, 75, -135, 0, 0.375f, 0.375f, 0.375f);
     protected BlockModelStandard<T> parentModel;
     public BlockModelStairs(Block<T> block) {
         super(block);
@@ -20,11 +25,15 @@ public class BlockModelStairs<T extends BlockLogicStairs> extends BlockModelStan
         overbrightTextures.copy(parentModel.overbrightTextures);
         retroBlockTextures.copy(parentModel.retroBlockTextures);
         retroOverbrightTextures.copy(parentModel.retroOverbrightTextures);
+
+        setDisplayPos(DisplayPos.GUI, STAIRS_GUI);
+        setDisplayPos(DisplayPos.HEAD, STAIRS_HEAD);
+        setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, STAIRS_THIRD_PERSON_LEFT_HAND);
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int meta = worldSource.getBlockMetadata(x, y, z);
         int hRotation = meta & 0b0011;
         int vRotation = meta & 0b1000;
 
@@ -35,37 +44,37 @@ public class BlockModelStairs<T extends BlockLogicStairs> extends BlockModelStan
         if(hRotation == 0)
         {
             bounds.set(0.0F, 0.0F + stepYOffset, 0.0F, 0.5F, 0.5F + stepYOffset, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         } else
         if(hRotation == 1)
         {
             bounds.set(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.5F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         } else
         if(hRotation == 2)
         {
             bounds.set(0.0F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 0.5F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.0F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         } else {
             bounds.set(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             bounds.set(0.0F, 0.0F + stepYOffset, 0.5F, 1.0F, 0.5F + stepYOffset, 1.0F);
-            renderStandardBlock(tessellator, bounds, x, y, z);
+            renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         }
         return true;
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         if(renderBlocks.useInventoryTint)
         {
-            int j = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+            int j = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
             float f1 = (float)(j >> 16 & 0xff) / 255F;
             float f3 = (float)(j >> 8 & 0xff) / 255F;
             float f5 = (float)(j & 0xff) / 255F;
@@ -76,52 +85,52 @@ public class BlockModelStairs<T extends BlockLogicStairs> extends BlockModelStan
             AABB bounds;
             if(l == 0)
             {
-                bounds = AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F);
+                bounds = AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
             } else {
-                bounds = AABB.getTemporaryBB(0.0F, 0.0F, 0.5F, 1.0F, 0.5F, 1.0F);
+                bounds = AABB.getTemporaryBB(0.5F, 0.5F, 0.0F, 1.0F, 1.0F, 1.0F);
             }
             GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, -1F, 0.0F);
-            renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
+            renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 1.0F, 0.0F);
-            renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
+            renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, -1F);
-            renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
+            renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(0.0F, 0.0F, 1.0F);
-            renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
+            renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(-1F, 0.0F, 0.0F);
-            renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
+            renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setNormal(1.0F, 0.0F, 0.0F);
-            renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
+            renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
             tessellator.draw();
 
             GL11.glTranslatef(0.5F, 0.5F, 0.5F);
         }
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         return parentModel.getBlockTextureFromSideAndMetadata(side, data);
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
     {
         return parentModel.getBlockTexture(blockAccess, x, y, z, side);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairsPainted.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairsPainted.java
index c60850ab1..3aa0e7be2 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairsPainted.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairsPainted.java
@@ -5,6 +5,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicStairs;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelStairsPainted<T extends BlockLogicStairs> extends BlockModelStairs<T> {
     public BlockModelStairsPainted(Block<T> block) {
@@ -12,13 +13,13 @@ public class BlockModelStairsPainted<T extends BlockLogicStairs> extends BlockMo
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int meta) {
         meta = meta >> 4;
         return BlockModelPlanksPainted.texCoords[meta & 0x0F];
     }
 
     @Override
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
     {
         return getBlockTextureFromSideAndMetadata(side, blockAccess.getBlockMetadata(x, y, z));
     }
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 1601225cd..093e119a8 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
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.LightmapHelper;
+import net.minecraft.client.render.item.model.ItemModelStandard;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
@@ -13,10 +14,23 @@ import net.minecraft.core.world.WorldSource;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
 
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 
 public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
+    protected static final RenderBlocks renderBlocks = new RenderBlocks();
+
+    protected static final DisplayPos DEFAULT_BLOCK_GUI = new DisplayPos(0, 0, 0, 30, 225, 0, 0.625f, 0.625f, 0.625f);
+    protected static final DisplayPos DEFAULT_BLOCK_GROUND = new DisplayPos(0, 3/16f, 0, 0, 0, 0, 0.25f, 0.25f, 0.25f);
+    protected static final DisplayPos DEFAULT_BLOCK_FIXED = new DisplayPos(0, 0, 0, 0, 0, 0, 0.5f, 0.5f, 0.5f);
+    protected static final DisplayPos DEFAULT_BLOCK_THIRD_PERSON_RIGHT_HAND = new DisplayPos(0, 2.5f/16f, 0, 75, 45, 0, 0.375f, 0.375f, 0.375f);
+    protected static final DisplayPos DEFAULT_BLOCK_THIRD_PERSON_LEFT_HAND = new DisplayPos(-0, 2.5f/16f, 0, 75, 45, 0, 0.375f, 0.375f, 0.375f);
+    protected static final DisplayPos DEFAULT_BLOCK_FIRST_PERSON_RIGHT_HAND = new DisplayPos(0, 0, 0, 0, 45, 0, 0.4f, 0.4f, 0.4f);
+    protected static final DisplayPos DEFAULT_BLOCK_FIRST_PERSON_LEFT_HAND = new DisplayPos(0, 0, 0, 0, 225, 0, 0.4f, 0.4f, 0.4f);
+
     public static final IconCoordinate BLOCK_TEXTURE_MISSING = TextureRegistry.getTexture("minecraft:block/texture_missing");
     public static final IconCoordinate BLOCK_TEXTURE_UNASSIGNED = TextureRegistry.getTexture("minecraft:block/texture_unassigned");
     public @Nullable AABB itemRenderBounds = null;
@@ -32,19 +46,52 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
     protected final TextureLayer retroBlockTextures = new TextureLayer();
     protected final TextureLayer retroOverbrightTextures = new TextureLayer();
 
+    protected @NotNull Map<@NotNull String, @NotNull DisplayPos> displayPosMap = new HashMap<>();
+
     public BlockModelStandard(Block<T> block) {
         super(block);
+        displayPosMap.put(DisplayPos.GUI, DEFAULT_BLOCK_GUI);
+        displayPosMap.put(DisplayPos.GROUND, DEFAULT_BLOCK_GROUND);
+        displayPosMap.put(DisplayPos.FIXED, DEFAULT_BLOCK_FIXED);
+        displayPosMap.put(DisplayPos.THIRD_PERSON_RIGHT_HAND, DEFAULT_BLOCK_THIRD_PERSON_RIGHT_HAND);
+        displayPosMap.put(DisplayPos.THIRD_PERSON_LEFT_HAND, DEFAULT_BLOCK_THIRD_PERSON_LEFT_HAND); // TODO make automatic since its just the axis flipped
+        displayPosMap.put(DisplayPos.FIRST_PERSON_RIGHT_HAND, DEFAULT_BLOCK_FIRST_PERSON_RIGHT_HAND);
+        displayPosMap.put(DisplayPos.FIRST_PERSON_LEFT_HAND, DEFAULT_BLOCK_FIRST_PERSON_LEFT_HAND);
+    }
+
+    @Override
+    public boolean renderNoCulling(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        renderBlocks.renderAllFaces = true;
+        boolean result = render(tessellator, worldSource, x, y, z);
+        renderBlocks.renderAllFaces = false;
+        return result;
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        return renderStandardBlock(tessellator, block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z), x, y, z);
+    public boolean renderWithOverrideTexture(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z, IconCoordinate textureIndex) {
+        renderBlocks.overrideBlockTexture = textureIndex;
+        boolean result = render(tessellator, worldSource, x, y, z);
+        renderBlocks.overrideBlockTexture = null;
+        return result;
     }
 
     @Override
-	public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        return renderBlocks.renderStandardBlock(tessellator, worldSource, this, block.getBlockBoundsFromState(worldSource, x, y, z), x, y, z);
+    }
+
+    @Override
+    public boolean renderOverbright(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        renderBlocks.overbright = true;
+        boolean result = render(tessellator, worldSource, x, y, z);
+        renderBlocks.overbright = false;
+        return result;
+    }
+
+    @Override
+	public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
 		if(renderBlocks.useInventoryTint) {
-			int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+			int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
 			float r = (float) (color >> 16 & 0xff) / 255F;
 			float g = (float) (color >> 8 & 0xff) / 255F;
 			float b = (float) (color & 0xff) / 255F;
@@ -68,22 +115,22 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
         tessellator.startDrawingQuads();
 
         tessellator.setNormal(0.0f, -1.0f, 0.0f);
-        renderBottomFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.BOTTOM, metadata));
 
         tessellator.setNormal(0.0f, 1.0f, 0.0f);
-        renderTopFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.TOP, metadata));
 
         tessellator.setNormal(0.0f, 0.0f, -1.0f);
-        renderNorthFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.NORTH, metadata));
 
         tessellator.setNormal(0.0f, 0.0f, 1.0f);
-        renderSouthFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.SOUTH, metadata));
 
         tessellator.setNormal(-1.0f, 0.0f, 0.0f);
-        renderWestFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.WEST, metadata));
 
         tessellator.setNormal(1.0f, 0.0f, 0.0f);
-        renderEastFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockTextureFromSideAndMetadata(Side.EAST, metadata));
 
         tessellator.draw();
 
@@ -92,7 +139,7 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
 
             brightness = 1.0f;
             if(renderBlocks.useInventoryTint) {
-                int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+                int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
                 float r = (float) (color >> 16 & 0xff) / 255F;
                 float g = (float) (color >> 8 & 0xff) / 255F;
                 float b = (float) (color & 0xff) / 255F;
@@ -108,22 +155,22 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
             tessellator.startDrawingQuads();
 
             tessellator.setNormal(0.0f, -1.0f, 0.0f);
-            renderBottomFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.BOTTOM, metadata));
+            renderBlocks.renderBottomFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.BOTTOM, metadata));
 
             tessellator.setNormal(0.0f, 1.0f, 0.0f);
-            renderTopFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.TOP, metadata));
+            renderBlocks.renderTopFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.TOP, metadata));
 
             tessellator.setNormal(0.0f, 0.0f, -1.0f);
-            renderNorthFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.NORTH, metadata));
+            renderBlocks.renderNorthFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.NORTH, metadata));
 
             tessellator.setNormal(0.0f, 0.0f, 1.0f);
-            renderSouthFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.SOUTH, metadata));
+            renderBlocks.renderSouthFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.SOUTH, metadata));
 
             tessellator.setNormal(-1.0f, 0.0f, 0.0f);
-            renderWestFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.WEST, metadata));
+            renderBlocks.renderWestFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.WEST, metadata));
 
             tessellator.setNormal(1.0f, 0.0f, 0.0f);
-            renderEastFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.EAST, metadata));
+            renderBlocks.renderEastFace(tessellator, bounds, 0.0, 0.0, 0.0, getBlockOverbrightTextureFromSideAndMeta(Side.EAST, metadata));
 
             tessellator.draw();
 
@@ -137,17 +184,23 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
     }
 
     @Override
-    public float getItemRenderScale() {
-        return 0.25f;
+    public @NotNull DisplayPos getItemDisplayPos(@NotNull String id) {
+        return displayPosMap.getOrDefault(id, DisplayPos.DEFAULT_DISPLAY_POS);
+    }
+
+    public @NotNull BlockModelStandard<T> setDisplayPos(@NotNull String id, @NotNull DisplayPos displayPos) {
+        this.displayPosMap.put(id, displayPos);
+        return this;
     }
-    public IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
+
+    public @Nullable IconCoordinate getBlockTexture(WorldSource blockAccess, int x, int y, int z, Side side)
     {
         return getBlockTextureFromSideAndMetadata(side, blockAccess.getBlockMetadata(x, y, z));
     }
-    @Override
-    public IconCoordinate getBlockOverbrightTexture(WorldSource blockAccess, int x, int y, int z, int side)
+
+    public @Nullable IconCoordinate getBlockOverbrightTexture(WorldSource blockAccess, int x, int y, int z, @NotNull Side side)
     {
-        return getBlockOverbrightTextureFromSideAndMeta(Side.getSideById(side), blockAccess.getBlockMetadata(x, y, z));
+        return getBlockOverbrightTextureFromSideAndMeta(side, blockAccess.getBlockMetadata(x, y, z));
     }
 
     @Override
@@ -155,16 +208,14 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
         return overbrightTextures.hasTexture();
     }
 
-    @Override
-    public IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data) {
+    public @Nullable IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data) {
         if (retroOverbrightTextures.hasTexture && isRetro()) {
             return retroOverbrightTextures.get(side);
         }
         return overbrightTextures.get(side);
     }
 
-    @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if (retroBlockTextures.hasTexture && isRetro()) {
             return retroBlockTextures.get(side);
@@ -172,39 +223,43 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
         return blockTextures.get(side);
     }
     @Override
-    public IconCoordinate getParticleTexture(Side side, int meta){
+    public @Nullable IconCoordinate getParticleTexture(@NotNull Side side, int meta){
         return getBlockTextureFromSideAndMetadata(side, meta);
     }
+
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side, int meta)
+    public @Nullable IconCoordinate getOverlayTexture(int meta) {
+        return getBlockTextureFromSideAndMetadata(Side.NORTH, meta);
+    }
+
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side, int meta)
     {
         return shouldSideBeRendered(blockAccess, bounds, x, y, z, side);
     }
-    @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side)
+
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side)
     {
-        Side side1 = Side.getSideById(side);
-        if(side1 == Side.BOTTOM && bounds.minY > 0.0D)
+        if(side == Side.BOTTOM && bounds.minY > 0.0D)
         {
             return true;
         }
-        else if(side1 == Side.TOP && bounds.maxY < 1.0D)
+        else if(side == Side.TOP && bounds.maxY < 1.0D)
         {
             return true;
         }
-        else if(side1 == Side.NORTH && bounds.minZ > 0.0D)
+        else if(side == Side.NORTH && bounds.minZ > 0.0D)
         {
             return true;
         }
-        else if(side1 == Side.SOUTH && bounds.maxZ < 1.0D)
+        else if(side == Side.SOUTH && bounds.maxZ < 1.0D)
         {
             return true;
         }
-        else if(side1 == Side.WEST && bounds.minX > 0.0D)
+        else if(side == Side.WEST && bounds.minX > 0.0D)
         {
             return true;
         }
-        else if(side1 == Side.EAST && bounds.maxX < 1.0D)
+        else if(side == Side.EAST && bounds.maxX < 1.0D)
         {
             return true;
         }
@@ -213,17 +268,22 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
             return !blockAccess.isBlockOpaqueCube(x, y, z);
         }
     }
-    @Override
-    public boolean shouldSideBeColored(WorldSource blockAccess, int x, int y, int z, int side, int meta){
+
+    public boolean shouldSideBeColored(@NotNull WorldSource worldSource, int x, int y, int z, @NotNull Side side, int meta){
         return true;
     }
+
     @Override
+    public int particleColorIndex(@NotNull WorldSource worldSource, int x, int y, int z, @NotNull Side side, int meta) {
+        return shouldSideBeColored(worldSource, x, y, z, side, meta) ? 0 : -1;
+    }
+
     public AABB getBlockBoundsForItemRender()
     {
         if (itemRenderBounds != null){
             return itemRenderBounds;
         }
-        return super.getBlockBoundsForItemRender();
+        return block.getBounds();
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStoneMossy.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStoneMossy.java
index a32e26629..1b96cab2b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStoneMossy.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStoneMossy.java
@@ -7,6 +7,8 @@ import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -18,23 +20,23 @@ public class BlockModelStoneMossy<T extends BlockLogic> extends BlockModelStanda
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        AABB bounds = block.getBlockBoundsFromState(renderBlocks.blockAccess, x, y, z);
-        renderStandardBlock(tessellator, bounds, x, y, z, 1.0f, 1.0f, 1.0f);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        AABB bounds = block.getBlockBoundsFromState(worldSource, x, y, z);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z, 1.0f, 1.0f, 1.0f);
         renderBlocks.overrideBlockTexture = mossOverlay;
-        renderStandardBlock(tessellator, bounds, x, y, z);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         renderBlocks.overrideBlockTexture = null;
         return true;
     }
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         renderBlocks.useInventoryTint = false;
-        super.renderBlockOnInventory(tessellator, metadata, brightness, alpha, lightmapCoordinate);
+        super.renderStandalone(tessellator, metadata, brightness, alpha, lightmapCoordinate);
         renderBlocks.useInventoryTint = true;
         GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
 
-        int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
+        int color = BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata, 0);
         float r = (float)(color >> 16 & 0xff) / 255F;
         float g = (float)(color >> 8 & 0xff) / 255F;
         float b = (float)(color & 0xff) / 255F;
@@ -45,27 +47,27 @@ public class BlockModelStoneMossy<T extends BlockLogic> extends BlockModelStanda
 
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, -1F, 0.0F);
-        renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
+        renderBlocks.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
+        renderBlocks.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, -1F);
-        renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
+        renderBlocks.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
+        renderBlocks.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(-1F, 0.0F, 0.0F);
-        renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
+        renderBlocks.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
+        renderBlocks.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, mossCoord);
         tessellator.draw();
         GL11.glTranslatef(0.5F, 0.5F, 0.5F);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTorch.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTorch.java
index bb8fae801..b99e1643a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTorch.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTorch.java
@@ -7,6 +7,9 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicTorch;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelTorch<T extends BlockLogic> extends BlockModelStandard<T> {
     public BlockModelTorch(Block<T> block) {
@@ -14,12 +17,12 @@ public class BlockModelTorch<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-            tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+            tessellator.setLightmapCoord(block.getLightmapCoord(worldSource, x, y, z));
         }else {
-            brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
             if(block.emission > 0) {
                 brightness = 1.0F;
             }
@@ -28,7 +31,7 @@ public class BlockModelTorch<T extends BlockLogic> extends BlockModelStandard<T>
         double d = 0.4;
         double d1 = 0.5D - d;
         double d2 = 0.2;
-        int direction = renderBlocks.blockAccess.getBlockMetadata(x, y, z) & BlockLogicTorch.MASK_DIRECTION;
+        int direction = worldSource.getBlockMetadata(x, y, z) & BlockLogicTorch.MASK_DIRECTION;
         switch (direction) {
             case BlockLogicTorch.SIDE_WEST:
                 renderTorchAtAngle(tessellator, (double) x - d1, (double) y + d2, z, -d, 0.0D);
@@ -107,8 +110,5 @@ public class BlockModelTorch<T extends BlockLogic> extends BlockModelStandard<T>
     public boolean shouldItemRender3d() {
         return false;
     }
-    @Override
-    public float getItemRenderScale() {
-        return 0.5f;
-    }
+
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTorchRedstone.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTorchRedstone.java
index 0b31ef818..205245bb4 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTorchRedstone.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTorchRedstone.java
@@ -5,16 +5,18 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelTorchRedstone<T extends BlockLogic> extends BlockModelTorch<T> {
-    private static final BlockModel<?> redstoneWire = BlockModelDispatcher.getInstance().getDispatch(Blocks.WIRE_REDSTONE);
+    private static final BlockModelStandard<?> redstoneWire = (BlockModelStandard<?>) BlockModelDispatcher.getInstance().getDispatch(Blocks.WIRE_REDSTONE);
 
     public BlockModelTorchRedstone(Block<T> block) {
         super(block);
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         if(side == Side.TOP)
         {
@@ -26,7 +28,7 @@ public class BlockModelTorchRedstone<T extends BlockLogic> extends BlockModelTor
     }
 
     @Override
-    public IconCoordinate getParticleTexture(Side side, int meta) {
+    public @Nullable IconCoordinate getParticleTexture(@NotNull Side side, int meta) {
         return blockTextures.get(Side.NORTH);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTransparent.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTransparent.java
index 887066417..eff666ee2 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTransparent.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTransparent.java
@@ -2,8 +2,10 @@ package net.minecraft.client.render.block.model;
 
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelTransparent<T extends BlockLogic> extends BlockModelStandard<T> {
     private final boolean renderInside;
@@ -12,7 +14,7 @@ public class BlockModelTransparent<T extends BlockLogic> extends BlockModelStand
         this.renderInside = renderInside;
     }
     @Override
-    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, int side)
+    public boolean shouldSideBeRendered(WorldSource blockAccess, AABB bounds, int x, int y, int z, @NotNull Side side)
     {
         if(!renderInside && blockAccess.getBlockId(x, y, z) == block.id())
         {
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 f29b8e6a1..8096fe0a9 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
@@ -8,6 +8,8 @@ import net.minecraft.core.block.BlockLogicTrapDoor;
 import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.helper.Sides;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -19,8 +21,8 @@ public class BlockModelTrapDoor<T extends BlockLogic> extends BlockModelStandard
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int metadata = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int metadata = worldSource.getBlockMetadata(x, y, z);
         boolean isUp = BlockLogicTrapDoor.isTrapdoorOpen(metadata);
 
         if(isUp) {
@@ -62,17 +64,17 @@ public class BlockModelTrapDoor<T extends BlockLogic> extends BlockModelStandard
                 renderBlocks.uvRotateWest = 3;
             }
         }
-        super.render(tessellator, x, y, z);
-        resetRenderBlocks();
+        super.render(tessellator, worldSource, x, y, z);
+        renderBlocks.resetRenderBlocks();
         return true;
     }
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
         GL11.glTranslatef(0, 0.25f, 0);
-        super.renderBlockOnInventory(tessellator, metadata, brightness, alpha, lightmapCoordinate);
+        super.renderStandalone(tessellator, metadata, brightness, alpha, lightmapCoordinate);
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         int orientation = data & 3;
         if(BlockLogicTrapDoor.isTrapdoorOpen(data)) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTrapDoorPainted.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTrapDoorPainted.java
index 0a38a0ca6..2e5c882fb 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTrapDoorPainted.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelTrapDoorPainted.java
@@ -9,6 +9,7 @@ import net.minecraft.core.util.helper.Axis;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.helper.Sides;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelTrapDoorPainted<T extends BlockLogic> extends BlockModelTrapDoor<T> {
     public static final IconCoordinate[] topTextures = new IconCoordinate[DyeColor.COLOR_AMOUNT];
@@ -24,7 +25,7 @@ public class BlockModelTrapDoorPainted<T extends BlockLogic> extends BlockModelT
         super(block);
     }
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         int color = (data >> 4) & DyeColor.MASK_COLOR;
         int orientation = data & 3;
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 1bc761e1a..265a7febd 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
@@ -7,41 +7,52 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicVeryRotatable;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.useless.dragonfly.DisplayPos;
 
 public class BlockModelVeryRotatable<T extends BlockLogic> extends BlockModelStandard<T> {
+    protected static final DisplayPos ROTATABLE_GUI = new DisplayPos(0, 0, 0, 30, 45, 0, 0.625f, 0.625f, 0.625f);
+    protected static final DisplayPos ROTATABLE_HEAD = new DisplayPos(0, 0, 0, 0, -180, 0, 1f, 1f, 1f);
+    protected static final DisplayPos ROTATABLE_FIRST_PERSON_RIGHT_HAND = new DisplayPos(0, 0, 0, 0, -45, 0, 0.4f, 0.4f, 0.4f);
+
     public BlockModelVeryRotatable(Block<T> block) {
         super(block);
+
+        setDisplayPos(DisplayPos.GUI, ROTATABLE_GUI);
+        setDisplayPos(DisplayPos.HEAD, ROTATABLE_HEAD);
+        setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, ROTATABLE_FIRST_PERSON_RIGHT_HAND);
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        final int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        final int meta = worldSource.getBlockMetadata(x, y, z);
         final Direction dir = BlockLogicVeryRotatable.metaToDirection(meta);
 
         if (dir == Direction.DOWN || dir == Direction.UP) {
             renderBlocks.uvRotateSouth = 1;
             renderBlocks.uvRotateNorth = 2;
         }
-        final boolean result = super.render(tessellator, x, y, z);
-        resetRenderBlocks();
+        final boolean result = super.render(tessellator, worldSource, x, y, z);
+        renderBlocks.resetRenderBlocks();
 
         return result;
     }
 
 
     @Override
-    public void renderBlockOnInventory(Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
-        super.renderBlockOnInventory(tessellator, 3, brightness, alpha, lightmapCoordinate);
+    public void renderStandalone(@NotNull Tessellator tessellator, int metadata, float brightness, float alpha, @Nullable Integer lightmapCoordinate) {
+        super.renderStandalone(tessellator, 3, brightness, alpha, lightmapCoordinate);
     }
 
     @Override
-    public IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data) {
+    public @Nullable IconCoordinate getBlockOverbrightTextureFromSideAndMeta(Side side, int data) {
         return super.getBlockOverbrightTextureFromSideAndMeta(getRotatedSide(side, data), data);
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data)
     {
         return super.getBlockTextureFromSideAndMetadata(getRotatedSide(side, data), data);
     }
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 66d69aedf..9f53e013a 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
@@ -10,6 +10,8 @@ import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.block.BlockLogicWireRedstone;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.Color;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockModelWireRedstone<T extends BlockLogic> extends BlockModelStandard<T> {
     protected final IconCoordinate wireStraight = TextureRegistry.getTexture("minecraft:block/wire_redstone_straight");
@@ -20,8 +22,8 @@ public class BlockModelWireRedstone<T extends BlockLogic> extends BlockModelStan
     }
 
     @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+    public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
+        int meta = worldSource.getBlockMetadata(x, y, z);
         IconCoordinate straight = wireStraight;
         IconCoordinate cross = wireCross;
         if(renderBlocks.overrideBlockTexture != null)
@@ -30,14 +32,14 @@ public class BlockModelWireRedstone<T extends BlockLogic> extends BlockModelStan
         }
         float brightness = 1.0f;
         if(LightmapHelper.isLightmapEnabled()) {
-//            int lmc = block.getLightmapCoord(renderBlocks.blockAccess, x, y, z);
+//            int lmc = block.getLightmapCoord(worldSource, x, y, z);
 //            if(Blocks.lightEmission[block.id] > 0) {
 //                lmc = LightmapHelper.setBlocklightValue(lmc, 15);
 //            }
-            int lmc = LightmapHelper.getLightmapCoord(renderBlocks.blockAccess.getSavedLightValue(LightLayer.Sky, x, y, z), Math.max(renderBlocks.blockAccess.getSavedLightValue(LightLayer.Block, x, y, z), meta & 0xF));
+            int lmc = LightmapHelper.getLightmapCoord(worldSource.getSavedLightValue(LightLayer.Sky, x, y, z), Math.max(worldSource.getSavedLightValue(LightLayer.Block, x, y, z), meta & 0xF));
             tessellator.setLightmapCoord(lmc);
         }else {
-            brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            brightness = renderBlocks.getBlockBrightness(worldSource, x, y, z);
             if(block.emission > 0) {
                 brightness = 1.0f;
             }
@@ -51,32 +53,32 @@ public class BlockModelWireRedstone<T extends BlockLogic> extends BlockModelStan
         float blue = color.getBlue() / 255.0f;
 
         tessellator.setColorOpaque_F(brightness * red, brightness * green, brightness * blue);
-        boolean west = BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x - 1, y, z, 1) || !renderBlocks.blockAccess.isBlockNormalCube(x - 1, y, z) && BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x - 1, y - 1, z, -1);
-        boolean east = BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x + 1, y, z, 3) || !renderBlocks.blockAccess.isBlockNormalCube(x + 1, y, z) && BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x + 1, y - 1, z, -1);
-        boolean north = BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x, y, z - 1, 2) || !renderBlocks.blockAccess.isBlockNormalCube(x, y, z - 1) && BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x, y - 1, z - 1, -1);
-        boolean south = BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x, y, z + 1, 0) || !renderBlocks.blockAccess.isBlockNormalCube(x, y, z + 1) && BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x, y - 1, z + 1, -1);
+        boolean west = BlockLogicWireRedstone.shouldConnectTo(worldSource, x - 1, y, z, 1) || !worldSource.isBlockNormalCube(x - 1, y, z) && BlockLogicWireRedstone.shouldConnectTo(worldSource, x - 1, y - 1, z, -1);
+        boolean east = BlockLogicWireRedstone.shouldConnectTo(worldSource, x + 1, y, z, 3) || !worldSource.isBlockNormalCube(x + 1, y, z) && BlockLogicWireRedstone.shouldConnectTo(worldSource, x + 1, y - 1, z, -1);
+        boolean north = BlockLogicWireRedstone.shouldConnectTo(worldSource, x, y, z - 1, 2) || !worldSource.isBlockNormalCube(x, y, z - 1) && BlockLogicWireRedstone.shouldConnectTo(worldSource, x, y - 1, z - 1, -1);
+        boolean south = BlockLogicWireRedstone.shouldConnectTo(worldSource, x, y, z + 1, 0) || !worldSource.isBlockNormalCube(x, y, z + 1) && BlockLogicWireRedstone.shouldConnectTo(worldSource, x, y - 1, z + 1, -1);
         boolean westUp = false;
         boolean eastUp = false;
         boolean northUp = false;
         boolean southUp = false;
-        if(!renderBlocks.blockAccess.isBlockOpaqueCube(x, y + 1, z))
+        if(!worldSource.isBlockOpaqueCube(x, y + 1, z))
         {
-            if(renderBlocks.blockAccess.isBlockNormalCube(x - 1, y, z) && BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x - 1, y + 1, z, -1))
+            if(worldSource.isBlockNormalCube(x - 1, y, z) && BlockLogicWireRedstone.shouldConnectTo(worldSource, x - 1, y + 1, z, -1))
             {
                 west = true;
                 westUp = true;
             }
-            if(renderBlocks.blockAccess.isBlockNormalCube(x + 1, y, z) && BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x + 1, y + 1, z, -1))
+            if(worldSource.isBlockNormalCube(x + 1, y, z) && BlockLogicWireRedstone.shouldConnectTo(worldSource, x + 1, y + 1, z, -1))
             {
                 east = true;
                 eastUp = true;
             }
-            if(renderBlocks.blockAccess.isBlockNormalCube(x, y, z - 1) && BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x, y + 1, z - 1, -1))
+            if(worldSource.isBlockNormalCube(x, y, z - 1) && BlockLogicWireRedstone.shouldConnectTo(worldSource, x, y + 1, z - 1, -1))
             {
                 north = true;
                 northUp = true;
             }
-            if(renderBlocks.blockAccess.isBlockNormalCube(x, y, z + 1) && BlockLogicWireRedstone.shouldConnectTo(renderBlocks.blockAccess, x, y + 1, z + 1, -1))
+            if(worldSource.isBlockNormalCube(x, y, z + 1) && BlockLogicWireRedstone.shouldConnectTo(worldSource, x, y + 1, z + 1, -1))
             {
                 south = true;
                 southUp = true;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelWool.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelWool.java
index 6059031e9..8c00fc865 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelWool.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelWool.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockModelWool<T extends BlockLogic> extends BlockModelStandard<T> {
     public static final IconCoordinate[] texCoords = new IconCoordinate[DyeColor.COLOR_AMOUNT];
@@ -20,7 +21,7 @@ public class BlockModelWool<T extends BlockLogic> extends BlockModelStandard<T>
     }
 
     @Override
-    public IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
+    public @Nullable IconCoordinate getBlockTextureFromSideAndMetadata(Side side, int data) {
         return texCoords[data & DyeColor.MASK_COLOR];
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/RenderBlocks.java b/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
similarity index 78%
rename from game/client/src/main/java/net/minecraft/client/render/RenderBlocks.java
rename to game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
index 959d7597a..097fe7176 100644
--- a/game/client/src/main/java/net/minecraft/client/render/RenderBlocks.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
@@ -1,23 +1,58 @@
-package net.minecraft.client.render;
+package net.minecraft.client.render.block.model;
 
+import net.minecraft.client.render.LightingCache;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.phys.AABB;
-import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
-public class RenderBlocks
+import static net.minecraft.client.render.block.model.BlockModel.FULL_CUBE_THRESHOLD;
+import static net.minecraft.client.render.block.model.BlockModel.SIDE_LIGHT_MULTIPLIER;
+
+public final class RenderBlocks
 {
+    public final Minecraft mc;
+    public IconCoordinate overrideBlockTexture;
+    public boolean flipTexture;
+    public boolean renderAllFaces;
+    public byte renderBitMask;
+    public boolean useInventoryTint;
+    public int uvRotateEast;
+    public int uvRotateWest;
+    public int uvRotateSouth;
+    public int uvRotateNorth;
+    public int uvRotateTop;
+    public int uvRotateBottom;
+    public boolean enableAO;
+    public float colorRedTopLeft;
+    public float colorRedBottomLeft;
+    public float colorRedBottomRight;
+    public float colorRedTopRight;
+    public float colorGreenTopLeft;
+    public float colorGreenBottomLeft;
+    public float colorGreenBottomRight;
+    public float colorGreenTopRight;
+    public float colorBlueTopLeft;
+    public float colorBlueBottomLeft;
+    public float colorBlueBottomRight;
+    public float colorBlueTopRight;
+    public int lightmapCoordTopLeft;
+    public int lightmapCoordBottomLeft;
+    public int lightmapCoordBottomRight;
+    public int lightmapCoordTopRight;
+    public boolean overbright;
+    public LightingCache cache = new LightingCache();
 
-    public RenderBlocks(WorldSource worldSource)
+    public RenderBlocks()
     {
         overrideBlockTexture = null;
         flipTexture = false;
@@ -29,29 +64,32 @@ public class RenderBlocks
         uvRotateNorth = 0;
         uvRotateTop = 0;
         uvRotateBottom = 0;
-        field_22352_G = 1;
-        blockAccess = worldSource;
         renderBitMask = 0;
-        forceAO = false;
         this.mc = Minecraft.getMinecraft();
     }
 
-    public RenderBlocks()
-    {
-        overrideBlockTexture = null;
-        flipTexture = false;
+    public void resetRenderBlocks(){
         renderAllFaces = false;
+        enableAO = false;
+//        overbright = false;
         useInventoryTint = true;
+        flipTexture = false;
+        overrideBlockTexture = null;
         uvRotateEast = 0;
         uvRotateWest = 0;
         uvRotateSouth = 0;
         uvRotateNorth = 0;
         uvRotateTop = 0;
         uvRotateBottom = 0;
-        field_22352_G = 1;
         renderBitMask = 0;
-        forceAO = false;
-        this.mc = Minecraft.getMinecraft();
+    }
+
+    public void setRenderSide(Side side, boolean shouldRender){
+        if (!shouldRender){
+            renderBitMask |= (byte) (1 << side.getId());
+        } else {
+            renderBitMask &= (byte) ~(1 << side.getId());
+        }
     }
 
     public float getBlockBrightness(WorldSource blockAccess, int x, int y, int z)
@@ -68,154 +106,72 @@ public class RenderBlocks
         return blockAccess.getBrightness(x, y, z, Blocks.lightEmission[id]);
     }
 
-	public void renderBlockFallingSand(Tessellator tessellator, BlockModel<?> blockModel, Block<?> block, WorldSource world, int x, int y, int z) {
-		final boolean lightmap = LightmapHelper.isLightmapEnabled();
-		
-		float sideBottom = 1.0f;
-		float sideTop = 1.0f;
-		float sideNorthSouth = 1.0f;
-		float sideEastWest = 1.0f;
-		if(enableDirectionalLight) {
-			sideBottom = 0.5f;
-			sideTop = 1.0f;
-			sideNorthSouth = 0.8f;
-			sideEastWest = 0.6f;
-		}
-		
-		tessellator.startDrawingQuads();
-		
-		int meta = world.getBlockMetadata(x, y, z);
-		
-		final float brightnessInside = lightmap ? 1.0f : getBlockBrightness(world, x, y, z);
-		float brightness = 1.0f;
-		
-		final int lmcInside = lightmap ? block.getLightmapCoord(world, x, y, z) : 0;
-
-        final AABB bounds = block.getBounds();
-
-		// Bottom
-		if(lightmap) {
-			tessellator.setLightmapCoord(LightmapHelper.max(lmcInside, block.getLightmapCoord(world, x, y - 1, z)));
-		}else {
-			brightness = Math.max(getBlockBrightness(world, x, y - 1, z), brightnessInside);
-		}
-		tessellator.setColorOpaque_F(sideBottom * brightness, sideBottom * brightness, sideBottom * brightness);
-		renderBottomFace(tessellator, bounds, -0.5, -0.5, -0.5, blockModel.getBlockTextureFromSideAndMetadata(Side.BOTTOM, meta));
-		
-		// Top
-		if(lightmap) {
-			tessellator.setLightmapCoord(LightmapHelper.max(lmcInside, block.getLightmapCoord(world, x, y + 1, z)));
-		}else {
-			brightness = Math.max(getBlockBrightness(world, x, y + 1, z), brightnessInside);	
-		}
-		tessellator.setColorOpaque_F(sideTop * brightness, sideTop * brightness, sideTop * brightness);
-		renderTopFace(tessellator, bounds, -0.5, -0.5, -0.5, blockModel.getBlockTextureFromSideAndMetadata(Side.TOP, meta));
-		
-		// North
-		if(lightmap) {
-			tessellator.setLightmapCoord(LightmapHelper.max(lmcInside, block.getLightmapCoord(world, x, y, z - 1)));
-		}else {
-			brightness = Math.max(getBlockBrightness(world, x, y, z - 1), brightnessInside);
-		}
-		tessellator.setColorOpaque_F(sideNorthSouth * brightness, sideNorthSouth * brightness, sideNorthSouth * brightness);
-		renderNorthFace(tessellator, bounds, -0.5, -0.5, -0.5, blockModel.getBlockTextureFromSideAndMetadata(Side.NORTH, meta));
-		
-		// South
-		if(lightmap) {
-			tessellator.setLightmapCoord(LightmapHelper.max(lmcInside, block.getLightmapCoord(world, x, y, z + 1)));
-		}else {
-			brightness = Math.max(getBlockBrightness(world, x, y, z + 1), brightnessInside);
-		}
-		tessellator.setColorOpaque_F(sideNorthSouth * brightness, sideNorthSouth * brightness, sideNorthSouth * brightness);
-		renderSouthFace(tessellator, bounds, -0.5, -0.5, -0.5, blockModel.getBlockTextureFromSideAndMetadata(Side.SOUTH, meta));
-		
-		// West
-		if(lightmap) {
-			tessellator.setLightmapCoord(LightmapHelper.max(lmcInside, block.getLightmapCoord(world, x - 1, y, z)));
-		}else {
-			brightness = Math.max(getBlockBrightness(world, x - 1, y, z), brightnessInside);
-		}
-		tessellator.setColorOpaque_F(sideEastWest * brightness, sideEastWest * brightness, sideEastWest * brightness);
-		renderWestFace(tessellator, bounds, -0.5, -0.5, -0.5, blockModel.getBlockTextureFromSideAndMetadata(Side.WEST, meta));
-		
-		// East
-		if(lightmap) {
-			tessellator.setLightmapCoord(LightmapHelper.max(lmcInside, block.getLightmapCoord(world, x + 1, y, z)));
-		}else {
-			brightness = Math.max(getBlockBrightness(world, x + 1, y, z), brightnessInside);
-		}
-		tessellator.setColorOpaque_F(sideEastWest * brightness, sideEastWest * brightness, sideEastWest * brightness);
-		renderEastFace(tessellator, bounds, -0.5, -0.5, -0.5, blockModel.getBlockTextureFromSideAndMetadata(Side.EAST, meta));
-		
-		tessellator.draw();
-	}
-
-    public boolean renderStandardBlock(Tessellator tessellator, BlockModel<?> blockModel, AABB bounds, int x, int y, int z)
+    public boolean renderStandardBlock(Tessellator tessellator, WorldSource worldSource, BlockModelStandard<?> blockModel, AABB bounds, int x, int y, int z)
     {
-        int color = BlockColorDispatcher.getInstance().getDispatch(blockModel.block).getWorldColor(blockAccess, x, y, z);
+        int color = BlockColorDispatcher.getInstance().getDispatch(blockModel.block).getWorldColor(worldSource, x, y, z, 0);
         float r = (float)(color >> 16 & 0xff) / 255F;
         float g = (float)(color >> 8 & 0xff) / 255F;
         float b = (float)(color & 0xff) / 255F;
-        return renderStandardBlock(tessellator, blockModel, bounds, x, y, z, r, g, b);
+        return renderStandardBlock(tessellator, worldSource, blockModel, bounds, x, y, z, r, g, b);
     }
 
     /**
      * @author CyborgCabbage
      * Thanks! :D
      */
-    public boolean renderStandardBlock(Tessellator tessellator, BlockModel<?> blockModel, AABB bounds, int x, int y, int z, float r, float g, float b) {
+    public boolean renderStandardBlock(Tessellator tessellator, WorldSource worldSource, BlockModelStandard<?> blockModel, AABB bounds, int x, int y, int z, float r, float g, float b) {
         this.enableAO = true;
-        int meta = blockAccess.getBlockMetadata(x, y, z);
-        cache.setupCache(blockModel.block, blockAccess, x, y, z);
+        int meta = worldSource.getBlockMetadata(x, y, z);
+        cache.setupCache(blockModel.block, worldSource, x, y, z);
         boolean somethingRendered = false;
         for (Side side : Side.sides){
-            somethingRendered |= renderSide(tessellator, blockModel, bounds, x, y, z, r, g, b, side, meta);
+            somethingRendered |= renderSide(tessellator, worldSource, blockModel, bounds, x, y, z, r, g, b, side, meta);
         }
         this.enableAO = false;
         return somethingRendered;
     }
-    public final boolean renderSide(Tessellator tessellator, BlockModel<?> blockModel, AABB bounds, int x, int y, int z, float r, float g, float b, Side side, int meta){
+    public boolean renderSide(Tessellator tessellator, WorldSource worldSource, BlockModelStandard<?> blockModel, AABB bounds, int x, int y, int z, float r, float g, float b, Side side, int meta){
         boolean useColor;
         switch (side){
             case BOTTOM:
-                useColor = blockModel.shouldSideBeColored(blockAccess, x, y, z, 0, meta);
-                return renderSide(tessellator, blockModel, bounds, x, y, z,
-                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,0, meta,
+                useColor = blockModel.shouldSideBeColored(worldSource, x, y, z, side, meta);
+                return renderSide(tessellator, worldSource, blockModel, bounds, x, y, z,
+                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,side, meta,
                         0, -1, 0, (float)bounds.minY,
                         0, 0, 1, (float)bounds.maxZ, (float)bounds.minZ,
                         -1, 0, 0, 1-(float)bounds.minX, 1-(float)bounds.maxX);
             case TOP:
-                useColor = blockModel.shouldSideBeColored(blockAccess, x, y, z, 1, meta);
-                return renderSide(tessellator, blockModel, bounds, x, y, z,
-                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,1, meta,
+                useColor = blockModel.shouldSideBeColored(worldSource, x, y, z, side, meta);
+                return renderSide(tessellator, worldSource, blockModel, bounds, x, y, z,
+                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,side, meta,
                         0,1,0, 1-(float)bounds.maxY,
                         0,0,1, (float)bounds.maxZ, (float)bounds.minZ,
                         1,0,0, (float)bounds.maxX, (float)bounds.minX);
             case NORTH:
-                useColor = blockModel.shouldSideBeColored(blockAccess, x, y, z, 2, meta);
-                return renderSide(tessellator, blockModel, bounds, x, y, z,
-                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,2, meta,
+                useColor = blockModel.shouldSideBeColored(worldSource, x, y, z, side, meta);
+                return renderSide(tessellator, worldSource, blockModel, bounds, x, y, z,
+                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,side, meta,
                         0,0,-1, (float)bounds.minZ,
                         -1,0,0, 1-(float)bounds.minX, 1-(float)bounds.maxX,
                         0,1,0, (float)bounds.maxY, (float)bounds.minY);
             case SOUTH:
-                useColor = blockModel.shouldSideBeColored(blockAccess, x, y, z, 3, meta);
-                return renderSide(tessellator, blockModel, bounds, x, y, z,
-                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,3, meta,
+                useColor = blockModel.shouldSideBeColored(worldSource, x, y, z, side, meta);
+                return renderSide(tessellator, worldSource, blockModel, bounds, x, y, z,
+                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,side, meta,
                         0,0,1, 1-(float)bounds.maxZ,
                         0,1,0, (float)bounds.maxY, (float)bounds.minY,
                         -1,0,0, 1-(float)bounds.minX, 1-(float)bounds.maxX);
             case WEST:
-                useColor = blockModel.shouldSideBeColored(blockAccess, x, y, z, 4, meta);
-                return renderSide(tessellator, blockModel, bounds, x, y, z,
-                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,4, meta,
+                useColor = blockModel.shouldSideBeColored(worldSource, x, y, z, side, meta);
+                return renderSide(tessellator, worldSource, blockModel, bounds, x, y, z,
+                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,side, meta,
                         -1,0,0, (float)bounds.minX,
                         0,0,1, (float)bounds.maxZ, (float)bounds.minZ,
                         0,1,0, (float)bounds.maxY, (float)bounds.minY);
             case EAST:
-                useColor = blockModel.shouldSideBeColored(blockAccess, x, y, z, 5, meta);
-                return renderSide(tessellator, blockModel, bounds, x, y, z,
-                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,5, meta,
+                useColor = blockModel.shouldSideBeColored(worldSource, x, y, z, side, meta);
+                return renderSide(tessellator, worldSource, blockModel, bounds, x, y, z,
+                        useColor ? r : 1, useColor ? g : 1, useColor ? b : 1,side, meta,
                         1,0,0, 1-(float)bounds.maxX,
                         0,0,1, (float)bounds.maxZ, (float)bounds.minZ,
                         0,-1,0, 1-(float)bounds.minY, 1-(float)bounds.maxY);
@@ -228,48 +184,55 @@ public class RenderBlocks
      * @author CyborgCabbage
      * Thanks! :D
      */
-    public final boolean renderSide(Tessellator tessellator, BlockModel<?> blockModel, AABB bounds, int x, int y, int z, float r, float g, float b, int side, int meta,
-                                    int dirX, int dirY, int dirZ, float depth,
-                                    int topX, int topY, int topZ, float topP, float botP,
-                                    int lefX, int lefY, int lefZ, float lefP, float rigP
+    public boolean renderSide(Tessellator tessellator, WorldSource worldSource, BlockModelStandard<?> blockModel, AABB bounds, int x, int y, int z, float r, float g, float b, @NotNull Side side, int meta,
+                              int dirX, int dirY, int dirZ, float depth,
+                              int topX, int topY, int topZ, float topP, float botP,
+                              int lefX, int lefY, int lefZ, float lefP, float rigP
     ){
         IconCoordinate tex;
         if (this.overbright) {
-            tex = blockModel.getBlockOverbrightTexture(this.blockAccess, x, y, z, side);
+            tex = blockModel.getBlockOverbrightTexture(worldSource, x, y, z, side);
         } else {
-            tex = blockModel.getBlockTexture(this.blockAccess, x, y, z, Side.getSideById(side));
+            tex = blockModel.getBlockTexture(worldSource, x, y, z, side);
         }
-        if (tex == null || ((renderBitMask >> side) & 1) != 0) return false;
+        if (tex == null || ((renderBitMask >> side.getId()) & 1) != 0) return false;
 
         boolean rendered = false;
-        if (this.renderAllFaces || blockModel.shouldSideBeRendered(this.blockAccess, bounds, x+dirX, y+dirY, z+dirZ, side, meta)) {
+        if (this.renderAllFaces || blockModel.shouldSideBeRendered(worldSource, bounds, x+dirX, y+dirY, z+dirZ, side, meta)) {
         	
-            setupLighting(blockModel.block, x, y, z, r, g, b, side, meta,
-                    dirX, dirY, dirZ, depth,
+            setupLighting(blockModel.block, worldSource, x, y, z, r, g, b, side,
+                dirX, dirY, dirZ, depth,
                     topX, topY, topZ, topP, botP,
                     lefX, lefY, lefZ, lefP, rigP);
 
-            if (side == 0) {
-                this.renderBottomFace(tessellator, bounds, x, y, z, tex);
-            } else if (side == 1) {
-                this.renderTopFace(tessellator, bounds, x, y, z, tex);
-            } else if (side == 2) {
-                this.renderNorthFace(tessellator, bounds, x, y, z, tex);
-            } else if (side == 3) {
-                this.renderSouthFace(tessellator, bounds, x, y, z, tex);
-            } else if (side == 4) {
-                this.renderWestFace(tessellator, bounds, x, y, z, tex);
-            } else if (side == 5) {
-                this.renderEastFace(tessellator, bounds, x, y, z, tex);
+            switch (side) {
+                case BOTTOM:
+                    this.renderBottomFace(tessellator, bounds, x, y, z, tex);
+                    break;
+                case TOP:
+                    this.renderTopFace(tessellator, bounds, x, y, z, tex);
+                    break;
+                case NORTH:
+                    this.renderNorthFace(tessellator, bounds, x, y, z, tex);
+                    break;
+                case SOUTH:
+                    this.renderSouthFace(tessellator, bounds, x, y, z, tex);
+                    break;
+                case WEST:
+                    this.renderWestFace(tessellator, bounds, x, y, z, tex);
+                    break;
+                case EAST:
+                    this.renderEastFace(tessellator, bounds, x, y, z, tex);
+                    break;
             }
             rendered = true;
         }
         return rendered;
     }
-    public final void setupLighting(Block<?> block, int x, int y, int z, float r, float g, float b, int side, int meta,
-                                    int dirX, int dirY, int dirZ, float depth,
-                                    int topX, int topY, int topZ, float topP, float botP,
-                                    int lefX, int lefY, int lefZ, float lefP, float rigP){
+    public void setupLighting(Block<?> block, WorldSource worldSource, int x, int y, int z, float r, float g, float b, @NotNull Side side,
+                              int dirX, int dirY, int dirZ, float depth,
+                              int topX, int topY, int topZ, float topP, float botP,
+                              int lefX, int lefY, int lefZ, float lefP, float rigP){
     	boolean ao = mc.isAmbientOcclusionEnabled() && block.emission == 0;
         boolean isFullCube = depth <= FULL_CUBE_THRESHOLD;
 
@@ -285,7 +248,7 @@ public class RenderBlocks
     				dirZ2 = 0;
     			}
     			
-    			int lmc = LightmapHelper.getOverbrightLightmapCoord(blockAccess.getSavedLightValue(LightLayer.Sky, dirX2, dirY2, dirZ2));
+    			int lmc = LightmapHelper.getOverbrightLightmapCoord(worldSource.getSavedLightValue(LightLayer.Sky, dirX2, dirY2, dirZ2));
     			
         		lightmapCoordTopLeft = lightmapCoordBottomLeft = lightmapCoordBottomRight = lightmapCoordTopRight = lmc;
     		}else {
@@ -329,9 +292,9 @@ public class RenderBlocks
         		}else {
         			int lmc;
                 	if(!isFullCube) {
-                		lmc = block.getLightmapCoord(blockAccess, x, y, z);
+                		lmc = block.getLightmapCoord(worldSource, x, y, z);
                 	}else {
-                		lmc = block.getLightmapCoord(blockAccess, x + dirX, y + dirY, z + dirZ);
+                		lmc = block.getLightmapCoord(worldSource, x + dirX, y + dirY, z + dirZ);
                 	}
             		lightmapCoordTopLeft = lightmapCoordBottomLeft = lightmapCoordBottomRight = lightmapCoordTopRight = lmc;
         		}
@@ -348,8 +311,6 @@ public class RenderBlocks
             lightBR = 1.0F;
             lightBL = 1.0F;
             lightTL = 1.0F;
-        } else if (this.field_22352_G <= 0) {
-            lightTL = lightBL = lightBR = lightTR = cache.getBrightness(dirX, dirY, dirZ);
         } else {
             if (ao) {
                 {
@@ -406,7 +367,7 @@ public class RenderBlocks
             }
         }
 
-        if (overbright || !enableDirectionalLight)
+        if (overbright || !BlockModel.ENABLE_DIRECTIONAL_LIGHTING)
         {
             this.colorRedTopLeft = this.colorRedBottomLeft = this.colorRedBottomRight = this.colorRedTopRight = r;
             this.colorGreenTopLeft = this.colorGreenBottomLeft = this.colorGreenBottomRight = this.colorGreenTopRight = g;
@@ -414,9 +375,9 @@ public class RenderBlocks
         }
         else
         {
-            this.colorRedTopLeft = this.colorRedBottomLeft = this.colorRedBottomRight = this.colorRedTopRight = r * SIDE_LIGHT_MULTIPLIER[side];
-            this.colorGreenTopLeft = this.colorGreenBottomLeft = this.colorGreenBottomRight = this.colorGreenTopRight = g * SIDE_LIGHT_MULTIPLIER[side];
-            this.colorBlueTopLeft = this.colorBlueBottomLeft = this.colorBlueBottomRight = this.colorBlueTopRight = b * SIDE_LIGHT_MULTIPLIER[side];
+            this.colorRedTopLeft = this.colorRedBottomLeft = this.colorRedBottomRight = this.colorRedTopRight = r * SIDE_LIGHT_MULTIPLIER[side.getId()];
+            this.colorGreenTopLeft = this.colorGreenBottomLeft = this.colorGreenBottomRight = this.colorGreenTopRight = g * SIDE_LIGHT_MULTIPLIER[side.getId()];
+            this.colorBlueTopLeft = this.colorBlueBottomLeft = this.colorBlueBottomRight = this.colorBlueTopRight = b * SIDE_LIGHT_MULTIPLIER[side.getId()];
         }
         float tl = topP * lightTL + (1 - topP) * lightBL;
         float tr = topP * lightTR + (1 - topP) * lightBR;
@@ -989,67 +950,4 @@ public class RenderBlocks
             tessellator.addVertexWithUV(xMax, yMax, zMax, uMin, vMin);
         }
     }
-
-    public void renderBlockAsItem(Tessellator tessellator, BlockModel<?> blockModel, float var2)
-    {
-        AABB bounds = blockModel.getBlockBoundsForItemRender();
-        GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
-        float var5 = 0.5F;
-        float var6 = 1.0F;
-        float var7 = 0.8F;
-        float var8 = 0.6F;
-        tessellator.startDrawingQuads();
-        tessellator.setColorRGBA_F(var6, var6, var6, var2);
-        this.renderBottomFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, blockModel.getBlockTextureFromSideAndMetadata(Side.BOTTOM, 0));
-        tessellator.setColorRGBA_F(var5, var5, var5, var2);
-        this.renderTopFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, blockModel.getBlockTextureFromSideAndMetadata(Side.TOP, 0));
-        tessellator.setColorRGBA_F(var7, var7, var7, var2);
-        this.renderNorthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, blockModel.getBlockTextureFromSideAndMetadata(Side.NORTH, 0));
-        this.renderSouthFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, blockModel.getBlockTextureFromSideAndMetadata(Side.SOUTH, 0));
-        tessellator.setColorRGBA_F(var8, var8, var8, var2);
-        this.renderWestFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, blockModel.getBlockTextureFromSideAndMetadata(Side.WEST, 0));
-        this.renderEastFace(tessellator, bounds, 0.0D, 0.0D, 0.0D, blockModel.getBlockTextureFromSideAndMetadata(Side.EAST, 0));
-        tessellator.draw();
-        GL11.glTranslatef(0.5F, 0.5F, 0.5F);
-    }
-    public WorldSource blockAccess;
-    private final Minecraft mc;
-    public IconCoordinate overrideBlockTexture;
-    public boolean flipTexture;
-    public boolean renderAllFaces;
-    public byte renderBitMask;
-    public static boolean fancyGrass = true;
-
-    public static final float[] SIDE_LIGHT_MULTIPLIER = {0.5f, 1.0f, 0.8f, 0.8f, 0.6f, 0.6f};
-    public static final float FULL_CUBE_THRESHOLD = 1.0f / 16.0f;
-    public static boolean enableDirectionalLight = true;
-    public boolean useInventoryTint;
-    public int uvRotateEast;
-    public int uvRotateWest;
-    public int uvRotateSouth;
-    public int uvRotateNorth;
-    public int uvRotateTop;
-    public int uvRotateBottom;
-    public boolean enableAO;
-    public int field_22352_G;
-    public float colorRedTopLeft;
-    public float colorRedBottomLeft;
-    public float colorRedBottomRight;
-    public float colorRedTopRight;
-    public float colorGreenTopLeft;
-    public float colorGreenBottomLeft;
-    public float colorGreenBottomRight;
-    public float colorGreenTopRight;
-    public float colorBlueTopLeft;
-    public float colorBlueBottomLeft;
-    public float colorBlueBottomRight;
-    public float colorBlueTopRight;
-    public int lightmapCoordTopLeft;
-    public int lightmapCoordBottomLeft;
-    public int lightmapCoordBottomRight;
-    public int lightmapCoordTopRight; 
-    public boolean overbright;
-    public boolean forceAO;
-    public RenderBlockCache cache = new RenderBlockCache();
-
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererBoat.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererBoat.java
index a6aa5e9ba..d53a766c6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererBoat.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererBoat.java
@@ -1,12 +1,12 @@
 package net.minecraft.client.render.entity;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.model.ModelBase;
 import net.minecraft.client.render.model.ModelBoat;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.client.render.blockentity.TileEntityRendererFlag;
+import net.minecraft.client.render.tileentity.TileEntityRendererFlag;
 import net.minecraft.core.entity.vehicle.EntityBoat;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
@@ -22,7 +22,7 @@ public class EntityRendererBoat extends EntityRenderer<EntityBoat>
     {
         shadowSize = 0.5F;
         modelBoat = new ModelBoat();
-        flagRenderer.setRenderDispatcher(BlockEntityRenderDispatcher.instance);
+        flagRenderer.setRenderDispatcher(TileEntityRenderDispatcher.instance);
     }
 
     @Override
@@ -63,7 +63,7 @@ public class EntityRendererBoat extends EntityRenderer<EntityBoat>
         GL11.glScalef(1.0F / f4, 1.0F / f4, 1.0F / f4);
         bindTexture("/assets/minecraft/textures/entity/boat.png");
         GL11.glScalef(-1F, -1F, 1.0F);
-        modelBoat.render(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F);
+        modelBoat.render(null, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, partialTick);
         GL11.glPopMatrix();
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererCannonball.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererCannonball.java
index a4280e414..b10c0a198 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererCannonball.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererCannonball.java
@@ -9,29 +9,23 @@ import org.lwjgl.opengl.GL11;
 public class EntityRendererCannonball extends EntityRenderer<ProjectileCannonball>
 {
 
+    protected ModelBase modelCannonball;
+
     public EntityRendererCannonball()
     {
         modelCannonball = new ModelCannonball();
     }
 
-    public void RenderCannonball(ProjectileCannonball entity, double d, double d1, double d2,
-                                 float f)
+    @Override
+    public void render(Tessellator tessellator, ProjectileCannonball entity, double x, double y, double z,
+                       float yaw, float partialTick)
     {
         GL11.glPushMatrix();
-        GL11.glTranslatef((float)d, (float)d1, (float)d2);
-        GL11.glRotatef(180F - f, 0.0F, 1.0F, 0.0F);
+        GL11.glTranslatef((float)x, (float)y, (float)z);
+        GL11.glRotatef(180F - yaw, 0.0F, 1.0F, 0.0F);
         bindTexture("/assets/minecraft/textures/entity/cannonball.png");
         GL11.glScalef(-1F, -1F, 1.0F);
-        modelCannonball.render(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.03125F);
+        modelCannonball.render(null, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.03125F, partialTick);
         GL11.glPopMatrix();
     }
-
-    @Override
-    public void render(Tessellator tessellator, ProjectileCannonball entity, double x, double y, double z,
-                       float yaw, float partialTick)
-    {
-        RenderCannonball(entity, x, y, z, yaw);
-    }
-
-    protected ModelBase modelCannonball;
 }
\ No newline at end of file
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 589409b52..dac540d6e 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
@@ -1,12 +1,10 @@
 package net.minecraft.client.render.entity;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.RenderBlocks;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
-import net.minecraft.client.render.blockentity.TileEntityRenderer;
+import net.minecraft.client.render.tileentity.TileEntityRenderer;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Blocks;
@@ -20,7 +18,6 @@ public class EntityRendererFallingBlock extends EntityRenderer<EntityFallingBloc
 {
     private final Minecraft mc;
     private BlocksContainer container = null;
-    private RenderBlocks containerRenderBlock = null;
 
 
     public EntityRendererFallingBlock()
@@ -33,7 +30,6 @@ public class EntityRendererFallingBlock extends EntityRenderer<EntityFallingBloc
     public void render(Tessellator tessellator, EntityFallingBlock fallingBlock, double x, double y, double z, float yaw, float partialTick) {
         if (container == null || container.world != fallingBlock.world) {
             container = new BlocksContainer(fallingBlock.world);
-            containerRenderBlock = new RenderBlocks(container);
         }
         GL11.glPushMatrix();
         GL11.glTranslated(x, y, z);
@@ -56,11 +52,10 @@ public class EntityRendererFallingBlock extends EntityRenderer<EntityFallingBloc
 
         tessellator.startDrawingQuads();
         tessellator.setTranslation(-blockX - 0.5, -blockY - 0.5, -blockZ - 0.5);
-        BlockModel.setRenderBlocks(containerRenderBlock);
 
         container.setLightReferenceEntity(fallingBlock);
         container.setBlock(blockX, blockY, blockZ, fallingBlock.carriedBlock.blockId, fallingBlock.carriedBlock.metadata, fallingBlock.carriedBlock.entity);
-        BlockModelDispatcher.getInstance().getDispatch(Blocks.getBlock(fallingBlock.carriedBlock.blockId)).renderNoCulling(Tessellator.instance, blockX, blockY, blockZ);
+        BlockModelDispatcher.getInstance().getDispatch(Blocks.getBlock(fallingBlock.carriedBlock.blockId)).renderNoCulling(Tessellator.instance, container, blockX, blockY, blockZ);
         container.setLightReferenceEntity(null);
         container.clear();
 
@@ -70,7 +65,7 @@ public class EntityRendererFallingBlock extends EntityRenderer<EntityFallingBloc
         Lighting.enableLight();
         GL11.glPopMatrix();
 
-        TileEntityRenderer<TileEntity> renderer = BlockEntityRenderDispatcher.instance.getRenderer(fallingBlock.carriedBlock.entity);
+        TileEntityRenderer<TileEntity> renderer = TileEntityRenderDispatcher.instance.getRenderer(fallingBlock.carriedBlock.entity);
         if (renderer != null) {
             GL11.glPushMatrix();
             renderer.doRender(tessellator, fallingBlock.carriedBlock.entity, x - 0.5, y - 0.5, z - 0.5, partialTick);
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 c1e070110..98eb6efcc 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
@@ -1,53 +1,34 @@
 package net.minecraft.client.render.entity;
 
-import java.util.Random;
-
-import net.minecraft.client.render.block.color.BlockColorDispatcher;
+import net.minecraft.client.Minecraft;
 import net.minecraft.core.entity.EntityItem;
-import net.minecraft.core.item.block.ItemBlock;
 import org.lwjgl.opengl.GL11;
 
-import net.minecraft.core.block.Block;
 import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.RenderBlocks;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.opengl.GL12;
+import org.useless.dragonfly.DisplayPos;
 
 import static org.lwjgl.opengl.GL11.glPushMatrix;
 
 public class EntityRendererItem extends EntityRenderer<EntityItem>
 {
-	public final RenderBlocks renderBlocks;
-	private final Random random;
-	public boolean useColor;
+
 
 	public EntityRendererItem() {
-		renderBlocks = new RenderBlocks();
-		random = new Random();
-		useColor = true;
 		shadowSize = 0.15F;
 		shadowOpacity = 0.75F;
 	}
 
-	public int getItemColorFromMetadata(Item item, int metadata) {
-		if (item instanceof ItemBlock) {
-			Block<?> block = ((ItemBlock<?>)item).getBlock();
-			return BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(metadata);
-		}
-		return 0xFFFFFF;
-	}
-
 	public void render(Tessellator tessellator, final EntityItem entity, final double x, final double y, final double z, final float yaw, final float partialTick) {
 		float brightness = 1.0f;
 		if(!LightmapHelper.isLightmapEnabled()) {
 			brightness = entity.getBrightness(partialTick);
 		}
-		random.setSeed(187L);
 		final ItemStack itemstack = entity.item;
 		if(itemstack == null) {
 			return;
@@ -58,7 +39,7 @@ public class EntityRendererItem extends EntityRenderer<EntityItem>
 		}
 		glPushMatrix();
 		final float bobbingOffset = MathHelper.sin((entity.age + partialTick) / 10F + entity.bobOffset) * 0.1F + 0.1F;
-		final float f3 = (float) Math.toDegrees(((entity.age + partialTick) / 20F + entity.bobOffset));
+		final float yw = (float) Math.toDegrees(((entity.age + partialTick) / 20F + entity.bobOffset));
 		byte renderCount = 1;
 		if (entity.item.stackSize > 1) {
 			renderCount = 2;
@@ -69,13 +50,8 @@ public class EntityRendererItem extends EntityRenderer<EntityItem>
 		if (entity.item.stackSize > 20) {
 			renderCount = 4;
 		}
-		GL11.glTranslatef((float) x, (float) y + bobbingOffset, (float) z);
-		GL11.glEnable(GL12.GL_RESCALE_NORMAL);
-		GL11.glEnable(GL11.GL_BLEND);
-		BlockModel.setRenderBlocks(renderBlocks);
-		ItemModelDispatcher.getInstance().getDispatch(item).renderAsItemEntity(Tessellator.instance, entity, random, itemstack, renderCount, f3, brightness, partialTick);
-		GL11.glDisable(GL11.GL_BLEND);
-		GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+		GL11.glTranslated(x, y + bobbingOffset, z);
+		ItemModelDispatcher.getInstance().getDispatch(item).renderItemEntity(tessellator, itemstack, Minecraft.getMinecraft().gameSettings.items3D.value, renderCount, entity.age, yw, brightness, 1f, partialTick);
 		GL11.glPopMatrix();
 	}
 }
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 91b94b718..a937cccf0 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
@@ -9,19 +9,19 @@ import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.Global;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.Vec3;
 import org.lwjgl.opengl.GL11;
 
-public class EntityRendererMinecart extends EntityRenderer<MinecartEntity> {
+public class EntityRendererMinecart extends EntityRenderer<EntityMinecart> {
     public EntityRendererMinecart() {
         shadowSize = 0.5F;
         modelMinecart = new ModelMinecart();
     }
 
     @Override
-    public void render(Tessellator tessellator, MinecartEntity minecart, final double x, final double y, final double z, final float yaw, final float partialTick) {
+    public void render(Tessellator tessellator, EntityMinecart minecart, final double x, final double y, final double z, final float yaw, final float partialTick) {
         GL11.glPushMatrix();
         
         double lerpX = MathHelper.lerp(minecart.xo, minecart.x, partialTick);
@@ -78,7 +78,7 @@ public class EntityRendererMinecart extends EntityRenderer<MinecartEntity> {
             GL11.glRotated(((Math.sin(hurtAngle) * hurtAngle * currentDamage) / 10F) * (float)minecart.hurtDirection, 1.0F, 0.0F, 0.0F);
         }
         // Render block in cart
-        if(minecart.type != MinecartEntity.PASSENGER_CART) {
+        if(minecart.getType() != EntityMinecart.PASSENGER_CART) {
             TextureRegistry.blockAtlas.bind();
             final float scale = 0.75F;
             GL11.glScalef(scale, scale, scale);
@@ -95,21 +95,21 @@ public class EntityRendererMinecart extends EntityRenderer<MinecartEntity> {
             if (doAFlip){
                 GL11.glRotatef(180, 0, 1, 0);
             }
-            switch (minecart.type){
-                case MinecartEntity.CHEST_CART:
+            switch (minecart.getType()){
+                case EntityMinecart.CHEST_CART:
                     Block<?> block;
-                    if ((minecart.typeMeta & 0b0000_0001) != 0) {
+                    if ((minecart.getMeta() & 0b0000_0001) != 0) {
                         block = Blocks.CHEST_PLANKS_OAK_PAINTED;
                     } else {
                         block = Blocks.CHEST_PLANKS_OAK;
                     }
-                    BlockModelDispatcher.getInstance().getDispatch(block).renderBlockOnInventory(tessellator, minecart.typeMeta, brightness, null);
+                    BlockModelDispatcher.getInstance().getDispatch(block).renderStandalone(tessellator, minecart.getMeta(), brightness, 1, null);
                     break;
-                case MinecartEntity.FURNACE_CART:
-                    if (minecart.fuel > 0) {
-                        BlockModelDispatcher.getInstance().getDispatch(Blocks.FURNACE_STONE_ACTIVE).renderBlockOnInventory(tessellator, 0, brightness, null);
+                case EntityMinecart.FURNACE_CART:
+                    if (minecart.getFuel() > 0) {
+                        BlockModelDispatcher.getInstance().getDispatch(Blocks.FURNACE_STONE_ACTIVE).renderStandalone(tessellator, 0, brightness, 1, null);
                     } else {
-                        BlockModelDispatcher.getInstance().getDispatch(Blocks.FURNACE_STONE_IDLE).renderBlockOnInventory(tessellator, 0, brightness, null);
+                        BlockModelDispatcher.getInstance().getDispatch(Blocks.FURNACE_STONE_IDLE).renderStandalone(tessellator, 0, brightness, 1, null);
                     }
                     break;
             }
@@ -120,7 +120,7 @@ public class EntityRendererMinecart extends EntityRenderer<MinecartEntity> {
         }
         bindTexture("/assets/minecraft/textures/entity/cart.png");
         GL11.glScalef(-1F, -1F, 1.0F);
-        modelMinecart.render(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F);
+        modelMinecart.render(null, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, partialTick);
         GL11.glPopMatrix();
     }
 
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 05c78e1eb..22606bde2 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
@@ -1,6 +1,5 @@
 package net.minecraft.client.render.entity;
 
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
@@ -12,11 +11,8 @@ import org.lwjgl.opengl.GL11;
 
 public class EntityRendererTNT extends EntityRenderer<EntityPrimedTNT>
 {
-    private final RenderBlocks blockRenderer;
-
     public EntityRendererTNT()
     {
-        blockRenderer = new RenderBlocks();
         shadowSize = 0.5F;
     }
 
@@ -45,9 +41,8 @@ public class EntityRendererTNT extends EntityRenderer<EntityPrimedTNT>
         TextureRegistry.blockAtlas.bind();
         float brightness = tnt.getBrightness(partialTick);
         if (Global.accessor.isFullbrightEnabled()) brightness = 1.0f;
-        BlockModel.setRenderBlocks(blockRenderer);
         BlockModel<?> model = BlockModelDispatcher.getInstance().getDispatch(Blocks.TNT);
-        model.renderBlockOnInventory(tessellator, 0, brightness, null);
+        model.renderStandalone(tessellator, 0, brightness, 1, null);
         if((tnt.fuse / 5) % 2 == 0)
         {
             GL11.glDisable(GL11.GL_TEXTURE_2D);
@@ -55,7 +50,7 @@ public class EntityRendererTNT extends EntityRenderer<EntityPrimedTNT>
             GL11.glEnable(GL11.GL_BLEND);
             GL11.glBlendFunc(770, 772);
             GL11.glColor4f(1.0F, 1.0F, 1.0F, f3);
-            model.renderBlockOnInventory(tessellator, 0, 1.0F, null);
+            model.renderStandalone(tessellator, 0, 1.0F, 1, null);
             GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
             GL11.glDisable(GL11.GL_BLEND);
             GL11.glEnable(GL11.GL_LIGHTING);
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java
index 15553c76d..771a96bfe 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java
@@ -46,9 +46,9 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
     {
         GL11.glPushMatrix();
         GL11.glDisable(GL11.GL_CULL_FACE);
-        mainModel.onGround = getSwingProgress(entity, partialTick);
-        if (armorModel != null) armorModel.onGround = mainModel.onGround;
-        if (overlayModel != null) overlayModel.onGround = mainModel.onGround;
+        mainModel.swingProgress = getSwingProgress(entity, partialTick);
+        if (armorModel != null) armorModel.swingProgress = mainModel.swingProgress;
+        if (overlayModel != null) overlayModel.swingProgress = mainModel.swingProgress;
         mainModel.isRiding = entity.isPassenger();
         if (armorModel != null) armorModel.isRiding = mainModel.isRiding;
         if (overlayModel != null) overlayModel.isRiding = mainModel.isRiding;
@@ -61,7 +61,7 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
             float limbSway = limbSway(entity, partialTick);
             setupRotations(entity, limbSway, bodyYaw, partialTick);
             float scale = 0.0625F;
-            GL11.glEnable(GL12.GL_RESCALE_NORMAL);
+            GL12.glEnable(GL12.GL_RESCALE_NORMAL);
             GL11.glScalef(-1F, -1F, 1.0F);
             setupScale(entity, partialTick);
             GL11.glTranslatef(0.0F, -24F * scale - 0.0078125F, 0.0F);
@@ -73,21 +73,17 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
             }
             loadEntityTexture(entity);
             GL11.glEnable(GL11.GL_ALPHA_TEST);
-            mainModel.setLivingAnimations(entity, walkProgress, walkSpeed, partialTick);
-            mainModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
+            mainModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
             if (overlayModel != null)
             {
-                overlayModel.setLivingAnimations(entity, walkProgress, walkSpeed, partialTick);
                 bindTexture(overlayTexture);
-                overlayModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
+                overlayModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
             }
-            if (armorModel != null) armorModel.setLivingAnimations(entity, walkProgress, walkSpeed, partialTick);
             for(int renderPass = 0; renderPass < MAX_ARMOR_LAYERS; renderPass++)
             {
                 if(prepareArmor(entity, renderPass, partialTick))
                 {
-                    armorModel.setLivingAnimations(entity, walkProgress, walkSpeed, partialTick);
-                    armorModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
+                    armorModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
                     GL11.glDisable(GL11.GL_BLEND);
                     GL11.glEnable(GL11.GL_ALPHA_TEST);
                 }
@@ -107,14 +103,14 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
                 if(entity.hurtTime > 0 || entity.deathTime > 0)
                 {
                     GL11.glColor4f(brightness, 0.0F, 0.0F, 0.4F);
-                    mainModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
-                    if (overlayModel != null) overlayModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
+                    mainModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
+                    if (overlayModel != null) overlayModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
                     for(int k = 0; k < MAX_ARMOR_LAYERS; k++)
                     {
                         if(prepareArmor(entity, k, partialTick))
                         {
                             GL11.glColor4f(brightness, 0.0F, 0.0F, 0.4F);
-                            armorModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
+                            armorModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
                         }
                     }
 
@@ -126,14 +122,14 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
                     float b = (float)(argb & 0xff) / 255F;
                     float a = (float)(argb >> 24 & 0xff) / 255F;
                     GL11.glColor4f(r, g, b, a);
-                    mainModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
-                    if (overlayModel != null) overlayModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
+                    mainModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
+                    if (overlayModel != null) overlayModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
                     for(int l = 0; l < MAX_ARMOR_LAYERS; l++)
                     {
                         if(prepareArmor(entity, l, partialTick))
                         {
                             GL11.glColor4f(r, g, b, a);
-                            armorModel.render(walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale);
+                            armorModel.render(entity, walkProgress, walkSpeed, limbSway, headYaw - bodyYaw, headPitch, scale, partialTick);
                         }
                     }
 
@@ -184,7 +180,7 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
         return (float)entity.tickCount + partialTick;
     }
 
-    protected void renderAdditional(T entity, float f)
+    protected void renderAdditional(T entity, float partialTick)
     {
     }
 
@@ -207,19 +203,19 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
     {
     }
 
-    protected void renderSpecials(Tessellator tessellator, T entity, double d, double d1, double d2)
+    protected void renderSpecials(Tessellator tessellator, T entity, double x, double y, double z)
     {
         if(mc.canRenderEntityLabel())
         {
-            renderLivingLabel(tessellator, entity, Integer.toString(entity.id), d, d1, d2, 64, false);
+            renderLivingLabel(tessellator, entity, Integer.toString(entity.id), x, y, z, 64, false);
         }
         else if (!entity.nickname.isEmpty())
         {
-            renderLivingLabel(tessellator, entity, entity.getDisplayName(), d, d1, d2, 64, true);
+            renderLivingLabel(tessellator, entity, entity.getDisplayName(), x, y, z, 64, true);
         }
     }
 
-    protected void renderLivingLabel(Tessellator tessellator, T entity, String s, double d, double d1, double d2, int maxDistance, boolean depthTest)
+    protected void renderLivingLabel(Tessellator tessellator, T entity, String s, double x, double y, double z, int maxDistance, boolean depthTest)
     {
         final float f = (float) renderDispatcher.camera.distanceTo(entity);
         if (f > maxDistance)
@@ -230,7 +226,7 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
         final float f1 = 1.6F;
         final float f2 = 0.01666667F * f1;
         GL11.glPushMatrix();
-        GL11.glTranslatef((float) d + 0.0F, (float) d1 + entity.getHeadHeight() + 0.8f, (float) d2);
+        GL11.glTranslatef((float) x + 0.0F, (float) y + entity.getHeadHeight() + 0.8f, (float) z);
         GL11.glNormal3f(0.0F, 1.0F, 0.0F);
         GL11.glRotatef(-renderDispatcher.viewLerpYaw, 0.0F, 1.0F, 0.0F);
         GL11.glRotatef(renderDispatcher.viewLerpPitch, 1.0F, 0.0F, 0.0F);
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 d2be306e3..b7a882126 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
@@ -4,10 +4,12 @@ import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.model.ModelBiped;
 import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.entity.IItemHolding;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.monster.MobZombieArmored;
 import net.minecraft.core.item.ItemStack;
 import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
 
 public class MobRendererBiped<T extends Mob> extends MobRenderer<T>
 {
@@ -22,14 +24,30 @@ public class MobRendererBiped<T extends Mob> extends MobRenderer<T>
 	}
 
 	@Override
-	protected void renderAdditional(T entity, float f) {
-		ItemStack itemstack = entity.getHeldItem();
-		if(itemstack != null) {
-			GL11.glPushMatrix();
-			this.modelBipedMain.armRight.translateTo(0.0625F);
-			BlockModel.setRenderBlocks(this.renderDispatcher.itemRenderer.renderBlocksInstance);
-			ItemModelDispatcher.getInstance().getDispatch(itemstack.getItem()).renderItemThirdPerson(Tessellator.instance, renderDispatcher.itemRenderer, entity, itemstack, true);
-			GL11.glPopMatrix();
+	protected void renderAdditional(T entity, float partialTick) {
+		if (entity instanceof IItemHolding) {
+			IItemHolding itemHolder = (IItemHolding) entity;
+			ItemStack itemstack = itemHolder.getHeldItem();
+			if(itemstack != null) {
+				GL11.glPushMatrix();
+				if (((IItemHolding) entity).isLeftHanded()) {
+					modelBipedMain.armLeft.translateTo(0.0625F);
+					GL11.glRotatef(-90, 1, 0, 0);
+					GL11.glRotatef(180, 0, 1, 0);
+					GL11.glScalef(-1, 1, 1);
+					GL11.glTranslatef(1/16f, 2/16f, -10f/16f);
+					ItemModelDispatcher.getInstance().getDispatch(itemstack)
+						.render(Tessellator.instance, entity, itemstack, DisplayPos.THIRD_PERSON_LEFT_HAND, true, 1, entity.getBrightness(partialTick), 1f, partialTick, true);
+				} else {
+					modelBipedMain.armRight.translateTo(0.0625F);
+					GL11.glRotatef(-90, 1, 0, 0);
+					GL11.glScalef(-1, 1, -1);
+					GL11.glTranslatef(1/16f, 2/16f, -10f/16f);
+					ItemModelDispatcher.getInstance().getDispatch(itemstack)
+						.render(Tessellator.instance, entity, itemstack, DisplayPos.THIRD_PERSON_RIGHT_HAND, true, 1, entity.getBrightness(partialTick), 1f, partialTick, false);
+				}
+				GL11.glPopMatrix();
+			}
 		}
 	}
 }
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 c1fc9e3b2..9132a584c 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,17 +1,20 @@
 package net.minecraft.client.render.entity;
 
 import net.minecraft.client.entity.player.PlayerLocal;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.model.ModelBiped;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.IArmorWearing;
+import net.minecraft.core.entity.IItemHolding;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.item.*;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
 
 public class MobRendererBipedArmored<T extends Mob & IArmorWearing<HumanArmorShape>> extends MobRendererBiped<T> {
     protected ModelBiped modelArmorA;
@@ -29,31 +32,24 @@ public class MobRendererBipedArmored<T extends Mob & IArmorWearing<HumanArmorSha
     }
 
     @Override
-    protected void renderAdditional(T entity, float f) {
+    protected void renderAdditional(T entity, float partialTick) {
         final @Nullable ItemStack stack = entity.getItemInArmorSlot(HumanArmorShape.HEAD);
         if(stack != null) {
             GL11.glPushMatrix();
-            this.modelBipedMain.head.translateTo(0.0625F);
-            if(stack.itemID < Blocks.blocksList.length && BlockModelDispatcher.getInstance().getDispatch(Blocks.getBlock(stack.itemID)).shouldItemRender3d())
-            {
-                float scale = 0.625F;
-                GL11.glTranslatef(0.0F, -0.25F, 0.0F);
-                GL11.glRotatef(180F, 0.0F, 1.0F, 0.0F);
-                GL11.glScalef(scale, -scale, scale);
-                ItemModelDispatcher.getInstance().getDispatch(stack).renderItem(Tessellator.instance, renderDispatcher.itemRenderer, entity, stack);
-            } else if (!(stack.getItem() instanceof IArmorItem)) {
+            modelBipedMain.head.translateTo(0.0625F);
+            if (!(stack.getItem() instanceof IArmorItem)) {
+                GL11.glPushMatrix();
                 GL11.glEnable(GL11.GL_CULL_FACE);
-                float scale = 0.625F;
-                GL11.glTranslatef(0.0F, -0.8F, 0.0F);
-                GL11.glRotatef(180, 0.0F, 0.0F, 1.0F);
-                GL11.glScalef(scale, scale, scale);
-                ItemModelDispatcher.getInstance().getDispatch(stack).renderItemInWorld(Tessellator.instance, entity, stack, entity.getBrightness(f), 1f, true);
+                GL11.glScalef(-0.6f, -0.6f, 0.6f);
+                GL11.glTranslatef(0, 7/16f, 0);
+                ItemModelDispatcher.getInstance().getDispatch(stack).render(Tessellator.instance, null, stack, DisplayPos.HEAD, true, 1, LightmapHelper.isLightmapEnabled() ? 1f : entity.getBrightness(partialTick), 1f, partialTick, true);
                 GL11.glDisable(GL11.GL_CULL_FACE);
+                GL11.glPopMatrix();
             }
             GL11.glPopMatrix();
         }
 
-        super.renderAdditional(entity, f);
+        super.renderAdditional(entity, partialTick);
     }
 
     @Override
@@ -61,9 +57,14 @@ public class MobRendererBipedArmored<T extends Mob & IArmorWearing<HumanArmorSha
         GL11.glEnable(GL11.GL_BLEND);
         GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
 
-        ItemStack itemstack = entity.getHeldItem();
-
-        this.modelArmorA.holdingRightHand = this.modelArmorB.holdingRightHand = this.modelBipedMain.holdingRightHand |= itemstack != null;
+        if (entity instanceof IItemHolding) {
+            ItemStack itemstack = ((IItemHolding) entity).getHeldItem();
+            if (((IItemHolding) entity).isLeftHanded()) {
+                this.modelArmorA.holdingLeftHand = this.modelArmorB.holdingLeftHand = this.modelBipedMain.holdingLeftHand |= itemstack != null;
+            } else {
+                this.modelArmorA.holdingRightHand = this.modelArmorB.holdingRightHand = this.modelBipedMain.holdingRightHand |= itemstack != null;
+            }
+        }
         this.modelArmorA.sneaking = this.modelArmorB.sneaking = this.modelBipedMain.sneaking = entity.isSneaking();
         this.modelArmorA.isRiding = this.modelArmorB.isRiding = this.modelBipedMain.isRiding = entity.isPassenger();
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java
index c838aa0d5..72f55827f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java
@@ -2,15 +2,14 @@ package net.minecraft.client.render.entity;
 
 import net.minecraft.client.Minecraft;
 
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.entity.player.PlayerLocal;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.Font;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.PlayerSkinParser;
-import net.minecraft.client.render.RenderBlocks;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
-import net.minecraft.client.render.blockentity.TileEntityRenderer;
+import net.minecraft.client.render.tileentity.TileEntityRenderer;
 import net.minecraft.client.render.camera.EntityCamera;
 import net.minecraft.client.render.model.ModelPlayer;
 import net.minecraft.client.render.model.ModelPlayerSlim;
@@ -31,7 +30,6 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
     private final ModelPlayer modelSlim;
 
     private BlocksContainer container = null;
-    private RenderBlocks containerRenderBlock = null;
 
     public MobRendererPlayer()
     {
@@ -45,9 +43,9 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
         mainModel = player.slimModel ? modelSlim : modelThick;
         modelBipedMain = player.slimModel ? modelSlim : modelThick;
 
-        modelBipedMain.onGround = 0.0F;
+        modelBipedMain.swingProgress = 0.0F;
         modelBipedMain.isRiding = false;
-        modelBipedMain.setupAnimation(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0625F);
+        modelBipedMain.setupAnimation(player, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0625F, 1f);
         if (isLeft){
             modelBipedMain.armLeft.render(0.0625F);
         } else {
@@ -68,7 +66,6 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
             CarriedBlock carriedBlock = (CarriedBlock)player.getHeldObject();
             if (container == null || container.world != player.world) {
                 container = new BlocksContainer(player.world);
-                containerRenderBlock = new RenderBlocks(container);
             }
 
             Tessellator tessellator = Tessellator.instance;
@@ -92,19 +89,18 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
             int blockY = MathHelper.floor(player.y) + 1;
             int blockZ = MathHelper.floor(player.z);
 
-            BlockModel.setRenderBlocks(containerRenderBlock);
             tessellator.startDrawingQuads();
             tessellator.setTranslation(-blockX -0.5, -blockY -0.5, -blockZ -0.5);
 
             container.setLightReferenceEntity(player);
             container.setBlock(blockX, blockY, blockZ, carriedBlock.blockId, carriedBlock.metadata, carriedBlock.entity);
-            BlockModelDispatcher.getInstance().getDispatch(carriedBlock.block()).renderNoCulling(Tessellator.instance, blockX, blockY, blockZ);
+            BlockModelDispatcher.getInstance().getDispatch(carriedBlock.block()).renderNoCulling(Tessellator.instance, container, blockX, blockY, blockZ);
             tessellator.draw();
             tessellator.setTranslation(0, 0, 0);
             container.setLightReferenceEntity(null);
             container.clear();
 
-            TileEntityRenderer<TileEntity> renderer = BlockEntityRenderDispatcher.instance.getRenderer(carriedBlock.entity);
+            TileEntityRenderer<TileEntity> renderer = TileEntityRenderDispatcher.instance.getRenderer(carriedBlock.entity);
             if (renderer != null) {
                 carriedBlock.entity.worldObj = player.world;
                 renderer.doRender(tessellator, carriedBlock.entity, -0.5, -0.5, -0.5, partialTick);
@@ -116,7 +112,7 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
         }
     }
     @Override
-    protected void renderSpecials(Tessellator tessellator, Player entity, double d, double d1, double d2)
+    protected void renderSpecials(Tessellator tessellator, Player entity, double x, double y, double z)
     {
         if (Minecraft.getMinecraft().thePlayer.getGamemode() != Gamemode.spectator && entity.getGamemode() == Gamemode.spectator) {
             return;
@@ -138,16 +134,16 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
                 {
                     if(entity.isPlayerSleeping())
                     {
-                        renderLivingLabel(tessellator, entity, s, d, d1 - 1.5D, d2, 64, false);
+                        renderLivingLabel(tessellator, entity, s, x, y - 1.5D, z, 64, false);
                     } else
                     {
-                        renderLivingLabel(tessellator, entity, s, d, d1, d2, 64, false);
+                        renderLivingLabel(tessellator, entity, s, x, y, z, 64, false);
                     }
                 } else
                 {
                     Font font = getFont();
                     GL11.glPushMatrix();
-                    GL11.glTranslatef((float)d + 0.0F, (float)d1 + 2.3F, (float)d2);
+                    GL11.glTranslatef((float) x + 0.0F, (float) y + 2.3F, (float) z);
                     GL11.glNormal3f(0.0F, 1.0F, 0.0F);
                     GL11.glRotatef(-renderDispatcher.viewLerpYaw, 0.0F, 1.0F, 0.0F);
                     GL11.glRotatef(renderDispatcher.viewLerpPitch, 1.0F, 0.0F, 0.0F);
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 cedcbb1d5..c270f7617 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
@@ -1,5 +1,6 @@
 package net.minecraft.client.render.entity;
 
+import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.model.ModelWolf;
@@ -11,6 +12,8 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.useless.dragonfly.DisplayPos;
 
 public class MobRendererWolf extends MobRenderer<MobWolf>
 {
@@ -52,30 +55,22 @@ public class MobRendererWolf extends MobRenderer<MobWolf>
     }
 
     @Override
-    protected void renderAdditional(MobWolf entity, float f){
-        ItemStack itemstack = entity.getWolfHeldItem();
+    protected void renderAdditional(MobWolf entity, float partialTick){
+        ItemStack itemstack = entity.getHeldItem();
 
         if(itemstack != null && itemstack.getItem() != null) {
             GL11.glPushMatrix();
             modelWolfMain.wolfHeadMain.translateTo(0.0625F);
-            GL11.glTranslatef(-0.0625F, 0.4375F, 0.0625F);
-            float scale;
-            if (itemstack.itemID > 0 && itemstack.itemID < Blocks.blocksList.length && BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemstack.itemID]).shouldItemRender3d()) {
-                scale = 0.35F;
-                GL11.glTranslatef(0.075F, -0.3F, -0.35F);
-                scale *= 0.75F;
-                GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
-                GL11.glScalef(scale, -scale, scale);
-
-            } else {
-                scale = 0.375F;
-                GL11.glTranslatef(0.25F, -0.25F, -0.35F);
-                GL11.glScalef(scale, scale, scale);
-                GL11.glRotatef(50F, 0.0F, 0.0F, 1.0F);
-                GL11.glRotatef(-90F, 1.0F, 0.0F, 0.0F);
-                GL11.glRotatef(70F, 1.0F, 0.0F, 1.0F);
-            }
-            ItemModelDispatcher.getInstance().getDispatch(itemstack).renderItem(Tessellator.instance, renderDispatcher.itemRenderer, entity, itemstack);
+            GL11.glScalef(1, -1, 1);
+            GL11.glTranslatef(0.5f/16f, -2.5f/16f, -2/16f);
+            GL11.glRotatef(-2.5f, 0, 0, 1);
+            GL11.glRotatef(45, 0, 1, 0);
+            GL11.glRotatef(-90, 1, 0, 0);
+            GL11.glEnable(GL12.GL_RESCALE_NORMAL);
+            GL11.glEnable(GL11.GL_BLEND);
+            ItemModelDispatcher.getInstance().getDispatch(itemstack).render(Tessellator.instance, entity, itemstack, DisplayPos.GROUND, Minecraft.getMinecraft().gameSettings.items3D.value, 1, entity.getBrightness(partialTick), 1f, partialTick, true);
+            GL11.glDisable(GL11.GL_BLEND);
+            GL11.glDisable(GL12.GL_RESCALE_NORMAL);
             GL11.glPopMatrix();
         }
     }
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 6cf37eed3..b389474db 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
@@ -1,43 +1,106 @@
 package net.minecraft.client.render.item.model;
 
-import net.minecraft.client.Minecraft;
+import net.minecraft.client.render.EntityRenderDispatcher;
 import net.minecraft.client.render.Font;
 import net.minecraft.client.render.ItemRenderer;
+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.tessellator.Tessellator;
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-
-import java.util.Random;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.useless.dragonfly.DisplayPos;
 
 public abstract class ItemModel {
     public Item item;
     public ItemModel(Item item){
         this.item = item;
     }
-    public abstract void renderItemFirstPerson(Tessellator tessellator, ItemRenderer renderer, Player player, ItemStack stack, float partialTick);
-    public void renderItem(Tessellator tessellator, ItemRenderer renderer, Mob entityLiving, ItemStack itemStack){
-        final Minecraft mc = Minecraft.getMinecraft();
-        float brightness = entityLiving.getBrightness(1.0f);
-        renderItem(tessellator, renderer, itemStack, entityLiving, brightness, true);
+
+    public abstract void render(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, float brightness, float alpha, 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 Tessellator tessellator, @NotNull Font font, @NotNull TextureManager textureManager, @NotNull ItemStack itemstack, int x, int y, @Nullable String override, float alpha);
+
+    public void renderGui(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, int x, int y, float brightness, float alpha, float partialTick) {
+        GL11.glPushMatrix();
+        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+        GL11.glDisable(GL11.GL_LIGHTING);
+        GL11.glEnable(GL11.GL_BLEND);
+        GL11.glEnable(GL11.GL_CULL_FACE);
+        GL11.glTranslatef(x + 8, y + 8, 0);
+        GL11.glScalef(16, -16, 1);
+        render(tessellator, holder, itemStack, DisplayPos.GUI, false, 1, brightness, alpha, partialTick, false);
+        GL11.glEnable(GL11.GL_LIGHTING);
+        GL11.glDisable(GL11.GL_CULL_FACE);
+        GL11.glDisable(GL11.GL_BLEND);
+        GL11.glPopMatrix();
     }
-    public abstract void renderItem(Tessellator tessellator, ItemRenderer renderer, ItemStack itemstack, @Nullable Entity entity, float brightness, boolean handheldTransform);
-    public abstract void renderItemThirdPerson(Tessellator tessellator, ItemRenderer renderer, Entity entity, ItemStack itemstack, boolean handheldTransform);
-    public void renderItemIntoGui(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemstack, int x, int y, float alpha) {
-        renderItemIntoGui(tessellator, font, textureManager, itemstack, x, y, 1.0f, alpha);
+
+    public void renderItemEntity(@NotNull Tessellator tessellator, @NotNull ItemStack itemStack, boolean items3d, int clusterSize, int ticks, float yaw, float brightness, float alpha, float partialTick) {
+        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
+        GL11.glEnable(GL11.GL_BLEND);
+        if (items3d) {
+            GL11.glRotated(yaw, 0, 1, 0);
+        } else {
+            GL11.glRotatef(180F - EntityRenderDispatcher.instance.viewLerpYaw, 0.0F, 1.0F, 0.0F);
+        }
+        render(tessellator, null, itemStack, DisplayPos.GROUND, items3d, clusterSize, brightness, alpha, partialTick, false);
+        GL11.glDisable(GL11.GL_BLEND);
+        GL11.glDisable(GL12.GL_RESCALE_NORMAL);
     }
-    public abstract void renderItemIntoGui(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemStack, int x, int y, float brightness, float alpha);
-    public void renderItemOverlayIntoGUI(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemstack, int x, int y, float alpha) {
-        renderItemOverlayIntoGUI(tessellator, font, textureManager, itemstack, x, y, null, alpha);
+
+    public void renderFirstPerson(@NotNull Tessellator tessellator, @NotNull ItemRenderer itemRenderer, @NotNull Player player, @NotNull ItemStack itemStack, float brightness, float alpha, float partialTick) {
+        GL11.glPushMatrix();
+        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
+        final float swingProgress = player.getSwingProgress(partialTick);
+        final float animationProgress2 = MathHelper.sin(swingProgress * MathHelper.PI);
+        final float animationProgress = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
+
+        if (player.isLeftHanded()) {
+            final float xOff = 9/16f;
+            final float yOff = -8.25f/16f -(1.0F - itemRenderer.getEquippedProgress(partialTick)) * 0.6F;
+            final float zOff = -0.775f;
+
+            GL11.glScalef(-1, 1, 1);
+            GL11.glTranslatef(-animationProgress * 0.4F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.2F, -animationProgress2 * 0.2F); // Makes swing travel in an arc
+            GL11.glTranslatef(xOff, yOff, zOff);
+
+            float animationProgress3 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
+            GL11.glRotatef(45, 0, 1, 0);
+            GL11.glRotatef(-animationProgress3 * 20F, 0.0F, 1.0F, 0.0F);
+            GL11.glRotatef(-animationProgress * 20F, 0.0F, 0.0F, 1.0F);
+            GL11.glRotatef(-animationProgress * 80F, 1.0F, 0.0F, 0.0F);
+            GL11.glRotatef(-45, 0, 1, 0);
+
+            GL11.glFrontFace(GL11.GL_CW);
+            render(tessellator,player, itemStack, DisplayPos.FIRST_PERSON_LEFT_HAND, true, 1, brightness, alpha, partialTick, true);
+            GL11.glFrontFace(GL11.GL_CCW);
+        } else {
+            final float xOff = 9/16f;
+            final float yOff = -8.25f/16f -(1.0F - itemRenderer.getEquippedProgress(partialTick)) * 0.6F;
+            final float zOff = -0.775f;
+
+            GL11.glTranslatef(-animationProgress * 0.4F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.2F, -animationProgress2 * 0.2F); // Makes swing travel in an arc
+            GL11.glTranslatef(xOff, yOff, zOff);
+
+            float animationProgress3 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
+            GL11.glRotatef(45, 0, 1, 0);
+            GL11.glRotatef(-animationProgress3 * 20F, 0.0F, 1.0F, 0.0F);
+            GL11.glRotatef(-animationProgress * 20F, 0.0F, 0.0F, 1.0F);
+            GL11.glRotatef(-animationProgress * 80F, 1.0F, 0.0F, 0.0F);
+            GL11.glRotatef(-45, 0, 1, 0);
+
+            render(tessellator,player, itemStack, DisplayPos.FIRST_PERSON_RIGHT_HAND, true, 1, brightness, alpha, partialTick, false);
+        }
+        GL11.glPopMatrix();
+        GL11.glDisable(GL12.GL_RESCALE_NORMAL);
     }
 
-    public abstract void renderItemOverlayIntoGUI(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemstack, int x, int y, String override, float alpha);
-    public abstract void renderAsItemEntity(Tessellator tessellator, @Nullable Entity entity, Random random, ItemStack itemstack, int renderCount, float yaw, float brightness, float partialTick);
-    public abstract void renderItemInWorld(Tessellator tessellator, Entity entity, ItemStack itemStack, float brightness, float alpha, boolean worldTransform);
     public abstract IconCoordinate getIcon(@Nullable Entity entity, ItemStack itemStack);
 }
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 1c28468c1..4334b3a74 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
@@ -1,212 +1,119 @@
 package net.minecraft.client.render.item.model;
 
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
-import net.minecraft.client.render.ItemRenderer;
-import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
+import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
-import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
-import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.block.ItemBlock;
-import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.util.helper.Side;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.opengl.GL12;
-
-import java.util.Random;
-
-import static org.lwjgl.opengl.GL11.*;
+import org.useless.dragonfly.DisplayPos;
 
 public class ItemModelBlock extends ItemModelStandard {
-    private Block<?> block;
-    private BlockModel<?> blockModel;
+    private final Block<?> block;
+    private final BlockModel<?> blockModel;
     public ItemModelBlock(ItemBlock<?> itemBlock){
         super(itemBlock, null);
         this.block = itemBlock.getBlock();
         this.blockModel = BlockModelDispatcher.getInstance().getDispatch(block);
-        icon = blockModel.getBlockTextureFromSideAndMetadata(Side.NORTH, 0);
+        icon = blockModel.getOverlayTexture(0);
     }
 
     @Override
     public @NotNull IconCoordinate getIcon(@Nullable Entity entity, ItemStack itemStack) {
-        return this.blockModel.getBlockTextureFromSideAndMetadata(Side.NORTH, itemStack.getMetadata());
+        return this.blockModel.getOverlayTexture(itemStack.getMetadata());
     }
 
     @Override
-    public void renderItemFirstPerson(Tessellator tessellator, ItemRenderer renderer, Player player, ItemStack stack, float partialTick) {
-        final Minecraft mc = Minecraft.getMinecraft();
-        float brightness = 1.0f;
-        if(LightmapHelper.isLightmapEnabled()) {
-        	int lightmapCoord = player.getLightmapCoord(partialTick);
-        	if(itemfullBright) {
-        		lightmapCoord = LightmapHelper.setBlocklightValue(lightmapCoord, 15);
-        	}
-        	LightmapHelper.setLightmapCoord(lightmapCoord);	
-        }else if(mc.fullbright || itemfullBright) {
-        	
-        }else {
-        	brightness = player.getBrightness(1.0f);
-        }
-        
-        final float distanceScale = 0.8F; // Relates to how close the held item renders from the camera
-        final float swingProgress = player.getSwingProgress(partialTick);
-        final float animationProgress2 = MathHelper.sin(swingProgress * MathHelper.PI);
-        final float animationProgress = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
-
-        GL11.glTranslatef(-animationProgress * 0.4F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.2F, -animationProgress2 * 0.2F); // Makes swing travel in an arc
-        GL11.glTranslatef(0.7F * distanceScale, -0.65F * distanceScale - (1.0F - renderer.getEquippedProgress(partialTick)) * 0.6F, -0.9F * distanceScale); // Positions hand in correct place on right side of screen
-        GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F); // 45 degrees tilt, makes it face more towards the camera
-        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
-
-        float animationProgress3 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
-        GL11.glRotatef(-animationProgress3 * 20F, 0.0F, 1.0F, 0.0F);
-        GL11.glRotatef(-animationProgress * 20F, 0.0F, 0.0F, 1.0F);
-        GL11.glRotatef(-animationProgress * 80F, 1.0F, 0.0F, 0.0F);
-
-        final float scale = 0.4F;
-        GL11.glScalef(scale, scale, scale);
-
-        if (blockModel.shouldItemRender3d())
-        {
-            GL11.glRotatef(-90F, 0.0F, 1.0F, 0.0F);
-        }
-        renderItem(tessellator, renderer, stack, player, brightness, true);
+    public @NotNull DisplayPos getDisplayPos(@NotNull String id) {
+        return blockModel.shouldItemRender3d() ? this.blockModel.getItemDisplayPos(id) : super.getDisplayPos(id); // TODO this is jank fix with proper implementation
     }
+
     @Override
-    public void renderItem(Tessellator tessellator, ItemRenderer renderer, ItemStack itemstack, @Nullable Entity entity, float brightness, boolean handheldTransform) {
-        if(BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemstack.itemID]).shouldItemRender3d())
-        {
-            GL11.glEnable(GL_BLEND);
-            GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-            TextureRegistry.blockAtlas.bind();
-            BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemstack.itemID]).renderBlockOnInventory(tessellator, itemstack.getMetadata(), brightness, null);
-            GL11.glDisable(GL_BLEND);
-        } else {
-            super.renderItem(tessellator, renderer, itemstack, entity, brightness, handheldTransform);
+    public void render(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, float brightness, float alpha, float partialTick, boolean mirrorX) {
+        if (!blockModel.shouldItemRender3d()) {
+            super.render(tessellator, holder, itemStack, displayPosId, items3d, clusterSize, brightness, alpha, partialTick, mirrorX);
+            return;
         }
-    }
-    @Override
-    public void heldTransformThirdPerson(ItemRenderer renderer, Entity entity, ItemStack itemStack) {
-        if(itemStack.itemID < Blocks.blocksList.length && BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemStack.itemID]).shouldItemRender3d()) {
-            final float scale = 0.5F * 0.75F;
-            GL11.glTranslatef(0.0F, 0.1875F, -0.3125F);
-            GL11.glRotatef(20F, 1.0F, 0.0F, 0.0F);
-            GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
-            GL11.glScalef(scale, -scale, scale);
-        } else {
-            super.heldTransformThirdPerson(renderer, entity, itemStack);
+        random.setSeed(187L);
+        DisplayPos displayPos = getDisplayPos(displayPosId);
+        GL11.glTranslatef(displayPos.tx, displayPos.ty, displayPos.tz);
+        GL11.glRotatef(displayPos.rx, 1, 0, 0);
+        GL11.glRotatef(displayPos.ry, 0, 1, 0);
+        GL11.glRotatef(displayPos.rz, 0, 0, 1);
+        GL11.glScalef(displayPos.sx, displayPos.sy, displayPos.sz);
+        int color = getColor(itemStack);
+        float r = net.minecraft.core.util.helper.Color.redFromInt(color)/255f;
+        float g = net.minecraft.core.util.helper.Color.greenFromInt(color)/255f;
+        float b = net.minecraft.core.util.helper.Color.blueFromInt(color)/255f;
+        GL11.glColor4f(brightness * r, brightness * g, brightness * b, alpha);
+        for (int i = 0; i < clusterSize; i++) {
+            float rOffX = 0;
+            float rOffY = 0;
+            float rOffZ = 0;
+            if (i > 0) {
+                rOffX = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / displayPos.sx;
+                rOffY = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / displayPos.sy;
+                rOffZ = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / displayPos.sz;
+            }
+            GL11.glTranslatef(rOffX, rOffY, rOffZ);
+            renderSingle(tessellator, holder, itemStack, items3d, brightness, alpha, partialTick, mirrorX);
+            GL11.glTranslatef(-rOffX, -rOffY, -rOffZ);
         }
     }
+
     @Override
-    public void renderItemIntoGui(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemStack, int x, int y, float brightness, float alpha) {
-        if (itemStack == null) return;
-        GL11.glEnable(GL_BLEND);
-        GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        GL11.glEnable(GL_CULL_FACE);
-        if (BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemStack.itemID]).shouldItemRender3d()) {
-            GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
-            TextureRegistry.blockAtlas.bind();
-            GL11.glPushMatrix();
-            GL11.glTranslatef(x - 2, y + 3, -3F);
-            GL11.glScalef(10F, 10F, 10F);
-            GL11.glTranslatef(1.0F, 0.5F, 1.0F);
-            GL11.glScalef(1.0F, 1.0F, -1F);
-            GL11.glRotatef(210F, 1.0F, 0.0F, 0.0F);
-            GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
-            if (useColor) {
-                final int color = getColor(itemStack);
-                final float r = (color >> 16 & 0xff) / 255F;
-                final float g = (color >> 8 & 0xff) / 255F;
-                final float b = (color & 0xff) / 255F;
-                GL11.glColor4f(r * brightness, g * brightness, b * brightness, alpha);
-            } else {
-                GL11.glColor4f(brightness, brightness, brightness, alpha);
-            }
-            GL11.glRotatef(-90F, 0.0F, 1.0F, 0.0F);
-            BlockModel.renderBlocks.useInventoryTint = useColor;
-            BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemStack.itemID]).renderBlockOnInventory(tessellator, itemStack.getMetadata(), brightness, alpha, null);
-            BlockModel.renderBlocks.useInventoryTint = true;
-            GL11.glPopMatrix();
+    protected void renderSingle(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, float brightness, float alpha, float partialTick, boolean mirrorX) {
+        if (!blockModel.shouldItemRender3d()) {
+            super.renderSingle(tessellator, holder,itemStack, items3d, brightness, alpha, partialTick, mirrorX);
         } else {
-            super.renderItemIntoGui(tessellator, font, textureManager, itemStack, x, y, brightness, alpha);
+            TextureRegistry.blockAtlas.bind();
+            blockModel.renderStandalone(tessellator, itemStack.getMetadata(), brightness, alpha, null);
         }
-        GL11.glEnable(GL_CULL_FACE);
-        GL11.glDisable(GL_BLEND);
     }
-    
+
     @Override
-    public void renderAsItemEntity(Tessellator tessellator, Entity entity, Random random, ItemStack itemstack, int renderCount, float yaw, float brightness, float partialTick) {
-        if (Blocks.blocksList[itemstack.itemID] != null && BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemstack.itemID]).shouldItemRender3d()) {
-            GL11.glRotatef(yaw, 0.0F, 1.0F, 0.0F);
-            TextureRegistry.blockAtlas.bind();
-            final float itemSize = blockModel.getItemRenderScale();
-            GL11.glScalef(itemSize, itemSize, itemSize);
-            for (int i = 0; i < renderCount; i++) {
-                GL11.glPushMatrix();
-                if (i > 0) {
-                    final float rOffX = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / itemSize;
-                    final float rOffY = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / itemSize;
-                    final float rOffZ = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / itemSize;
-                    GL11.glTranslatef(rOffX, rOffY, rOffZ);
-                }
-                if(LightmapHelper.isLightmapEnabled()) {
-                	brightness = 1.0f;
-                	LightmapHelper.setLightmapCoord(entity.getLightmapCoord(partialTick));
-                }
-                if (Global.accessor.isFullbrightEnabled() || itemfullBright) {
-                	brightness = 1.0f;
-                }
-                blockModel.renderBlockOnInventory(tessellator, itemstack.getMetadata(), brightness, null);
-                GL11.glPopMatrix();
-            }
-        } else {
-            super.renderAsItemEntity(tessellator, entity, random, itemstack, renderCount, yaw, brightness, partialTick);
+    public void renderGui(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, int x, int y, float brightness, float alpha, float partialTick) {
+        if (!blockModel.shouldItemRender3d()) {
+            super.renderGui(tessellator, holder, itemStack, x, y, brightness, alpha, partialTick);
+            return;
         }
+        GL11.glPushMatrix();
+        GL11.glEnable(GL11.GL_BLEND);
+        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+        GL11.glEnable(GL11.GL_CULL_FACE);
+        GL11.glTranslatef(x + 8, y + 8, 1);
+        GL11.glScalef(16, -16, 1);
+        render(tessellator, holder, itemStack, DisplayPos.GUI, false, 1, brightness, alpha, partialTick, false);
+        GL11.glDisable(GL11.GL_CULL_FACE);
+        GL11.glDisable(GL11.GL_BLEND);
+        GL11.glPopMatrix();
     }
-    
+
     @Override
-    public void renderItemInWorld(Tessellator tessellator, Entity entity, ItemStack itemStack, float brightness, float alpha, boolean worldTransform) {
-        if (itemStack == null) return;
-        GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        GL11.glEnable(GL_CULL_FACE);
-        GL11.glEnable(GL_BLEND);
-        if (BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemStack.itemID]).shouldItemRender3d()) {
-            GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
-            TextureRegistry.blockAtlas.bind();
-            if (useColor) {
-                final int color = getColor(itemStack);
-                final float r = (color >> 16 & 0xff) / 255F;
-                final float g = (color >> 8 & 0xff) / 255F;
-                final float b = (color & 0xff) / 255F;
-                GL11.glColor4f(r * brightness, g * brightness, b * brightness, alpha);
-            } else {
-                GL11.glColor4f(brightness, brightness, brightness, alpha);
-            }
-            GL11.glRotatef(90F, 0.0F, 1.0F, 0.0F);
-            BlockModel.renderBlocks.useInventoryTint = useColor;
-            BlockModelDispatcher.getInstance().getDispatch(Blocks.blocksList[itemStack.itemID]).renderBlockOnInventory(tessellator, itemStack.getMetadata(), brightness, alpha, null);
-            BlockModel.renderBlocks.useInventoryTint = true;
-        } else {
-            super.renderItemInWorld(tessellator, entity, itemStack, brightness, alpha, worldTransform);
+    public void renderItemEntity(@NotNull Tessellator tessellator, @NotNull ItemStack itemStack, boolean items3d, int clusterSize, int ticks, float yaw, float brightness, float alpha, float partialTick) {
+        if (!blockModel.shouldItemRender3d()) {
+            super.renderItemEntity(tessellator, itemStack, items3d, clusterSize, ticks, yaw, brightness, alpha, partialTick);
+            return;
         }
-        GL11.glDisable(GL_CULL_FACE);
-        GL11.glDisable(GL_BLEND);
+        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
+        GL11.glEnable(GL11.GL_BLEND);
+        GL11.glRotated(yaw, 0, 1, 0);
+        render(tessellator, null, itemStack, DisplayPos.GROUND, items3d, clusterSize, brightness, alpha, partialTick, false);
+        GL11.glDisable(GL11.GL_BLEND);
+        GL11.glDisable(GL12.GL_RESCALE_NORMAL);
     }
+
     @Override
     public int getColor(ItemStack stack)
     {
-        return BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(stack.getMetadata());
+        return BlockColorDispatcher.getInstance().getDispatch(block).getFallbackColor(stack.getMetadata(), 0);
     }
 }
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 792841bc9..bb6df22ad 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
@@ -1,11 +1,6 @@
 package net.minecraft.client.render.item.model;
 
-import net.minecraft.client.Minecraft;
 import net.minecraft.client.entity.player.PlayerRemote;
-import net.minecraft.client.render.Font;
-import net.minecraft.client.render.ItemRenderer;
-import net.minecraft.client.render.TextureManager;
-import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.monster.MobSkeleton;
@@ -13,67 +8,37 @@ import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
-import static org.lwjgl.opengl.GL11.GL_BLEND;
-import static org.lwjgl.opengl.GL11.GL_CULL_FACE;
-import static org.lwjgl.opengl.GL11.GL_LIGHTING;
-import static org.lwjgl.opengl.GL11.glBlendFunc;
-import static org.lwjgl.opengl.GL11.glDisable;
-import static org.lwjgl.opengl.GL11.glEnable;
-
 public class ItemModelBow extends ItemModelStandard {
     public ItemModelBow(Item item, String namespace) {
         super(item, namespace);
     }
 
     @Override
-    public void renderItem(Tessellator tessellator, ItemRenderer renderer, ItemStack itemstack, Entity entity, float brightness, boolean handheldTransform) {
-        super.renderItem(tessellator, renderer, itemstack, entity, brightness, handheldTransform);
+    protected void renderSingle(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, float brightness, float alpha, float partialTick, boolean mirrorX) {
+        super.renderSingle(tessellator, holder, itemStack, items3d, brightness, alpha, partialTick, mirrorX);
         Item nextArrow = null;
-        if (entity instanceof Player){
-            Player entityplayer = (Player)entity;
+        if (holder instanceof Player){
+            Player entityplayer = (Player)holder;
             nextArrow = getNextArrow(entityplayer);
-        }
-        if (entity instanceof MobSkeleton){
-            if (((MobSkeleton) entity).attackTime < 5){
+        } else if (holder instanceof MobSkeleton){
+            if (((MobSkeleton) holder).attackTime < 5){
                 nextArrow = Items.AMMO_ARROW;
             }
         }
         if (nextArrow != null){
-            GL11.glRotatef(-90, 0, 0, 1);
-            GL11.glTranslatef(-1,0, 0.0625f);
-            ItemModelDispatcher.getInstance().getDispatch(nextArrow).renderItem(tessellator, renderer, itemstack, entity, brightness, false);
+            GL11.glPushMatrix();
+            GL11.glRotatef(90, 0, 0, 1);
+            GL11.glTranslatef(0.0001f, 0.0001f, 0);
+            GL11.glScalef(1, 1, 0.999f);
+            renderCoordinate(tessellator, ItemModelDispatcher.getInstance().getDispatch(nextArrow).getIcon(holder, nextArrow.getDefaultStack()), items3d, mirrorX);
+            GL11.glPopMatrix();
         }
     }
-    @Override
-    public void renderItemIntoGui(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemStack, int x, int y, float brightness, float alpha) {
-        Minecraft mc = Minecraft.getMinecraft();
-        Item nextArrow = getNextArrow(mc.thePlayer);
-        if (itemStack == mc.thePlayer.getHeldItem() && nextArrow != null){
-            glEnable(GL_BLEND);
-            glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
-            glEnable(GL_CULL_FACE);
-            ItemModelStandard arrowModel = (ItemModelStandard) ItemModelDispatcher.getInstance().getDispatch(nextArrow);
-            IconCoordinate textureIndex = arrowModel.getIcon(mc.thePlayer, nextArrow.getDefaultStack());
-            GL11.glDisable(GL_LIGHTING);
-            textureIndex.parentAtlas.bind();
-            if (useColor) {
-                final int color = getColor(itemStack);
-                final float r = (color >> 16 & 0xff) / 255F;
-                final float g = (color >> 8 & 0xff) / 255F;
-                final float b = (color & 0xff) / 255F;
-                GL11.glColor4f(r * brightness, g * brightness, b * brightness, alpha);
-            } else {
-                GL11.glColor4f(brightness, brightness, brightness, alpha);
-            }
-            renderTexturedQuad(tessellator, x, y, textureIndex, true, false);
-            glEnable(GL_LIGHTING);
-            glEnable(GL_CULL_FACE);
-            glDisable(GL11.GL_BLEND);
-        }
-        super.renderItemIntoGui(tessellator, font, textureManager, itemStack, x, y, brightness, alpha);
-    }
+
     public Item getNextArrow(Player player){
         if (player instanceof PlayerRemote){
             int id = player.getArrowId();
@@ -82,13 +47,4 @@ public class ItemModelBow extends ItemModelStandard {
         }
         return player.getNextArrow();
     }
-    @Override
-    public void heldTransformThirdPerson(ItemRenderer renderer, Entity entity, ItemStack itemStack) {
-        GL11.glTranslatef(0.0F, 0.125F, 0.3125F);
-        GL11.glRotatef(-20.0F, 0.0F, 1.0F, 0.0F);
-        final float scale = 0.625F;
-        GL11.glScalef(scale, -scale, scale);
-        GL11.glRotatef(-100.0F, 1.0F, 0.0F, 0.0F);
-        GL11.glRotatef(45.0F, 0.0F, 1.0F, 0.0F);
-    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
index 3a87550ae..0e7b69eb7 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
@@ -7,9 +7,20 @@ import net.minecraft.core.item.Item;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.block.ItemBlock;
+import org.useless.dragonfly.DisplayPos;
 
 public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
-    private static final ItemModelDispatcher instance = new ItemModelDispatcher();
+    protected static final DisplayPos HANDHELD_FIRST_PERSON_RIGHT_HAND = new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 0, -90, 25, 0.68f, 0.68f, 0.68f);
+    protected static final DisplayPos HANDHELD_FIRST_PERSON_LEFT_HAND = new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 0, 90, -25, 0.68f, 0.68f, 0.68f);
+    protected static final DisplayPos HANDHELD_THIRD_PERSON_RIGHT_HAND = new DisplayPos(0, 4.0f/16f, 0.5f/16f, 0, -90, 55, 0.85f, 0.85f, 0.85f);
+    protected static final DisplayPos HANDHELD_THIRD_PERSON_LEFT_HAND = new DisplayPos(0, 4.0f/16f, 0.5f/16f, 0,  90, -55, 0.85f, 0.85f, 0.85f);
+
+    protected static final DisplayPos HANDHELD_ROD_FIRST_PERSON_RIGHT_HAND = new DisplayPos(0/16f, 1.6f/16f, 0.8f/16f, 0, 90, 25, 0.68f, 0.68f, 0.68f);
+    protected static final DisplayPos HANDHELD_ROD_FIRST_PERSON_LEFT_HAND = new DisplayPos(0/16f, 1.6f/16f, 0.8f/16f, 0, -90, -25, 0.68f, 0.68f, 0.68f);
+    protected static final DisplayPos HANDHELD_ROD_THIRD_PERSON_RIGHT_HAND = new DisplayPos(0, 4.0f/16f, 2.5f/16f, 0, 90, 55, 0.85f, 0.85f, 0.85f);
+    protected static final DisplayPos HANDHELD_ROD_THIRD_PERSON_LEFT_HAND = new DisplayPos(0, 4.0f/16f, 2.5f/16f, 0,  -90, -55, 0.85f, 0.85f, 0.85f);
+
+    private static ItemModelDispatcher instance = new ItemModelDispatcher();
     public static final ItemModel emptyModel = new ItemModelNone();
 
     public static ItemModelDispatcher getInstance()
@@ -32,51 +43,165 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
     }
 
     private ItemModelDispatcher() {
-        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_IRON, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_IRON, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_AXE_IRON, "minecraft").setFull3D());
+        instance = this;
+        reload();
+    }
+
+    public void reload() {
+        dispatches.clear();
+        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_IRON, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_IRON, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_AXE_IRON, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
         addDispatch(new ItemModelStandard(Items.TOOL_FIRESTRIKER_IRON, "minecraft"));
 
         addDispatch(new ItemModelStandard(Items.FOOD_APPLE, "minecraft"));
-        addDispatch(new ItemModelBow(Items.TOOL_BOW, "minecraft"));
+        addDispatch(new ItemModelBow(Items.TOOL_BOW, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 0, -90, 25, 0.68f, 0.68f, 0.68f))
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 0, 90, -25, 0.68f, 0.68f, 0.68f))
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, new DisplayPos(-1f/16f, -2f/16f, 2.5f/16f, -80, 260, -40, 0.9f, 0.9f, 0.9f))
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, new DisplayPos(-1f/16f, -2f/16f, 2.5f/16f, -80, -280, 40, 0.9f, 0.9f, 0.9f)));
         addDispatch(new ItemModelStandard(Items.AMMO_ARROW, "minecraft"));
         addDispatch(new ItemModelCoal(Items.COAL, "minecraft"));
         addDispatch(new ItemModelStandard(Items.DIAMOND, "minecraft"));
         addDispatch(new ItemModelStandard(Items.INGOT_IRON, "minecraft"));
         addDispatch(new ItemModelStandard(Items.INGOT_GOLD, "minecraft"));
 
-        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_IRON, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_WOOD, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_WOOD, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_WOOD, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_AXE_WOOD, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_STONE, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_STONE, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_STONE, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_AXE_STONE, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_DIAMOND, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_DIAMOND, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_DIAMOND, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_AXE_DIAMOND, "minecraft").setFull3D());
-
-        addDispatch(new ItemModelStandard(Items.STICK, "minecraft").setFull3D());
+        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_IRON, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_WOOD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_WOOD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_WOOD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_AXE_WOOD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_STONE, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_STONE, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_STONE, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_AXE_STONE, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_DIAMOND, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_DIAMOND, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_DIAMOND, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_AXE_DIAMOND, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+
+        addDispatch(new ItemModelStandard(Items.STICK, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
         addDispatch(new ItemModelStandard(Items.BOWL, "minecraft"));
         addDispatch(new ItemModelStandard(Items.FOOD_STEW_MUSHROOM, "minecraft"));
 
-        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_GOLD, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_GOLD, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_GOLD, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_AXE_GOLD, "minecraft").setFull3D());
+        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_GOLD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_GOLD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_GOLD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_AXE_GOLD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
 
         addDispatch(new ItemModelStandard(Items.STRING, "minecraft"));
         addDispatch(new ItemModelStandard(Items.FEATHER_CHICKEN, "minecraft"));
         addDispatch(new ItemModelStandard(Items.SULPHUR, "minecraft"));
 
-        addDispatch(new ItemModelStandard(Items.TOOL_HOE_WOOD, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_HOE_STONE, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_HOE_IRON, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_HOE_DIAMOND, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_HOE_GOLD, "minecraft").setFull3D());
+        addDispatch(new ItemModelStandard(Items.TOOL_HOE_WOOD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_HOE_STONE, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_HOE_IRON, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_HOE_DIAMOND, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_HOE_GOLD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
 
         addDispatch(new ItemModelStandard(Items.SEEDS_WHEAT, "minecraft"));
         addDispatch(new ItemModelStandard(Items.WHEAT, "minecraft"));
@@ -137,13 +262,21 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
         addDispatch(new ItemModelStandard(Items.MINECART_FURNACE, "minecraft"));
         addDispatch(new ItemModelStandard(Items.EGG_CHICKEN, "minecraft"));
         addDispatch(new ItemModelStandard(Items.TOOL_COMPASS, "minecraft"));
-        addDispatch(new ItemModelFishingRod(Items.TOOL_FISHINGROD, "minecraft").setFull3D().setRotateWhenRendering());
+        addDispatch(new ItemModelFishingRod(Items.TOOL_FISHINGROD, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_ROD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_ROD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_ROD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_ROD_THIRD_PERSON_LEFT_HAND));
         addDispatch(new ItemModelStandard(Items.TOOL_CLOCK, "minecraft"));
         addDispatch(new ItemModelStandard(Items.DUST_GLOWSTONE, "minecraft").setFullBright());
         addDispatch(new ItemModelStandard(Items.FOOD_FISH_RAW, "minecraft"));
         addDispatch(new ItemModelStandard(Items.FOOD_FISH_COOKED, "minecraft"));
         addDispatch(new ItemModelDye(Items.DYE));
-        addDispatch(new ItemModelStandard(Items.BONE, "minecraft").setFull3D());
+        addDispatch(new ItemModelStandard(Items.BONE, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
         addDispatch(new ItemModelStandard(Items.DUST_SUGAR, "minecraft"));
         addDispatch(new ItemModelStandard(Items.FOOD_CAKE, "minecraft"));
         addDispatch(new ItemModelStandard(Items.FOOD_PUMPKIN_PIE, "minecraft"));
@@ -160,21 +293,49 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
         addDispatch(new ItemModelStandard(Items.ARMOR_LEGGINGS_STEEL, "minecraft"));
         addDispatch(new ItemModelStandard(Items.ARMOR_BOOTS_STEEL, "minecraft"));
 
-        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_STEEL, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_STEEL, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_STEEL, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_AXE_STEEL, "minecraft").setFull3D());
-        addDispatch(new ItemModelStandard(Items.TOOL_HOE_STEEL, "minecraft").setFull3D());
+        addDispatch(new ItemModelStandard(Items.TOOL_SWORD_STEEL, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_SHOVEL_STEEL, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_PICKAXE_STEEL, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_AXE_STEEL, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.TOOL_HOE_STEEL, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
 
         addDispatch(new ItemModelStandard(Items.INGOT_STEEL, "minecraft"));
         addDispatch(new ItemModelStandard(Items.INGOT_STEEL_CRUDE, "minecraft"));
         addDispatch(new ItemModelStandard(Items.AMMO_FIREBALL, "minecraft").setFullBright());
         addDispatch(new ItemModelStandard(Items.ARMOR_QUIVER_GOLD, "minecraft"));
-        addDispatch(new ItemModelStandard(Items.HANDCANNON_UNLOADED, "minecraft").setFull3D());
+        addDispatch(new ItemModelStandard(Items.HANDCANNON_UNLOADED, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
         addDispatch(new ItemModelStandard(Items.CHAINLINK, "minecraft"));
         addDispatch(new ItemModelStandard(Items.CLOTH, "minecraft"));
         addDispatch(new ItemModelStandard(Items.AMMO_CHARGE_EXPLOSIVE, "minecraft"));
-        addDispatch(new ItemModelStandard(Items.HANDCANNON_LOADED, "minecraft").setFull3D().setFullBright());
+        addDispatch(new ItemModelStandard(Items.HANDCANNON_LOADED, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND).setFullBright());
         addDispatch(new ItemModelStandard(Items.AMMO_ARROW_GOLD, "minecraft"));
         addDispatch(new ItemModelQuiver(Items.ARMOR_QUIVER, "minecraft"));
         addDispatch(new ItemModelStandard(Items.TOOL_CALENDAR, "minecraft"));
@@ -195,7 +356,11 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
         addDispatch(new ItemModelStandard(Items.LANTERN_FIREFLY_RED, "minecraft").setFullBright());
 
         addDispatch(new ItemModelStandard(Items.BASKET, "minecraft"));
-        addDispatch(new ItemModelStandard(Items.FLAG, "minecraft").setFull3D());
+        addDispatch(new ItemModelStandard(Items.FLAG, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
 
         addDispatch(new ItemModelStandard(Items.ARMOR_BOOTS_ICESKATES, "minecraft"));
         addDispatch(new ItemModelStandard(Items.TOOL_SHEARS_STEEL, "minecraft"));
@@ -205,9 +370,17 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
 
         addDispatch(new ItemModelStandard(Items.ROPE, "minecraft"));
 
-        addDispatch(new ItemModelStandard(Items.WAND_MONSTER_SPAWNER, "minecraft").setFull3D());
+        addDispatch(new ItemModelStandard(Items.WAND_MONSTER_SPAWNER, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
         addDispatch(new ItemModelStandard(Items.DOOR_STEEL, "minecraft"));
-        addDispatch(new ItemModelPaintbrush(Items.PAINTBRUSH, "minecraft").setFull3D());
+        addDispatch(new ItemModelPaintbrush(Items.PAINTBRUSH, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
 
         addDispatch(new ItemModelStandard(Items.RECORD_13, "minecraft"));
         addDispatch(new ItemModelStandard(Items.RECORD_CAT, "minecraft"));
@@ -236,6 +409,11 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
         addDispatch(new ItemModelStandard(Items.JAR_BUTTERFLY_SILVER, "minecraft"));
 
         addDispatch(new ItemModelStandard(Items.STATUE_STONE, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.STATUE_BASALT, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.STATUE_LIMESTONE, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.STATUE_GRANITE, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.STATUE_MARBLE, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.STATUE_PIGMAN, "minecraft"));
 
         for (int i = 0; i < Blocks.blocksList.length; i++) {
             if (Blocks.blocksList[i] == null) continue;
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 2fa56485e..93c192540 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
@@ -26,95 +26,90 @@ import org.lwjgl.opengl.GL12;
 
 public class ItemModelMap extends ItemModelStandard {
     private final Minecraft mc = Minecraft.getMinecraft();
-    private final MapItemRenderer renderMapInstance = new MapItemRenderer(mc.font, mc.gameSettings, mc.textureManager);
+    private final MapItemRenderer renderMapInstance = new MapItemRenderer();
 
     public ItemModelMap(Item item, String namespace) {
         super(item, namespace);
     }
-
     @Override
-    public void renderItemFirstPerson(Tessellator tessellator, ItemRenderer renderer, Player player, ItemStack stack, float partialTick) {
-    	int blockX = MathHelper.floor(player.x);
-    	int blockY = MathHelper.floor(player.y);
-    	int blockZ = MathHelper.floor(player.z);
-    	
-        // Apply appropriate brightness
-        float brightness = 1.0f;
-        if(LightmapHelper.isLightmapEnabled()) {
-        	LightmapHelper.setLightmapCoord(mc.currentWorld.getLightmapCoord(blockX, blockY, blockZ, 0));
-        }else if(mc.fullbright) {
-        	
-        }else {
-        	brightness = mc.currentWorld.getLightBrightness(blockX, blockY, blockZ);
-        }
-        GL11.glColor4f(brightness, brightness, brightness, 1.0f);
+    public void renderFirstPerson(@NotNull Tessellator tessellator, @NotNull ItemRenderer itemRenderer, @NotNull Player player, @NotNull ItemStack itemStack, float brightness, float alpha, float partialTick) {
+        // The map renders very differently from any other item, so has its own custom first person render code
+        if (ItemMap.hasInitialized(itemStack)) {
+            GL11.glPushMatrix();
+            GL11.glEnable(GL12.GL_RESCALE_NORMAL);
 
-        final float rotationPitch = player.xRotO + (player.xRot - player.xRotO) * partialTick;
-        final float swingProgress = player.getSwingProgress(partialTick);
-        final float f_z = MathHelper.sin(swingProgress * MathHelper.PI);
-        final float f_x = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
-        GL11.glTranslatef(-f_x * 0.4F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.2F, -f_z * 0.2F);
+            final float rotationPitch = player.xRotO + (player.xRot - player.xRotO) * partialTick;
+            final float swingProgress = player.getSwingProgress(partialTick);
+            final float f_z = MathHelper.sin(swingProgress * MathHelper.PI);
+            final float f_x = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
+            GL11.glTranslatef(-f_x * 0.4F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.2F, -f_z * 0.2F);
 
-        float f_val = MathHelper.clamp((1.0F - rotationPitch / 45F) + 0.1F, 0, 1);
-        f_val = -MathHelper.cos(f_val * MathHelper.PI) * 0.5F + 0.5F;
-        final float zOff = 0.8F * -0.9F;
-        GL11.glTranslatef(0.0F, (-(1.0F - renderer.getEquippedProgress(partialTick)) * 1.2F - f_val * 0.5F) + 0.04F, zOff); // Place map at right distance from camera
-        GL11.glRotatef(90F, 0.0F, 1.0F, 0.0F);
-        GL11.glRotatef(f_val * -85F, 0.0F, 0.0F, 1.0F);
-        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
+            float f_val = MathHelper.clamp((1.0F - rotationPitch / 45F) + 0.1F, 0, 1);
+            f_val = -MathHelper.cos(f_val * MathHelper.PI) * 0.5F + 0.5F;
+            final float zOff = 0.8F * -0.9F;
+            GL11.glTranslatef(0.0F, (-(1.0F - itemRenderer.getEquippedProgress(partialTick)) * 1.2F - f_val * 0.5F) + 0.04F, zOff); // Place map at right distance from camera
+            GL11.glRotatef(90F, 0.0F, 1.0F, 0.0F);
+            GL11.glRotatef(f_val * -85F, 0.0F, 0.0F, 1.0F);
+            GL11.glEnable(GL12.GL_RESCALE_NORMAL);
 
-        // Render both player arms
-        mc.textureManager.bindDownloadableTexture(mc.thePlayer.skinURL, mc.thePlayer.getEntityTexture(), PlayerSkinParser.instance);
-        MobRendererPlayer playerRenderer = (MobRendererPlayer) (EntityRenderer<? extends Entity>) EntityRenderDispatcher.instance.getRenderer(mc.thePlayer);
+            // Render both player arms
+            mc.textureManager.bindDownloadableTexture(mc.thePlayer.skinURL, mc.thePlayer.getEntityTexture(), PlayerSkinParser.instance);
+            MobRendererPlayer playerRenderer = (MobRendererPlayer) (EntityRenderer<? extends Entity>) EntityRenderDispatcher.instance.getRenderer(mc.thePlayer);
 
-        GL11.glPushMatrix();
-        GL11.glTranslatef(-0F, -0.6F, -1.1F);
-        GL11.glRotatef(180, 0, 1, 0);
-        GL11.glRotatef(-45, 1.0F, 0.0F, 0.0F);
-        GL11.glRotatef(90F - 59F, 0.0F, 0.0F, 1.0F);
-        GL11.glRotatef(65, 0.0F, 1.0F, 0.0F);
-        playerRenderer.drawFirstPersonHand(mc.thePlayer, true);
-        GL11.glPopMatrix();
-        GL11.glPushMatrix();
-        GL11.glTranslatef(-0F, -0.6F, 1.1F);
-        GL11.glRotatef(-45, 1.0F, 0.0F, 0.0F);
-        GL11.glRotatef(-90F + 59F, 0.0F, 0.0F, 1.0F);
-        GL11.glRotatef(-65, 0.0F, 1.0F, 0.0F);
-        playerRenderer.drawFirstPersonHand(mc.thePlayer, false);
-        GL11.glPopMatrix();
+            GL11.glPushMatrix();
+            GL11.glTranslatef(-0F, -0.6F, -1.1F);
+            GL11.glRotatef(180, 0, 1, 0);
+            GL11.glRotatef(-45, 1.0F, 0.0F, 0.0F);
+            GL11.glRotatef(90F - 59F, 0.0F, 0.0F, 1.0F);
+            GL11.glRotatef(65, 0.0F, 1.0F, 0.0F);
+            playerRenderer.drawFirstPersonHand(mc.thePlayer, true);
+            GL11.glPopMatrix();
+            GL11.glPushMatrix();
+            GL11.glTranslatef(-0F, -0.6F, 1.1F);
+            GL11.glRotatef(-45, 1.0F, 0.0F, 0.0F);
+            GL11.glRotatef(-90F + 59F, 0.0F, 0.0F, 1.0F);
+            GL11.glRotatef(-65, 0.0F, 1.0F, 0.0F);
+            playerRenderer.drawFirstPersonHand(mc.thePlayer, false);
+            GL11.glPopMatrix();
 
 
-        final float f_val3 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
-        final float f_val4 = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
-        GL11.glRotatef(-f_val3 * 20F, 0.0F, 1.0F, 0.0F);
-        GL11.glRotatef(-f_val4 * 20F, 0.0F, 0.0F, 1.0F);
-        GL11.glRotatef(-f_val4 * 80F, 1.0F, 0.0F, 0.0F);
+            final float f_val3 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
+            final float f_val4 = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
+            GL11.glRotatef(-f_val3 * 20F, 0.0F, 1.0F, 0.0F);
+            GL11.glRotatef(-f_val4 * 20F, 0.0F, 0.0F, 1.0F);
+            GL11.glRotatef(-f_val4 * 80F, 1.0F, 0.0F, 0.0F);
 
-        final float scale1 = 0.38F;
-        GL11.glScalef(scale1, scale1, scale1);
-        GL11.glRotatef(90F, 0.0F, 1.0F, 0.0F);
-        GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
-        GL11.glTranslatef(-1F, -1F, 0.0F);
+            final float scale1 = 0.38F;
+            GL11.glScalef(scale1, scale1, scale1);
+            GL11.glRotatef(90F, 0.0F, 1.0F, 0.0F);
+            GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
+            GL11.glTranslatef(-1F, -1F, 0.0F);
 
-        final float scale2 = 0.015625F;
-        GL11.glScalef(scale2, scale2, scale2);
+            final float scale2 = 0.015625F;
+            GL11.glScalef(scale2, scale2, scale2);
 
-        GL11.glNormal3f(0.0F, 0.0F, -1F);
+            GL11.glNormal3f(0.0F, 0.0F, -1F);
 
-        // Render paper background of map
-        mc.textureManager.bindTexture(mc.textureManager.loadTexture("/assets/minecraft/textures/misc/mapbg.png"));
-        tessellator.startDrawingQuads();
-        final byte expansion = 7; // makes the edges extend around the actual map data by a bit
-        tessellator.addVertexWithUV(-expansion,     128 + expansion, 0.0D, 0.0D, 1.0D);
-        tessellator.addVertexWithUV(128 + expansion,128 + expansion, 0.0D, 1.0D, 1.0D);
-        tessellator.addVertexWithUV(128 + expansion,-expansion,      0.0D, 1.0D, 0.0D);
-        tessellator.addVertexWithUV(-expansion,     -expansion,      0.0D, 0.0D, 0.0D);
-        tessellator.draw();
+            // Render paper background of map
+            mc.textureManager.bindTexture(mc.textureManager.loadTexture("/assets/minecraft/textures/misc/mapbg.png"));
+            tessellator.startDrawingQuads();
+            final byte expansion = 7; // makes the edges extend around the actual map data by a bit
+            tessellator.addVertexWithUV(-expansion,     128 + expansion, 0.0D, 0.0D, 1.0D);
+            tessellator.addVertexWithUV(128 + expansion,128 + expansion, 0.0D, 1.0D, 1.0D);
+            tessellator.addVertexWithUV(128 + expansion,-expansion,      0.0D, 1.0D, 0.0D);
+            tessellator.addVertexWithUV(-expansion,     -expansion,      0.0D, 0.0D, 0.0D);
+            tessellator.draw();
 
-        ItemMapSavedData mapData = Items.MAP.getOrCreateSavedData(stack, mc.currentWorld);
-        if (mapData == null) return;
-        renderMapInstance.renderMap(mc.textureManager, mapData, brightness);
+            ItemMapSavedData mapData = Items.MAP.getOrCreateSavedData(itemStack, mc.currentWorld);
+            if (mapData != null) {
+                renderMapInstance.renderMap(tessellator, mapData, brightness);
+            }
+            GL11.glPopMatrix();
+        } else {
+            super.renderFirstPerson(tessellator, itemRenderer, player, itemStack, brightness, alpha, partialTick);
+        }
     }
+
     @Override
     public @NotNull IconCoordinate getIcon(@Nullable Entity entity, ItemStack itemStack){
         if (!ItemMap.hasInitialized(itemStack)){
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 655d998ca..156213958 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
@@ -1,54 +1,27 @@
 package net.minecraft.client.render.item.model;
 
 import net.minecraft.client.render.Font;
-import net.minecraft.client.render.ItemRenderer;
 import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Random;
-
 public class ItemModelNone extends ItemModel{
     public ItemModelNone() {
         super(null);
     }
 
-    @Override
-    public void renderItemFirstPerson(Tessellator tessellator, ItemRenderer renderer, Player player, ItemStack stack, float partialTick) {
-
-    }
-
-    @Override
-    public void renderItem(Tessellator tessellator, ItemRenderer renderer, ItemStack itemstack, @Nullable Entity entity, float brightness, boolean handheldTransform) {
-
-    }
-
-    @Override
-    public void renderItemThirdPerson(Tessellator tessellator, ItemRenderer renderer, Entity entity, ItemStack itemstack, boolean handheldTransform) {
-
-    }
-
-    @Override
-    public void renderItemIntoGui(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemStack, int x, int y, float brightness, float alpha) {
-
-    }
-
-    @Override
-    public void renderItemOverlayIntoGUI(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemstack, int x, int y, String override, float alpha) {
-
-    }
 
     @Override
-    public void renderAsItemEntity(Tessellator tessellator, @Nullable Entity entity, Random random, ItemStack itemstack, int renderCount, float yaw, float brightness, float partialTick) {
+    public void render(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, float brightness, float alpha, float partialTick, boolean mirrorX) {
 
     }
 
     @Override
-    public void renderItemInWorld(Tessellator tessellator, Entity entity, ItemStack itemStack, float brightness, float alpha, boolean worldTransform) {
+    public void renderItemOverlayIntoGUI(@NotNull Tessellator tessellator, @NotNull Font font, @NotNull TextureManager textureManager, @NotNull ItemStack itemstack, int x, int y, @Nullable String override, float alpha) {
 
     }
 
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 6a63af17b..4437d04bb 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,169 +1,209 @@
 package net.minecraft.client.render.item.model;
 
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.EntityRenderDispatcher;
 import net.minecraft.client.render.Font;
-import net.minecraft.client.render.ItemRenderer;
-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;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
-import org.lwjgl.opengl.GL12;
+import org.useless.dragonfly.DisplayPos;
 
 import java.awt.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Random;
 
 import static org.lwjgl.opengl.GL11.GL_BLEND;
-import static org.lwjgl.opengl.GL11.GL_CULL_FACE;
 import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST;
 import static org.lwjgl.opengl.GL11.GL_LIGHTING;
-import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
-import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
 import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
 import static org.lwjgl.opengl.GL11.glBlendFunc;
 import static org.lwjgl.opengl.GL11.glDisable;
 import static org.lwjgl.opengl.GL11.glEnable;
-import static org.lwjgl.opengl.GL11.glPopMatrix;
-import static org.lwjgl.opengl.GL11.glPushMatrix;
-import static org.lwjgl.opengl.GL11.glRotated;
-import static org.lwjgl.opengl.GL11.glScaled;
-import static org.lwjgl.opengl.GL11.glTranslated;
 
 public class ItemModelStandard extends ItemModel{
-    final Minecraft mc = Minecraft.getMinecraft();
+    protected static final Random random = new Random();
+
     public static final IconCoordinate ITEM_TEXTURE_MISSING = TextureRegistry.getTexture("minecraft:item/texture_missing");
     public static final IconCoordinate ITEM_TEXTURE_UNASSIGNED = TextureRegistry.getTexture("minecraft:item/texture_unassigned");
-    protected boolean useColor = true;
     public IconCoordinate icon = ITEM_TEXTURE_UNASSIGNED;
-    protected boolean bFull3D = false;
-    protected boolean rotateWhenRendering = false;
-    protected boolean pointInfrontOfPlayer = false;
+    protected @NotNull Map<@NotNull String, @NotNull DisplayPos> displayPosMap = new HashMap<>();
+
+    public static final DisplayPos DEFAULT_ITEM_GROUND = new DisplayPos(0, 2/16f, 0, 0, 0, 0, 0.5f, 0.5f, 0.5f);
+    public static final DisplayPos DEFAULT_ITEM_HEAD = new DisplayPos(0, 14/16f, 0, 0, 0, 0, 1, 1, 1); // This is different from modern mc's default
+    public static final DisplayPos DEFAULT_ITEM_THIRD_PERSON_RIGHT_HAND = new DisplayPos(0, 3/16f, 1/16f, 0, 0, 0, 0.55f, 0.55f, 0.55f);
+    public static final DisplayPos DEFAULT_ITEM_THIRD_PERSON_LEFT_HAND = new DisplayPos(-0, 3/16f, 1/16f, -0, 0, 0, 0.55f, 0.55f, 0.55f);
+    public static final DisplayPos DEFAULT_ITEM_FIRST_PERSON_RIGHT_HAND = new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 0, -90, 25, 0.68f, 0.68f, 0.68f);
+    public static final DisplayPos DEFAULT_ITEM_FIRST_PERSON_LEFT_HAND = new DisplayPos(-1.13f/16f, 3.2f/16f, 1.13f/16f, -0, -90, 25, 0.68f, 0.68f, 0.68f);
+    public static final DisplayPos DEFAULT_ITEM_FIXED = new DisplayPos(0, 0, 0, 0, 180, 0, 1, 1, 1);
+
     protected boolean itemfullBright = false;
 
     public ItemModelStandard(Item item, String namespace) {
         super(item);
+        displayPosMap.put(DisplayPos.GROUND, DEFAULT_ITEM_GROUND);
+        displayPosMap.put(DisplayPos.HEAD, DEFAULT_ITEM_HEAD);
+        displayPosMap.put(DisplayPos.THIRD_PERSON_RIGHT_HAND, DEFAULT_ITEM_THIRD_PERSON_RIGHT_HAND);
+        displayPosMap.put(DisplayPos.THIRD_PERSON_LEFT_HAND, DEFAULT_ITEM_THIRD_PERSON_LEFT_HAND); // TODO make automatic since its just the axis flipped
+        displayPosMap.put(DisplayPos.FIRST_PERSON_RIGHT_HAND, DEFAULT_ITEM_FIRST_PERSON_RIGHT_HAND);
+        displayPosMap.put(DisplayPos.FIRST_PERSON_LEFT_HAND, DEFAULT_ITEM_FIRST_PERSON_LEFT_HAND); // TODO make automatic since its just the axis flipped
+        displayPosMap.put(DisplayPos.FIXED, DEFAULT_ITEM_FIXED);
         if (namespace != null){
             icon = TextureRegistry.getTexture(namespace + ":item/" + item.getKey().substring("item.".length()).replace(".", "_"));
         }
     }
 
     @Override
-    public void renderItemFirstPerson(Tessellator tessellator, ItemRenderer renderer, Player player, ItemStack stack, float partialTick) {
-        float brightness = 1.0f;
-        if(mc.fullbright || itemfullBright || LightmapHelper.isLightmapEnabled()) {
-        	if(LightmapHelper.isLightmapEnabled()) {
-            	int lightmapCoord = player.getLightmapCoord(partialTick);
-            	if(itemfullBright) {
-            		lightmapCoord = LightmapHelper.setBlocklightValue(lightmapCoord, 15);
-            	}
-            	LightmapHelper.setLightmapCoord(lightmapCoord);	
-        	}
-        }else {
-        	brightness = player.getBrightness(1.0f);
+    public void render(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, float brightness, float alpha, float partialTick, boolean mirrorX) {
+        random.setSeed(187L);
+        DisplayPos displayPos = getDisplayPos(displayPosId);
+        GL11.glTranslatef(displayPos.tx, displayPos.ty, displayPos.tz);
+        GL11.glRotatef(displayPos.rx, 1, 0, 0);
+        GL11.glRotatef(displayPos.ry, 0, 1, 0);
+        GL11.glRotatef(displayPos.rz, 0, 0, 1);
+        GL11.glScalef(displayPos.sx, displayPos.sy, displayPos.sz);
+        int color = getColor(itemStack);
+        float r = net.minecraft.core.util.helper.Color.redFromInt(color)/255f;
+        float g = net.minecraft.core.util.helper.Color.greenFromInt(color)/255f;
+        float b = net.minecraft.core.util.helper.Color.blueFromInt(color)/255f;
+        GL11.glColor4f(brightness * r, brightness * g, brightness * b, alpha);
+        if (items3d) {
+            for (int i = 0; i < clusterSize; i++) {
+                float offX = 0;
+                float offY = 0;
+                float offZ = 0.1f * i;
+                GL11.glTranslatef(offX, offY, offZ);
+                renderSingle(tessellator, holder, itemStack, true, brightness, alpha, partialTick, mirrorX);
+                GL11.glTranslatef(-offX, -offY, -offZ);
+            }
+        } else {
+            for (int i = 0; i < clusterSize; i++) {
+                float rOffX = 0;
+                float rOffY = 0;
+                float rOffZ = 0;
+                if (i > 0) {
+                    rOffX = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / displayPos.sx;
+                    rOffY = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / displayPos.sy;
+                    rOffZ = ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / displayPos.sz;
+                }
+                GL11.glTranslatef(rOffX, rOffY, rOffZ);
+                renderSingle(tessellator, holder, itemStack, false, brightness, alpha, partialTick, mirrorX);
+                GL11.glTranslatef(-rOffX, -rOffY, -rOffZ);
+            }
         }
+    }
 
-        final float distanceScale = 0.8F; // Relates to how close the held item renders from the camera
-        final float swingProgress = player.getSwingProgress(partialTick);
-        final float animationProgress2 = MathHelper.sin(swingProgress * MathHelper.PI);
-        final float animationProgress = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI);
+    protected void renderSingle(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, float brightness, float alpha, float partialTick, boolean mirrorX) {
+        renderCoordinate(tessellator, getIcon(holder, itemStack), items3d, mirrorX);
+    }
 
-        GL11.glTranslatef(-animationProgress * 0.4F, MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.2F, -animationProgress2 * 0.2F); // Makes swing travel in an arc
-        GL11.glTranslatef(0.7F * distanceScale, -0.65F * distanceScale - (1.0F - renderer.getEquippedProgress(partialTick)) * 0.6F, -0.9F * distanceScale); // Positions hand in correct place on right side of screen
-        GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F); // 45 degrees tilt, makes it face more towards the camera
-        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
+    protected void renderCoordinate(@NotNull Tessellator tessellator, @NotNull IconCoordinate coordinate, boolean items3d, boolean mirrorX) {
+        final double cUMin = mirrorX ? coordinate.getIconUMax() : coordinate.getIconUMin();
+        final double cUMax = mirrorX ? coordinate.getIconUMin() : coordinate.getIconUMax();
+        final double cVMin = coordinate.getIconVMin();
+        final double cVMax = coordinate.getIconVMax();
+
+        coordinate.parentAtlas.bind();
+        if (items3d) {
+            final float halfThickness = 0.5f/16f;
+            final int pxH = coordinate.height;
+            final int pxW = coordinate.width;
+
+            tessellator.startDrawingQuads();
+            // front
+            tessellator.setNormal(0, 0, -1);
+            tessellator.addVertexWithUV(-0.5,  0.5, -halfThickness, cUMin, cVMin);
+            tessellator.addVertexWithUV( 0.5,  0.5, -halfThickness, cUMax, cVMin);
+            tessellator.addVertexWithUV( 0.5, -0.5, -halfThickness, cUMax, cVMax);
+            tessellator.addVertexWithUV(-0.5, -0.5, -halfThickness, cUMin, cVMax);
+
+            // top bottom
+            for (int h = 0; h < pxH; h++) {
+                double y1 = (double) h /pxH;
+                double y2 = (double) (h + 1) /pxH;
+                double vMin = coordinate.getSubIconV(y1);
+                double vMax = coordinate.getSubIconV(y2);
+
+                // top
+                tessellator.setNormal(0, 1, 0);
+                tessellator.addVertexWithUV(-0.5, 0.5 - y1, -halfThickness, cUMin, vMin);
+                tessellator.addVertexWithUV(-0.5, 0.5 - y1,  halfThickness, cUMin, vMax);
+                tessellator.addVertexWithUV( 0.5, 0.5 - y1,  halfThickness, cUMax, vMax);
+                tessellator.addVertexWithUV( 0.5, 0.5 - y1, -halfThickness, cUMax, vMin);
+
+                // bottom
+                tessellator.setNormal(0, -1, 0);
+                tessellator.addVertexWithUV(-0.5, 0.5 - y2, -halfThickness, cUMin, vMin);
+                tessellator.addVertexWithUV( 0.5, 0.5 - y2, -halfThickness, cUMax, vMin);
+                tessellator.addVertexWithUV( 0.5, 0.5 - y2,  halfThickness, cUMax, vMax);
+                tessellator.addVertexWithUV(-0.5, 0.5 - y2,  halfThickness, cUMin, vMax);
+            }
 
-        float animationProgress3 = MathHelper.sin(swingProgress * swingProgress * MathHelper.PI);
-        GL11.glRotatef(-animationProgress3 * 20F, 0.0F, 1.0F, 0.0F);
-        GL11.glRotatef(-animationProgress * 20F, 0.0F, 0.0F, 1.0F);
-        GL11.glRotatef(-animationProgress * 80F, 1.0F, 0.0F, 0.0F);
+            // left right
+            for (int w = 0; w < pxW; w++) {
+                double x1 = (double) w / pxW;
+                double x2 = (double) (w + 1) / pxW;
 
-        final float scale = 0.4F;
-        GL11.glScalef(scale, scale, scale);
 
-        heldTransformFirstPerson(renderer, player, stack);
+                double uMin = coordinate.getSubIconU(mirrorX ? 1 - x1 : x1);
+                double uMax = coordinate.getSubIconU(mirrorX ? 1 - x2 : x2);
 
-        renderItem(tessellator, renderer, stack, player, brightness, true);
-    }
-
-    @Override
-    public void renderItem(Tessellator tessellator, ItemRenderer renderer, ItemStack itemstack, @Nullable Entity entity, float brightness, boolean handheldTransform) {
-        if (itemfullBright || LightmapHelper.isLightmapEnabled()) {
-        	brightness = 1.0f;
-        }
-        if(handheldTransform) {
-            GL11.glTranslatef(-0.0F, -0.3F, 0.0F);
-            final float handheldScale = 1.5F;
-            GL11.glScalef(handheldScale, handheldScale, handheldScale);
-            GL11.glRotatef(50F, 0.0F, 1.0F, 0.0F);
-            GL11.glRotatef(335F, 0.0F, 0.0F, 1.0F);
-            GL11.glTranslatef(-0.9375F, -0.0625F, 0.0F);
-        }
+                // right
+                tessellator.setNormal(-1, 0, 0);
+                tessellator.addVertexWithUV(x1 - 0.5,  0.5, -halfThickness, uMin, cVMin);
+                tessellator.addVertexWithUV(x1 - 0.5, -0.5, -halfThickness, uMax, cVMax);
+                tessellator.addVertexWithUV(x1 - 0.5, -0.5,  halfThickness, uMax, cVMax);
+                tessellator.addVertexWithUV(x1 - 0.5,  0.5,  halfThickness, uMin, cVMin);
 
-        renderItemInWorld(tessellator, entity, itemstack, brightness, 1f, false);
+                // left
+                tessellator.setNormal(1, 0, 0);
+                tessellator.addVertexWithUV(x2 - 0.5,  0.5, -halfThickness, uMin, cVMin);
+                tessellator.addVertexWithUV(x2 - 0.5,  0.5,  halfThickness, uMin, cVMin);
+                tessellator.addVertexWithUV(x2 - 0.5, -0.5,  halfThickness, uMax, cVMax);
+                tessellator.addVertexWithUV(x2 - 0.5, -0.5, -halfThickness, uMax, cVMax);
+            }
 
+            // back
+            tessellator.setNormal(0, 0, 1);
+            tessellator.addVertexWithUV(-0.5,  0.5, halfThickness, cUMin, cVMin);
+            tessellator.addVertexWithUV(-0.5, -0.5, halfThickness, cUMin, cVMax);
+            tessellator.addVertexWithUV( 0.5, -0.5, halfThickness, cUMax, cVMax);
+            tessellator.addVertexWithUV( 0.5,  0.5, halfThickness, cUMax, cVMin);
+            tessellator.draw();
+        } else {
+            tessellator.startDrawingQuads();
+            tessellator.addVertexWithUV(-0.5,  0.5, 0, cUMin, cVMin);
+            tessellator.addVertexWithUV(-0.5, -0.5, 0, cUMin, cVMax);
+            tessellator.addVertexWithUV( 0.5, -0.5, 0, cUMax, cVMax);
+            tessellator.addVertexWithUV( 0.5,  0.5, 0, cUMax, cVMin);
+
+            tessellator.addVertexWithUV(-0.5,  0.5, 0, cUMin, cVMin);
+            tessellator.addVertexWithUV( 0.5,  0.5, 0, cUMax, cVMin);
+            tessellator.addVertexWithUV( 0.5, -0.5, 0, cUMax, cVMax);
+            tessellator.addVertexWithUV(-0.5, -0.5, 0, cUMin, cVMax);
+            tessellator.draw();
+        }
     }
 
-    @Override
-    public void renderItemThirdPerson(Tessellator tessellator, ItemRenderer renderer, Entity entity, ItemStack itemstack, boolean handheldTransform) {
-        float brightness = 1.0f;
-        if(mc.fullbright || itemfullBright || LightmapHelper.isLightmapEnabled()) {
-        	if(LightmapHelper.isLightmapEnabled()) {
-            	int lightmapCoord = entity.getLightmapCoord(1.0f);
-            	if(itemfullBright) {
-            		lightmapCoord = LightmapHelper.getLightmapCoord(15, 15);
-            	}
-            	LightmapHelper.setLightmapCoord(lightmapCoord);	
-        	}
-        }else {
-        	brightness = entity.getBrightness(1.0f);
-        }
-        
-        GL11.glTranslatef(-0.0625F, 0.4375F, 0.0625F);
-        heldTransformThirdPerson(renderer, entity, itemstack);
-        renderItem(tessellator, renderer, itemstack, entity, brightness, handheldTransform);
+    public @NotNull DisplayPos getDisplayPos(@NotNull String id) {
+        return displayPosMap.getOrDefault(id, DisplayPos.DEFAULT_DISPLAY_POS);
     }
 
-    @Override
-    public void renderItemIntoGui(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemStack, int x, int y, float brightness, float alpha) {
-        if (itemStack == null) return;
-        Minecraft mc = Minecraft.getMinecraft();
-        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
-        GL11.glDisable(GL_LIGHTING);
-        GL11.glEnable(GL_BLEND);
-        GL11.glEnable(GL_CULL_FACE);
-        IconCoordinate textureIndex = getIcon(mc.thePlayer, itemStack);
-        textureIndex.parentAtlas.bind();
-        if (useColor) {
-            final int color = getColor(itemStack);
-            final float r = (color >> 16 & 0xff) / 255F;
-            final float g = (color >> 8 & 0xff) / 255F;
-            final float b = (color & 0xff) / 255F;
-            GL11.glColor4f(r * brightness, g * brightness, b * brightness, alpha);
-        } else {
-            GL11.glColor4f(brightness, brightness, brightness, alpha);
-        }
-        renderTexturedQuad(tessellator, x, y, textureIndex);
-        GL11.glEnable(GL_LIGHTING);
-        GL11.glDisable(GL_CULL_FACE);
-        GL11.glDisable(GL11.GL_BLEND);
+    public @NotNull ItemModelStandard setDisplayPos(@NotNull String id, @NotNull DisplayPos displayPos) {
+        this.displayPosMap.put(id, Objects.requireNonNull(displayPos, "Display pos cannot be null!"));
+        return this;
     }
 
     @Override
-    public void renderItemOverlayIntoGUI(Tessellator tessellator, Font font, TextureManager textureManager, ItemStack itemstack, int x, int y, String override, float alpha) {
+    public void renderItemOverlayIntoGUI(@NotNull Tessellator tessellator, @NotNull Font font, @NotNull TextureManager textureManager, @NotNull ItemStack itemstack, int x, int y, @Nullable String override, float alpha) {
         glEnable(GL_BLEND);
         glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
-        if (itemstack == null) {
-            return;
-        }
         final int a = (int) (alpha * 255.0f);
         if (itemstack.stackSize != 1 || override != null) {
             String s = override != null ? override : "" + itemstack.stackSize;
@@ -192,238 +232,6 @@ public class ItemModelStandard extends ItemModel{
         glDisable(GL_BLEND);
     }
 
-    @Override
-    public void renderAsItemEntity(Tessellator tessellator, @Nullable Entity entity, Random random, ItemStack itemstack, int renderCount, float yaw, float brightness, float partialTick) {
-        final Minecraft mc = Minecraft.getMinecraft();
-        if (mc.fullbright || itemfullBright) brightness = 1.0f;
-
-        EntityRenderDispatcher renderDispatcher = EntityRenderDispatcher.instance;
-        GL11.glScalef(0.5F, 0.5F, 0.5F);
-        final IconCoordinate tex = getIcon(entity, itemstack);
-        tex.parentAtlas.bind();
-        if (useColor) {
-            final int color = getColor(itemstack);
-            final float r = (color >> 16 & 0xff) / 255F;
-            final float g = (color >> 8 & 0xff) / 255F;
-            final float b = (color & 0xff) / 255F;
-            GL11.glColor4f(r * brightness, g * brightness, b * brightness, 1.0F);
-        }  else {
-            GL11.glColor4f(brightness, brightness, brightness, 1.0F);
-        }
-        if(LightmapHelper.isLightmapEnabled() && itemfullBright && entity != null) {
-        	int lmc = entity.getLightmapCoord(1.0f);
-        	lmc = LightmapHelper.setBlocklightValue(lmc, 15);
-        	LightmapHelper.setLightmapCoord(lmc);
-        }
-        if(mc.gameSettings.items3D.value) {
-            glPushMatrix();
-
-            glScaled(1.0, 1.0, 1.0);
-            glRotated(yaw, 0, 1, 0);
-            glTranslated(-0.5, 0.0, -0.05 * (renderCount - 1));
-
-            for(int i=0; i < renderCount; i++) {
-                glPushMatrix();
-
-                glTranslated(0.0, 0.0, 0.1 * i);
-                renderItem(tessellator, renderDispatcher.itemRenderer, itemstack, entity, brightness, false);
-                glPopMatrix();
-            }
-
-            glPopMatrix();
-        } else {
-            for (int i = 0; i < renderCount; i++) {
-                glPushMatrix();
-                if (i > 0) {
-                    final float rOffX = (random.nextFloat() * 2.0F - 1.0F) * 0.3F;
-                    final float rOffY = (random.nextFloat() * 2.0F - 1.0F) * 0.3F;
-                    final float rOffZ = (random.nextFloat() * 2.0F - 1.0F) * 0.3F;
-                    GL11.glTranslatef(rOffX, rOffY, rOffZ);
-                }
-                GL11.glRotatef(180F - renderDispatcher.viewLerpYaw, 0.0F, 1.0F, 0.0F);
-                renderFlat(tessellator, tex);
-                GL11.glPopMatrix();
-            }
-        }
-    }
-
-    @Override
-    public void renderItemInWorld(Tessellator tessellator, Entity entity, ItemStack itemStack, float brightness, float alpha, boolean worldTransform) {
-        GL11.glEnable(GL_BLEND);
-        GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        if (useColor) {
-            final int color = getColor(itemStack);
-            final float r = (color >> 16 & 0xff) / 255F;
-            final float g = (color >> 8 & 0xff) / 255F;
-            final float b = (color & 0xff) / 255F;
-            GL11.glColor4f(r * brightness, g * brightness, b * brightness, alpha);
-        }  else {
-            GL11.glColor4f(brightness, brightness, brightness, alpha);
-        }
-
-        IconCoordinate tex = getIcon(entity, itemStack);
-        tex.parentAtlas.bind();
-        int tileWidth = tex.width;
-
-        float uMin = (float) tex.getIconUMin();
-        float uMax = (float) tex.getIconUMax();
-        float vMin = (float) tex.getIconVMin();
-        float vMax = (float) tex.getIconVMax();
-        float uDiff = uMin - uMax;
-        float vDiff = vMin - vMax;
-        final float width = 1.0F;
-
-        final float foon = (0.5f / tex.parentAtlas.getHeight());
-        final float goon = 0.0625f * (16.0f / tileWidth);
-        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
-        final float thickness = 0.0625f;
-        final float pixelWidth = 1f/tileWidth;
-
-        if (worldTransform){
-            GL11.glTranslatef(-0.5f, -0.5f, thickness/2);
-        }
-
-        // Back Face
-        tessellator.startDrawingQuads();
-        tessellator.setNormal(0.0F, 0.0F, 1.0F);
-        tessellator.addVertexWithUV(0.0D, 0.0D, 0.0D, uMax, vMax);
-        tessellator.addVertexWithUV(width,0.0D, 0.0D, uMin, vMax);
-        tessellator.addVertexWithUV(width,1.0D, 0.0D, uMin, vMin);
-        tessellator.addVertexWithUV(0.0D, 1.0D, 0.0D, uMax, vMin);
-        tessellator.draw();
-
-        // Front Face
-        tessellator.startDrawingQuads();
-        tessellator.setNormal(0.0F, 0.0F, -1F);
-        tessellator.addVertexWithUV(0.0D, 1.0D, -thickness, uMax, vMin);
-        tessellator.addVertexWithUV(width,1.0D, -thickness, uMin, vMin);
-        tessellator.addVertexWithUV(width,0.0D, -thickness, uMin, vMax);
-        tessellator.addVertexWithUV(0.0D, 0.0D, -thickness, uMax, vMax);
-        tessellator.draw();
-
-        // Right Sides
-        tessellator.startDrawingQuads();
-        tessellator.setNormal(-1F, 0.0F, 0.0F);
-        for(int i = 0; i < tileWidth; i++)
-        {
-            float texProgress = i * pixelWidth;
-            float u = (uMax + uDiff * texProgress) - foon;
-            float x = width * texProgress;
-            tessellator.addVertexWithUV(x, 0.0D,    -thickness, u, vMax);
-            tessellator.addVertexWithUV(x, 0.0D,    0.0D,       u, vMax);
-            tessellator.addVertexWithUV(x, 1.0D,    0.0D,       u, vMin);
-            tessellator.addVertexWithUV(x, 1.0D,    -thickness, u, vMin);
-        }
-        tessellator.draw();
-
-        // Left Sides
-        tessellator.startDrawingQuads();
-        tessellator.setNormal(1.0F, 0.0F, 0.0F);
-        for(int i = 0; i < tileWidth; i++)
-        {
-            float texProgress = i * pixelWidth;
-            float u = (uMax + uDiff * texProgress) - foon;
-            float x = width * texProgress + goon;
-            tessellator.addVertexWithUV(x, 1.0D,    -thickness, u, vMin);
-            tessellator.addVertexWithUV(x, 1.0D,    0.0D,       u, vMin);
-            tessellator.addVertexWithUV(x, 0.0D,    0.0D,       u, vMax);
-            tessellator.addVertexWithUV(x, 0.0D,    -thickness, u, vMax);
-        }
-        tessellator.draw();
-
-        // Top Sides
-        tessellator.startDrawingQuads();
-        tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        for(int i = 0; i < tileWidth; i++)
-        {
-            float texProgress = i * pixelWidth;
-            float v = (vMax + vDiff * texProgress) - foon;
-            float y = width * texProgress + goon;
-            tessellator.addVertexWithUV(0.0D,   y,  0.0D,       uMax, v);
-            tessellator.addVertexWithUV(width,  y,  0.0D,       uMin, v);
-            tessellator.addVertexWithUV(width,  y,  -thickness, uMin, v);
-            tessellator.addVertexWithUV(0.0D,   y,  -thickness, uMax, v);
-        }
-        tessellator.draw();
-
-        // Bottom Sides
-        tessellator.startDrawingQuads();
-        tessellator.setNormal(0.0F, -1F, 0.0F);
-        for(int i = 0; i < tileWidth; i++)
-        {
-            float texProgress = i * pixelWidth;
-            float v = (vMax + vDiff * texProgress) - foon;
-            float y = width * texProgress;
-            tessellator.addVertexWithUV(width,  y, 0.0D,        uMin, v);
-            tessellator.addVertexWithUV(0.0D,   y, 0.0D,        uMax, v);
-            tessellator.addVertexWithUV(0.0D,   y, -thickness,  uMax, v);
-            tessellator.addVertexWithUV(width,  y, -thickness,  uMin, v);
-        }
-        tessellator.draw();
-
-        GL11.glDisable(GL12.GL_RESCALE_NORMAL);
-        GL11.glDisable(GL_BLEND);
-    }
-
-    public void renderFlat(Tessellator tessellator, IconCoordinate index){
-        final float xOff = 0.5F;
-        final float yOff = 0.25F;
-        final float z = 0;
-        tessellator.startDrawingQuads();
-        tessellator.setNormal(0.0F, 1.0F, 0.0F);
-        tessellator.addVertexWithUV(0.0F - xOff, 0.0F - yOff, z, index.getIconUMin(), index.getIconVMax());
-        tessellator.addVertexWithUV(1.0F - xOff, 0.0F - yOff, z, index.getIconUMax(), index.getIconVMax());
-        tessellator.addVertexWithUV(1.0F - xOff, 1.0F - yOff, z, index.getIconUMax(), index.getIconVMin());
-        tessellator.addVertexWithUV(0.0F - xOff, 1.0F - yOff, z, index.getIconUMin(), index.getIconVMin());
-        tessellator.draw();
-    }
-
-    public void heldTransformThirdPerson(ItemRenderer renderer, Entity entity, ItemStack itemStack) {
-        if(bFull3D) {
-            final float scale = 0.625F;
-            if(rotateWhenRendering) {
-                GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
-                GL11.glTranslatef(0.0F, -0.125F, 0.0F);
-            }
-            if(pointInfrontOfPlayer) {
-                GL11.glRotatef(-20F, 0.0F, 1.0F, 0.0F);
-                GL11.glTranslatef(0.0F, -0.125F, 0.0F);
-            }
-            GL11.glTranslatef(0.0F, 0.1875F, 0.0F);
-            GL11.glScalef(scale, -scale, scale);
-            GL11.glRotatef(-100F, 1.0F, 0.0F, 0.0F);
-            GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
-        } else {
-            final float scale = 0.375F;
-            GL11.glTranslatef(0.25F, 0.1875F, -0.1875F);
-            GL11.glScalef(scale, scale, scale);
-            GL11.glRotatef(60F, 0.0F, 0.0F, 1.0F);
-            GL11.glRotatef(-90F, 1.0F, 0.0F, 0.0F);
-            GL11.glRotatef(20F, 0.0F, 0.0F, 1.0F);
-        }
-    }
-    public void heldTransformFirstPerson(ItemRenderer renderer, Entity entity, ItemStack itemStack) {
-        if(rotateWhenRendering)
-        {
-            GL11.glRotatef(180F, 0.0F, 1.0F, 0.0F);
-        }
-        if(pointInfrontOfPlayer)
-        {
-            GL11.glRotatef(-20F, 0.0F, 1.0F, 0.0F);
-        }
-    }
-    public @NotNull IconCoordinate getIcon(@Nullable Entity entity, ItemStack itemStack){
-        return icon;
-    }
-    public int getColor(ItemStack stack)
-    {
-        return getColorFromMeta(stack.getMetadata());
-    }
-    public int getColorFromMeta(int meta)
-    {
-        return 0xffffff;
-    }
-
     protected void renderColoredQuad(Tessellator tessellator, int x, int y, int width, int height, int colorRGB, int alpha) {
         final float z = 0.0F;
         tessellator.startDrawingQuads();
@@ -435,50 +243,18 @@ public class ItemModelStandard extends ItemModel{
         tessellator.draw();
     }
 
-    protected void renderTexturedQuad(Tessellator tessellator, int x, int y, IconCoordinate icon) {
-        renderTexturedQuad(tessellator, x, y, icon, false, false);
-    }
-
-    protected void renderTexturedQuad(Tessellator tessellator, int x, int y, IconCoordinate icon, boolean flipX, boolean flipY) {
-        final float z = 0.0F;
-        double uMin = icon.getIconUMin();
-        double uMax = icon.getIconUMax();
-        double vMin = icon.getIconVMin();
-        double vMax = icon.getIconVMax();
-        if (flipX){
-            double _uMin = uMin;
-            uMin = uMax;
-            uMax = _uMin;
-        }
-        if (flipY){
-            double _vMin = vMin;
-            vMin = vMax;
-            vMax = _vMin;
-        }
-        tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x,      y + 16, z, uMin, vMax);
-        tessellator.addVertexWithUV(x + 16, y + 16, z, uMax, vMax);
-        tessellator.addVertexWithUV(x + 16, y,      z, uMax, vMin);
-        tessellator.addVertexWithUV(x,      y,      z, uMin, vMin);
-        tessellator.draw();
-
-    }
-
-    public ItemModelStandard setFull3D()
-    {
-        bFull3D = true;
-        return this;
+    public @NotNull IconCoordinate getIcon(@Nullable Entity entity, ItemStack itemStack){
+        return icon;
     }
-    public ItemModelStandard setRotateWhenRendering()
+    public int getColor(ItemStack stack)
     {
-        rotateWhenRendering = true;
-        return this;
+        return getColorFromMeta(stack.getMetadata());
     }
-    public ItemModelStandard setPointInfrontOfPlayer()
+    public int getColorFromMeta(int meta)
     {
-        pointInfrontOfPlayer = true;
-        return this;
+        return 0xffffff;
     }
+
     public ItemModelStandard setFullBright()
     {
         itemfullBright = true;
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelBase.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelBase.java
index 714fada2c..94ddaedc3 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelBase.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelBase.java
@@ -1,31 +1,28 @@
 package net.minecraft.client.render.model;
 
 import net.minecraft.core.entity.Mob;
+import org.jetbrains.annotations.Nullable;
 
 public abstract class ModelBase
 {
 
+    public float swingProgress;
+    public boolean isRiding;
+
     public ModelBase()
     {
         isRiding = false;
     }
 
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
     }
 
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
-    {
-    }
-
-    public void setLivingAnimations(Mob mob, float limbSwing, float limbYaw, float partialTick)
+    protected void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
     }
 
     public void onUnload(){
 
     }
-
-    public float onGround;
-    public boolean isRiding;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelBiped.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelBiped.java
index ac7602a22..ff4ce45b5 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelBiped.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelBiped.java
@@ -1,6 +1,9 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.IItemHolding;
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelBiped extends ModelBase
 {
@@ -64,9 +67,9 @@ public class ModelBiped extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         head.render(scale);
         body.render(scale);
         armRight.render(scale);
@@ -77,7 +80,7 @@ public class ModelBiped extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         head.yRot = headYaw / 57.29578F; // 1 rad
         head.xRot = headPitch / 57.29578F; // 1 rad
@@ -115,26 +118,54 @@ public class ModelBiped extends ModelBase
         }
         armRight.yRot = 0.0F;
         armLeft.yRot = 0.0F;
-        if(onGround > -9990F)
+        if(swingProgress > -9990F)
         {
-            float f6 = onGround;
-            body.yRot = MathHelper.sin(MathHelper.sqrt_float(f6) * MathHelper.PI * 2.0F) * 0.2F;
-            armRight.z = MathHelper.sin(body.yRot) * 5F;
-            armRight.x = -MathHelper.cos(body.yRot) * 5F;
-            armLeft.z = -MathHelper.sin(body.yRot) * 5F;
-            armLeft.x = MathHelper.cos(body.yRot) * 5F;
-            armRight.yRot += body.yRot;
-            armLeft.yRot += body.yRot;
-            armLeft.xRot += body.xRot;
-            f6 = 1.0F - onGround;
-            f6 *= f6;
-            f6 *= f6;
-            f6 = 1.0F - f6;
-            float f7 = MathHelper.sin(f6 * MathHelper.PI);
-            float f8 = MathHelper.sin(onGround * MathHelper.PI) * -(head.xRot - 0.7F) * 0.75F;
-            armRight.xRot -= (double)f7 * 1.2D + (double)f8;
-            armRight.yRot += body.yRot * 2.0F;
-            armRight.zRot = MathHelper.sin(onGround * MathHelper.PI) * -0.4F;
+            if (mob instanceof IItemHolding && ((IItemHolding) mob).isLeftHanded()) {
+                body.yRot = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * -2.0F) * 0.2F;
+                armRight.z = MathHelper.sin(body.yRot) * 5F;
+                armRight.x = -MathHelper.cos(body.yRot) * 5F;
+                armRight.yRot += body.yRot;
+                armRight.xRot += body.xRot;
+
+                armLeft.z = -MathHelper.sin(body.yRot) * 5F;
+                armLeft.x = MathHelper.cos(body.yRot) * 5F;
+                armLeft.yRot += body.yRot;
+                armLeft.xRot += body.xRot;
+
+                float f6 = 1.0F - swingProgress;
+                f6 *= f6;
+                f6 *= f6;
+                f6 = 1.0F - f6;
+                float f7 = MathHelper.sin(f6 * MathHelper.PI);
+                float f8 = MathHelper.sin(swingProgress * MathHelper.PI) * -(head.xRot - 0.7F) * 0.75F;
+
+                armLeft.xRot -= (double)f7 * 1.2D + (double)f8;
+                armLeft.yRot += body.yRot * 2.0F;
+                armLeft.zRot = MathHelper.sin(swingProgress * MathHelper.PI) * 0.4F;
+            } else {
+                body.yRot = MathHelper.sin(MathHelper.sqrt_float(swingProgress) * MathHelper.PI * 2.0F) * 0.2F;
+                armRight.z = MathHelper.sin(body.yRot) * 5F;
+                armRight.x = -MathHelper.cos(body.yRot) * 5F;
+                armRight.yRot += body.yRot;
+                armRight.xRot += body.xRot;
+
+                armLeft.z = -MathHelper.sin(body.yRot) * 5F;
+                armLeft.x = MathHelper.cos(body.yRot) * 5F;
+                armLeft.yRot += body.yRot;
+                armLeft.xRot += body.xRot;
+
+                float f6 = 1.0F - swingProgress;
+                f6 *= f6;
+                f6 *= f6;
+                f6 = 1.0F - f6;
+                float f7 = MathHelper.sin(f6 * MathHelper.PI);
+                float f8 = MathHelper.sin(swingProgress * MathHelper.PI) * -(head.xRot - 0.7F) * 0.75F;
+
+                armRight.xRot -= (double)f7 * 1.2D + (double)f8;
+                armRight.yRot += body.yRot * 2.0F;
+                armRight.zRot = MathHelper.sin(swingProgress * MathHelper.PI) * -0.4F;
+            }
+
         }
         if(sneaking)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelBoat.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelBoat.java
index d4aab5c8b..1ec5b8b43 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelBoat.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelBoat.java
@@ -1,6 +1,8 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelBoat extends ModelBase
 {
@@ -34,13 +36,12 @@ public class ModelBoat extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         for(int i = 0; i < 5; i++)
         {
             boatSides[i].render(scale);
         }
-
     }
 
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelCannonball.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelCannonball.java
index 0ecd1d5a5..4f36e71a7 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelCannonball.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelCannonball.java
@@ -1,8 +1,13 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
+import org.jetbrains.annotations.Nullable;
+
 public class ModelCannonball extends ModelBase
 {
 
+    public Cube ball;
+
     public ModelCannonball()
     {
         ball = new Cube(0, 0);
@@ -11,16 +16,9 @@ public class ModelCannonball extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         ball.render(scale);
-
     }
 
-    @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
-    {
-    }
-
-    public Cube ball;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelChicken.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelChicken.java
index 25220c7fd..85e39f891 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelChicken.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelChicken.java
@@ -1,6 +1,8 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelChicken extends ModelBase
 {
@@ -44,9 +46,9 @@ public class ModelChicken extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         head.render(scale);
         bill.render(scale);
         chin.render(scale);
@@ -58,7 +60,7 @@ public class ModelChicken extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         head.xRot = headPitch / 57.29578F;
         head.yRot = headYaw / 57.29578F;
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelCow.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelCow.java
index 87c5fc0eb..ec1ede7d9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelCow.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelCow.java
@@ -1,6 +1,8 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelCow extends ModelQuadruped
 {
@@ -39,18 +41,18 @@ public class ModelCow extends ModelQuadruped
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        super.render(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        super.render(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         horn1.render(scale);
         horn2.render(scale);
         udders.render(scale);
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        super.setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        super.setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         horn1.yRot = head.yRot;
         horn1.xRot = head.xRot;
         horn2.yRot = head.yRot;
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelCreeper.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelCreeper.java
index bfc1e5cb6..8b44b1ec7 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelCreeper.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelCreeper.java
@@ -1,6 +1,8 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelCreeper extends ModelBase
 {
@@ -45,9 +47,9 @@ public class ModelCreeper extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         head.render(scale);
         body.render(scale);
         leg1.render(scale);
@@ -57,7 +59,7 @@ public class ModelCreeper extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         head.yRot = headYaw / 57.29578F;
         head.xRot = headPitch / 57.29578F;
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelGhast.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelGhast.java
index e790acf0f..eae274de4 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelGhast.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelGhast.java
@@ -1,6 +1,8 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
@@ -33,7 +35,7 @@ public class ModelGhast extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         for(int i = 0; i < tentacles.length; i++)
         {
@@ -43,9 +45,9 @@ public class ModelGhast extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         body.render(scale);
         for (Cube tentacle : tentacles) {
             tentacle.render(scale);
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelMinecart.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelMinecart.java
index 22c59dd25..45e22d331 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelMinecart.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelMinecart.java
@@ -1,10 +1,14 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelMinecart extends ModelBase
 {
 
+    public Cube[] sideModels;
+
     public ModelMinecart()
     {
         sideModels = new Cube[7];
@@ -18,18 +22,18 @@ public class ModelMinecart extends ModelBase
         byte byte1 = 8;
         byte byte2 = 16;
         byte byte3 = 4;
-        sideModels[0].addBox(-byte0 / 2, -byte2 / 2, -1F, byte0, byte2, 2, 0.0F);
+        sideModels[0].addBox(-byte0 / 2f, -byte2 / 2f, -1F, byte0, byte2, 2, 0.0F);
         sideModels[0].setRotationPoint(0.0F, 0 + byte3, 0.0F);
-        sideModels[5].addBox(-byte0 / 2 + 1, -byte2 / 2 + 1, -1F, byte0 - 2, byte2 - 2, 1, 0.0F);
+        sideModels[5].addBox(-byte0 / 2f + 1, -byte2 / 2f + 1, -1F, byte0 - 2, byte2 - 2, 1, 0.0F);
         sideModels[5].setRotationPoint(0.0F, 0 + byte3, 0.0F);
-        sideModels[1].addBox(-byte0 / 2 + 2, -byte1 - 1, -1F, byte0 - 4, byte1, 2, 0.0F);
+        sideModels[1].addBox(-byte0 / 2f + 2, -byte1 - 1, -1F, byte0 - 4, byte1, 2, 0.0F);
         sideModels[1].setRotationPoint(-byte0 / 2 + 1, 0 + byte3, 0.0F);
-        sideModels[2].addBox(-byte0 / 2 + 2, -byte1 - 1, -1F, byte0 - 4, byte1, 2, 0.0F);
+        sideModels[2].addBox(-byte0 / 2f + 2, -byte1 - 1, -1F, byte0 - 4, byte1, 2, 0.0F);
         sideModels[2].setRotationPoint(byte0 / 2 - 1, 0 + byte3, 0.0F);
-        sideModels[3].addBox(-byte0 / 2 + 2, -byte1 - 1, -1F, byte0 - 4, byte1, 2, 0.0F);
-        sideModels[3].setRotationPoint(0.0F, 0 + byte3, -byte2 / 2 + 1);
-        sideModels[4].addBox(-byte0 / 2 + 2, -byte1 - 1, -1F, byte0 - 4, byte1, 2, 0.0F);
-        sideModels[4].setRotationPoint(0.0F, 0 + byte3, byte2 / 2 - 1);
+        sideModels[3].addBox(-byte0 / 2f + 2, -byte1 - 1, -1F, byte0 - 4, byte1, 2, 0.0F);
+        sideModels[3].setRotationPoint(0.0F, 0 + byte3, -byte2 / 2f + 1);
+        sideModels[4].addBox(-byte0 / 2f + 2, -byte1 - 1, -1F, byte0 - 4, byte1, 2, 0.0F);
+        sideModels[4].setRotationPoint(0.0F, 0 + byte3, byte2 / 2f - 1);
         sideModels[0].xRot = MathHelper.PI / 2F;
         sideModels[1].yRot = MathHelper.PI * 1.5F;
         sideModels[2].yRot = MathHelper.PI / 2F;
@@ -38,7 +42,7 @@ public class ModelMinecart extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         sideModels[5].y = 4F - limbPitch;
         for(int i = 0; i < 6; i++)
@@ -49,9 +53,7 @@ public class ModelMinecart extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
     }
-
-    public Cube sideModels[];
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelPig.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelPig.java
index e27fb305f..f8591d002 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelPig.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelPig.java
@@ -1,7 +1,11 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
+import org.jetbrains.annotations.Nullable;
+
 public class ModelPig extends ModelQuadruped
 {
+    public Cube nose;
 
     public ModelPig()
     {
@@ -17,17 +21,15 @@ public class ModelPig extends ModelQuadruped
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale) {
-        super.render(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick) {
+        super.render(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         nose.render(scale);
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale) {
-        super.setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick) {
+        super.setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         nose.xRot = headPitch / 57.29578F;
         nose.yRot = headYaw / 57.29578F;
     }
-
-    public Cube nose;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelPigman.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelPigman.java
new file mode 100644
index 000000000..cfda6a811
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelPigman.java
@@ -0,0 +1,38 @@
+package net.minecraft.client.render.model;
+
+import net.minecraft.core.entity.Mob;
+import org.jetbrains.annotations.Nullable;
+
+public class ModelPigman extends ModelBiped {
+    public Cube nose;
+
+    public ModelPigman()
+    {
+        this(0.0F);
+    }
+
+    public ModelPigman(float yRotOffset)
+    {
+        this(6, yRotOffset);
+    }
+
+    public ModelPigman(float expansion, float yRotOffset) {
+        super(expansion, yRotOffset);
+        nose = new Cube(24, 0);
+        nose.addBox(-2.0F, -4.0F, -5.0F, 4, 3, 1);
+        nose.setRotationPoint(0.0F, 0, 0);
+    }
+
+    @Override
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick) {
+        super.render(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
+        nose.render(scale);
+    }
+
+    @Override
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick) {
+        super.setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
+        nose.xRot = headPitch / 57.29578F;
+        nose.yRot = headYaw / 57.29578F;
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelPlayer.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelPlayer.java
index 96d2c46a6..4a8a0aa1b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelPlayer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelPlayer.java
@@ -1,5 +1,7 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
 public class ModelPlayer extends ModelBiped {
@@ -61,8 +63,8 @@ public class ModelPlayer extends ModelBiped {
     }
 
     @Override
-	public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale){
-        super.render(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+	public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick){
+        super.render(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         GL11.glPushMatrix();
         bipedLeftArmOverlay.render(scale);
         bipedRightArmOverlay.render(scale);
@@ -73,8 +75,8 @@ public class ModelPlayer extends ModelBiped {
     }
 
     @Override
-	public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale){
-        super.setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+	public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick){
+        super.setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         copyTranslation(this.legLeft, this.bipedLeftLegOverlay);
         copyTranslation(this.legRight, this.bipedRightLegOverlay);
         copyTranslation(this.armLeft, this.bipedLeftArmOverlay);
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelQuadruped.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelQuadruped.java
index 0c37640c4..be0dda713 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelQuadruped.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelQuadruped.java
@@ -1,36 +1,44 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelQuadruped extends ModelBase
 {
+    public Cube head;
+    public Cube body;
+    public Cube leg1;
+    public Cube leg2;
+    public Cube leg3;
+    public Cube leg4;
 
-    public ModelQuadruped(int i, float f)
+    public ModelQuadruped(int heightOffset, float expand)
     {
         head = new Cube(0, 0);
-        head.addBox(-4F, -4F, -8F, 8, 8, 8, f);
-        head.setRotationPoint(0.0F, 18 - i, -6F);
+        head.addBox(-4F, -4F, -8F, 8, 8, 8, expand);
+        head.setRotationPoint(0.0F, 18 - heightOffset, -6F);
         body = new Cube(28, 8);
-        body.addBox(-5F, -10F, -7F, 10, 16, 8, f);
-        body.setRotationPoint(0.0F, 17 - i, 2.0F);
+        body.addBox(-5F, -10F, -7F, 10, 16, 8, expand);
+        body.setRotationPoint(0.0F, 17 - heightOffset, 2.0F);
         leg1 = new Cube(0, 16);
-        leg1.addBox(-2F, 0.0F, -2F, 4, i, 4, f);
-        leg1.setRotationPoint(-3F, 24 - i, 7F);
+        leg1.addBox(-2F, 0.0F, -2F, 4, heightOffset, 4, expand);
+        leg1.setRotationPoint(-3F, 24 - heightOffset, 7F);
         leg2 = new Cube(0, 16);
-        leg2.addBox(-2F, 0.0F, -2F, 4, i, 4, f);
-        leg2.setRotationPoint(3F, 24 - i, 7F);
+        leg2.addBox(-2F, 0.0F, -2F, 4, heightOffset, 4, expand);
+        leg2.setRotationPoint(3F, 24 - heightOffset, 7F);
         leg3 = new Cube(0, 16);
-        leg3.addBox(-2F, 0.0F, -2F, 4, i, 4, f);
-        leg3.setRotationPoint(-3F, 24 - i, -5F);
+        leg3.addBox(-2F, 0.0F, -2F, 4, heightOffset, 4, expand);
+        leg3.setRotationPoint(-3F, 24 - heightOffset, -5F);
         leg4 = new Cube(0, 16);
-        leg4.addBox(-2F, 0.0F, -2F, 4, i, 4, f);
-        leg4.setRotationPoint(3F, 24 - i, -5F);
+        leg4.addBox(-2F, 0.0F, -2F, 4, heightOffset, 4, expand);
+        leg4.setRotationPoint(3F, 24 - heightOffset, -5F);
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         head.render(scale);
         body.render(scale);
         leg1.render(scale);
@@ -40,7 +48,7 @@ public class ModelQuadruped extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         head.xRot = headPitch / 57.29578F;
         head.yRot = headYaw / 57.29578F;
@@ -50,11 +58,4 @@ public class ModelQuadruped extends ModelBase
         leg3.xRot = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 1.4F * limbYaw;
         leg4.xRot = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw;
     }
-
-    public Cube head;
-    public Cube body;
-    public Cube leg1;
-    public Cube leg2;
-    public Cube leg3;
-    public Cube leg4;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelScorpion.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelScorpion.java
index c3c869bed..698b7635d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelScorpion.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelScorpion.java
@@ -1,6 +1,8 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
 public class ModelScorpion extends ModelBase
@@ -82,9 +84,9 @@ public class ModelScorpion extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
 
         GL11.glPushMatrix();
         GL11.glTranslatef(0, 1.4F, 0);
@@ -105,7 +107,7 @@ public class ModelScorpion extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         legLFront.setRotationAngle(0.0F, -2.618F, 0.3927F);
         legLMid.setRotationAngle(0.0F, 3.1416F, 0.3927F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelSheep.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelSheep.java
index c47acc326..b93762537 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelSheep.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelSheep.java
@@ -3,9 +3,12 @@ package net.minecraft.client.render.model;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.animal.MobSheep;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelSheep extends ModelQuadruped
 {
+    boolean isEatingAnimPlaying;
+    float headBobTime;
 
     public ModelSheep()
     {
@@ -19,9 +22,9 @@ public class ModelSheep extends ModelQuadruped
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        super.setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        super.setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         float desiredRotateAngleX = headPitch / 57.29578F;
         float desiredRotateAngleY = headYaw / 57.29578F;
         // handles head rotation
@@ -54,40 +57,36 @@ public class ModelSheep extends ModelQuadruped
             head.xRot = desiredRotateAngleX;
             head.yRot = desiredRotateAngleY;
         }
-    }
 
-    @Override
-    public void setLivingAnimations(Mob mob, float limbSwing, float limbYaw, float partialTick)
-    {
-        MobSheep entitySheep = (MobSheep) mob;
-        head.y = 6F;
-        isEatingAnimPlaying = false;
-        if(entitySheep.getIsSheepEating())
-        {
-            headBobTime = entitySheep.prevTimeSheepEating + (entitySheep.timeSheepEating - entitySheep.prevTimeSheepEating) * partialTick;
-            isEatingAnimPlaying = true;
-
-            // Move head down
-            if (headBobTime < 5)
-            {
-                head.y = 6 + (10 / 5f) * (headBobTime + 1);
-            }
-            // Hold head down and bob
-            else if (headBobTime < 35)
+        if (mob != null) {
+            MobSheep entitySheep = (MobSheep) mob;
+            head.y = 6F;
+            isEatingAnimPlaying = false;
+            if(entitySheep.getIsSheepEating())
             {
-                head.y = 16 + MathHelper.sin((headBobTime * 0.05f) * 30.5f) / 3f;
+                headBobTime = entitySheep.prevTimeSheepEating + (entitySheep.timeSheepEating - entitySheep.prevTimeSheepEating) * partialTick;
+                isEatingAnimPlaying = true;
+
+                // Move head down
+                if (headBobTime < 5)
+                {
+                    head.y = 6 + (10 / 5f) * (headBobTime + 1);
+                }
+                // Hold head down and bob
+                else if (headBobTime < 35)
+                {
+                    head.y = 16 + MathHelper.sin((headBobTime * 0.05f) * 30.5f) / 3f;
+                }
+                // Bring head back up
+                else if (headBobTime < 40)
+                {
+                    head.y = 16f - ((10 / 5f) * (headBobTime - 34));
+                }
             }
-            // Bring head back up
-            else if (headBobTime < 40)
+            else
             {
-                head.y = 16f - ((10 / 5f) * (headBobTime - 34));
+                headBobTime = 0;
             }
         }
-        else
-        {
-            headBobTime = 0;
-        }
     }
-    boolean isEatingAnimPlaying;
-    float headBobTime;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelSheepOverlay.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelSheepOverlay.java
index d8650285d..18ab1b0e9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelSheepOverlay.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelSheepOverlay.java
@@ -4,11 +4,11 @@ import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.core.Global;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.animal.MobSheep;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
 public class ModelSheepOverlay extends ModelSheep
 {
-    Mob sheep;
 
     public ModelSheepOverlay()
     {
@@ -16,25 +16,14 @@ public class ModelSheepOverlay extends ModelSheep
     }
 
     @Override
-    public void setLivingAnimations(Mob mob, float limbSwing, float limbYaw, float partialTick)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        super.setLivingAnimations(mob, limbSwing, limbYaw, partialTick);
-        this.sheep = mob;
-        float brightness = sheep.getBrightness(limbSwing);
-        if (Global.accessor.isFullbrightEnabled() || LightmapHelper.isLightmapEnabled()) brightness = 1.0f;
-        int j = ((MobSheep)sheep).getFleeceColor().blockMeta;
-        GL11.glColor3f(brightness * MobSheep.FLEECE_COLOR_TABLE[j][0], brightness * MobSheep.FLEECE_COLOR_TABLE[j][1], brightness * MobSheep.FLEECE_COLOR_TABLE[j][2]);
-
-    }
-
-    @Override
-    public void onUnload(){
-        sheep = null;
-    }
-
-    @Override
-    public void render(float limbSwing, float limbYaw, float ticksExisted, float headYaw, float headPitch, float scale)
-    {
-        super.render(limbSwing, limbYaw, ticksExisted, headYaw, headPitch, scale);
+        super.setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
+        if (mob != null) {
+            float brightness = mob.getBrightness(limbSwing);
+            if (Global.accessor.isFullbrightEnabled() || LightmapHelper.isLightmapEnabled()) brightness = 1.0f;
+            int j = ((MobSheep)mob).getFleeceColor().blockMeta;
+            GL11.glColor3f(brightness * MobSheep.FLEECE_COLOR_TABLE[j][0], brightness * MobSheep.FLEECE_COLOR_TABLE[j][1], brightness * MobSheep.FLEECE_COLOR_TABLE[j][2]);
+        }
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelSlime.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelSlime.java
index 8904a454b..0523296a3 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelSlime.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelSlime.java
@@ -1,7 +1,14 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
+import org.jetbrains.annotations.Nullable;
+
 public class ModelSlime extends ModelBase
 {
+    Cube slimeBodies;
+    Cube slimeRightEye;
+    Cube slimeLeftEye;
+    Cube slimeMouth;
 
     public ModelSlime(int i)
     {
@@ -21,14 +28,9 @@ public class ModelSlime extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
-    {
-    }
-
-    @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         slimeBodies.render(scale);
         if(slimeRightEye != null)
         {
@@ -37,9 +39,4 @@ public class ModelSlime extends ModelBase
             slimeMouth.render(scale);
         }
     }
-
-    Cube slimeBodies;
-    Cube slimeRightEye;
-    Cube slimeLeftEye;
-    Cube slimeMouth;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelSpider.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelSpider.java
index a24a75cc6..d79e9e19c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelSpider.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelSpider.java
@@ -1,6 +1,8 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelSpider extends ModelBase
 {
@@ -56,9 +58,9 @@ public class ModelSpider extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         spiderHead.render(scale);
         spiderNeck.render(scale);
         spiderBody.render(scale);
@@ -73,7 +75,7 @@ public class ModelSpider extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         spiderHead.yRot = headYaw / 57.29578F;
         spiderHead.xRot = headPitch / 57.29578F;
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelSquid.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelSquid.java
index 5b9f4a919..e17a19cd1 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelSquid.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelSquid.java
@@ -1,7 +1,12 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
+import org.jetbrains.annotations.Nullable;
+
 public class ModelSquid extends ModelBase
 {
+    Cube squidBody;
+    Cube[] squidTentacles;
 
     public ModelSquid()
     {
@@ -27,7 +32,7 @@ public class ModelSquid extends ModelBase
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
         for(int i = 0; i < squidTentacles.length; i++)
         {
@@ -37,9 +42,9 @@ public class ModelSquid extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         squidBody.render(scale);
         for(int i = 0; i < squidTentacles.length; i++)
         {
@@ -47,7 +52,4 @@ public class ModelSquid extends ModelBase
         }
 
     }
-
-    Cube squidBody;
-    Cube squidTentacles[];
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelWolf.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelWolf.java
index 9158dc538..235e47e49 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelWolf.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelWolf.java
@@ -5,11 +5,24 @@ import net.minecraft.core.Global;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.animal.MobWolf;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
 public class ModelWolf extends ModelBase
 {
 
+    public Cube wolfHeadMain;
+    public Cube wolfBody;
+    public Cube wolfLeg1;
+    public Cube wolfLeg2;
+    public Cube wolfLeg3;
+    public Cube wolfLeg4;
+    Cube wolfRightEar;
+    Cube wolfLeftEar;
+    Cube wolfSnout;
+    Cube wolfTail;
+    Cube wolfMane;
+
     public ModelWolf(float expandAmount)
     {
         float f1 = 13.5F;
@@ -49,10 +62,9 @@ public class ModelWolf extends ModelBase
     }
 
     @Override
-    public void render(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
+    public void render(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        super.render(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
-        setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+        setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
         wolfHeadMain.renderWithRotation(scale);
         wolfBody.render(scale);
         wolfLeg1.render(scale);
@@ -67,17 +79,18 @@ public class ModelWolf extends ModelBase
     }
 
     @Override
-    public void setLivingAnimations(Mob mob, float limbSwing, float limbYaw, float partialTick)
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick)
     {
-        MobWolf entitywolf = (MobWolf) mob;
-        if(entitywolf.isWolfAngry())
+        if (mob == null) return;
+        MobWolf wolf = (MobWolf) mob;
+        if(wolf.isWolfAngry())
         {
             wolfTail.yRot = 0.0F;
         } else
         {
             wolfTail.yRot = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw;
         }
-        if(entitywolf.isWolfSitting())
+        if(wolf.isWolfSitting())
         {
             wolfMane.setRotationPoint(-1F, 16F, -3F);
             wolfMane.xRot = 1.256637F;
@@ -109,34 +122,30 @@ public class ModelWolf extends ModelBase
             wolfLeg3.xRot = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 1.4F * limbYaw;
             wolfLeg4.xRot = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw;
         }
-        float f3 = entitywolf.getInterestedAngle(partialTick) + entitywolf.getShakeAngle(partialTick, 0.0F);
+        float f3 = wolf.getInterestedAngle(partialTick) + wolf.getShakeAngle(partialTick, 0.0F);
         wolfHeadMain.zRot = f3;
         wolfRightEar.zRot = f3;
         wolfLeftEar.zRot = f3;
         wolfSnout.zRot = f3;
-        wolfMane.zRot = entitywolf.getShakeAngle(partialTick, -0.08F);
-        wolfBody.zRot = entitywolf.getShakeAngle(partialTick, -0.16F);
-        wolfTail.zRot = entitywolf.getShakeAngle(partialTick, -0.2F);
+        wolfMane.zRot = wolf.getShakeAngle(partialTick, -0.08F);
+        wolfBody.zRot = wolf.getShakeAngle(partialTick, -0.16F);
+        wolfTail.zRot = wolf.getShakeAngle(partialTick, -0.2F);
 
-        if(entitywolf.getWolfShaking())
+        if(wolf.getWolfShaking())
         {
             float brightness = 1.0f;
             if(LightmapHelper.isLightmapEnabled()) {
-            	LightmapHelper.setLightmapCoord(entitywolf.getLightmapCoord(partialTick));
+            	LightmapHelper.setLightmapCoord(wolf.getLightmapCoord(partialTick));
             }else if(Global.accessor.isFullbrightEnabled()) {
-            	
+
             }else {
-            	brightness = entitywolf.getBrightness(partialTick);
+            	brightness = wolf.getBrightness(partialTick);
             }
-            float f4 = brightness * entitywolf.getShadingWhileShaking(partialTick);
+            float f4 = brightness * wolf.getShadingWhileShaking(partialTick);
             GL11.glColor3f(f4, f4, f4);
         }
-    }
 
-    @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
-    {
-        super.setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
+
         wolfHeadMain.xRot = headPitch / 57.29578F;
         wolfHeadMain.yRot = headYaw / 57.29578F;
         wolfRightEar.yRot = wolfHeadMain.yRot;
@@ -147,16 +156,4 @@ public class ModelWolf extends ModelBase
         wolfSnout.xRot = wolfHeadMain.xRot;
         wolfTail.xRot = limbPitch;
     }
-
-    public Cube wolfHeadMain;
-    public Cube wolfBody;
-    public Cube wolfLeg1;
-    public Cube wolfLeg2;
-    public Cube wolfLeg3;
-    public Cube wolfLeg4;
-    Cube wolfRightEar;
-    Cube wolfLeftEar;
-    Cube wolfSnout;
-    Cube wolfTail;
-    Cube wolfMane;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelZombie.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelZombie.java
index 4af4cfe4f..75b7c6de8 100644
--- a/game/client/src/main/java/net/minecraft/client/render/model/ModelZombie.java
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelZombie.java
@@ -1,6 +1,8 @@
 package net.minecraft.client.render.model;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 public class ModelZombie extends ModelBiped {
     public ModelZombie() {
@@ -11,61 +13,55 @@ public class ModelZombie extends ModelBiped {
         this.parts(var1, 0.0F);
     }
 
-    public void parts(float var1, float var2) {
+    public void parts(float expansion, float var2) {
         this.holdingLeftHand = false;
         this.holdingRightHand = false;
         this.sneaking = false;
         this.cloak = new Cube(0, 0);
-        this.cloak.addBox(-5.0F, 0.0F, -1.0F, 10, 16, 1, var1);
+        this.cloak.addBox(-5.0F, 0.0F, -1.0F, 10, 16, 1, expansion);
         this.ear = new Cube(24, 0);
-        this.ear.addBox(-4.0F, -7.0F, -1.0F, 7, 7, 1, var1);
+        this.ear.addBox(-4.0F, -7.0F, -1.0F, 7, 7, 1, expansion);
         this.head = new Cube(0, 0);
-        this.head.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, var1);
+        this.head.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, expansion);
         this.head.setRotationPoint(0.0F, 0.0F + var2, 0.0F);
         this.hair = new Cube(32, 0);
-        this.hair.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, var1 + 0.5F);
+        this.hair.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, expansion + 0.5F);
         this.hair.setRotationPoint(0.0F, 0.0F + var2, 0.0F);
         this.body = new Cube(16, 16);
-        this.body.addBox(-4.0F, 0.0F, -2.0F, 8, 12, 4, var1);
+        this.body.addBox(-4.0F, 0.0F, -2.0F, 8, 12, 4, expansion);
         this.body.setRotationPoint(0.0F, 0.0F + var2, 0.0F);
         this.armRight = new Cube(40, 16);
-        this.armRight.addBox(-3.0F, -2.0F, -2.0F, 4, 12, 4, var1);
+        this.armRight.addBox(-3.0F, -2.0F, -2.0F, 4, 12, 4, expansion);
         this.armRight.setRotationPoint(-5.0F, 2.0F + var2, 0.0F);
         this.armLeft = new Cube(40, 16);
         this.armLeft.mirror = true;
-        this.armLeft.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, var1);
+        this.armLeft.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, expansion);
         this.armLeft.setRotationPoint(5.0F, 2.0F + var2, 0.0F);
         this.legRight = new Cube(0, 16);
-        this.legRight.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, var1);
+        this.legRight.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, expansion);
         this.legRight.setRotationPoint(-2.0F, 12.0F + var2, 0.0F);
         this.legLeft = new Cube(0, 16);
         this.legLeft.mirror = true;
-        this.legLeft.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, var1);
+        this.legLeft.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, expansion);
         this.legLeft.setRotationPoint(2.0F, 12.0F + var2, 0.0F);
     }
 
     @Override
-    public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale) {
-        super.setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
-        float var7 = MathHelper.sin(this.onGround * 3.1415927F);
-        float var8 = MathHelper.sin((1.0F - (1.0F - this.onGround) * (1.0F - this.onGround)) * 3.1415927F);
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick) {
+        super.setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
+        float var7 = MathHelper.sin(this.swingProgress * 3.1415927F);
+        float var8 = MathHelper.sin((1.0F - (1.0F - this.swingProgress) * (1.0F - this.swingProgress)) * 3.1415927F);
         this.armRight.zRot = 0.0F;
         this.armLeft.zRot = 0.0F;
         this.armRight.yRot = -(0.1F - var7 * 0.6F);
         this.armLeft.yRot = 0.1F - var7 * 0.6F;
         this.armRight.xRot = -1.5707964F;
         this.armLeft.xRot = -1.5707964F;
-        Cube var10000 = this.armRight;
-        var10000.xRot -= var7 * 1.2F - var8 * 0.4F;
-        var10000 = this.armLeft;
-        var10000.xRot -= var7 * 1.2F - var8 * 0.4F;
-        var10000 = this.armRight;
-        var10000.zRot += MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
-        var10000 = this.armLeft;
-        var10000.zRot -= MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
-        var10000 = this.armRight;
-        var10000.xRot += MathHelper.sin(limbPitch * 0.067F) * 0.05F;
-        var10000 = this.armLeft;
-        var10000.xRot -= MathHelper.sin(limbPitch * 0.067F) * 0.05F;
+        this.armRight.xRot -= var7 * 1.2F - var8 * 0.4F;
+        this.armLeft.xRot -= var7 * 1.2F - var8 * 0.4F;
+        this.armRight.zRot += MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
+        this.armLeft.zRot -= MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
+        this.armRight.xRot += MathHelper.sin(limbPitch * 0.067F) * 0.05F;
+        this.armLeft.xRot -= MathHelper.sin(limbPitch * 0.067F) * 0.05F;
     }
 }
\ No newline at end of file
diff --git a/game/client/src/main/java/net/minecraft/client/render/model/ModelZombiePigman.java b/game/client/src/main/java/net/minecraft/client/render/model/ModelZombiePigman.java
new file mode 100644
index 000000000..9473fced1
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/model/ModelZombiePigman.java
@@ -0,0 +1,68 @@
+package net.minecraft.client.render.model;
+
+import net.minecraft.core.entity.Mob;
+import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
+
+public class ModelZombiePigman extends ModelPigman {
+    public ModelZombiePigman() {
+        this(0.0F);
+    }
+
+    public ModelZombiePigman(float var1) {
+        this.parts(var1, 0.0F);
+    }
+
+    public void parts(float var1, float var2) {
+        this.holdingLeftHand = false;
+        this.holdingRightHand = false;
+        this.sneaking = false;
+        this.cloak = new Cube(0, 0);
+        this.cloak.addBox(-5.0F, 0.0F, -1.0F, 10, 16, 1, var1);
+        this.ear = new Cube(24, 0);
+        this.ear.addBox(-4.0F, -7.0F, -1.0F, 7, 7, 1, var1);
+        this.head = new Cube(0, 0);
+        this.head.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, var1);
+        this.head.setRotationPoint(0.0F, 0.0F + var2, 0.0F);
+        this.hair = new Cube(32, 0);
+        this.hair.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, var1 + 0.5F);
+        this.hair.setRotationPoint(0.0F, 0.0F + var2, 0.0F);
+        this.body = new Cube(16, 16);
+        this.body.addBox(-4.0F, 0.0F, -2.0F, 8, 12, 4, var1);
+        this.body.setRotationPoint(0.0F, 0.0F + var2, 0.0F);
+        this.armRight = new Cube(40, 16);
+        this.armRight.addBox(-3.0F, -2.0F, -2.0F, 4, 12, 4, var1);
+        this.armRight.setRotationPoint(-5.0F, 2.0F + var2, 0.0F);
+        this.armLeft = new Cube(40, 16);
+        this.armLeft.mirror = true;
+        this.armLeft.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, var1);
+        this.armLeft.setRotationPoint(5.0F, 2.0F + var2, 0.0F);
+        this.legRight = new Cube(0, 16);
+        this.legRight.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, var1);
+        this.legRight.setRotationPoint(-2.0F, 12.0F + var2, 0.0F);
+        this.legLeft = new Cube(0, 16);
+        this.legLeft.mirror = true;
+        this.legLeft.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, var1);
+        this.legLeft.setRotationPoint(2.0F, 12.0F + var2, 0.0F);
+    }
+
+    @Override
+    public void setupAnimation(@Nullable Mob mob, float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale, float partialTick) {
+        super.setupAnimation(mob, limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale, partialTick);
+        float var7 = MathHelper.sin(this.swingProgress * 3.1415927F);
+        float var8 = MathHelper.sin((1.0F - (1.0F - this.swingProgress) * (1.0F - this.swingProgress)) * 3.1415927F);
+        this.armRight.zRot = 0.0F;
+        this.armLeft.zRot = 0.0F;
+        this.armRight.yRot = -(0.1F - var7 * 0.6F);
+        this.armLeft.yRot = 0.1F - var7 * 0.6F;
+        this.armRight.xRot = -1.5707964F;
+        this.armLeft.xRot = -1.5707964F;
+        this.armRight.xRot -= var7 * 1.2F - var8 * 0.4F;
+        this.armLeft.xRot -= var7 * 1.2F - var8 * 0.4F;
+        this.armRight.zRot += MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
+        this.armLeft.zRot -= MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
+        this.armRight.xRot += MathHelper.sin(limbPitch * 0.067F) * 0.05F;
+        this.armLeft.xRot -= MathHelper.sin(limbPitch * 0.067F) * 0.05F;
+    }
+
+}
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 e7d7fdca4..3e6a423ea 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
@@ -4,9 +4,9 @@ import java.util.ArrayList;
 import java.util.List;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.world.WorldSource;
 import org.lwjgl.opengl.GL11;
 
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.camera.ICamera;
 import net.minecraft.client.render.culling.CameraFrustum;
@@ -98,13 +98,11 @@ public abstract class ChunkRenderer
     
     public abstract void rebuild();
     
-    public boolean renderBlock(Tessellator tessellator, RenderBlocks renderBlocks, BlockModel<?> model, int x, int y, int z) {
+    public boolean renderBlock(Tessellator tessellator, WorldSource worldSource, BlockModel<?> model, int x, int y, int z) {
     	boolean rendered = false;
-		rendered |= model.render(tessellator, x, y, z);
+		rendered |= model.render(tessellator, worldSource, x, y, z);
 		if(model.hasOverbright()) {
-			renderBlocks.overbright = true;
-			rendered |= model.render(tessellator, x, y, z);
-			renderBlocks.overbright = false;
+			rendered |= model.renderOverbright(tessellator, worldSource, x, y, z);
 		}
 		return rendered;
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererLegacy.java b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererLegacy.java
index b203a5574..9691b5268 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererLegacy.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererLegacy.java
@@ -9,9 +9,8 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.TileEntity;
 import org.lwjgl.opengl.GL11;
 
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.world.World;
@@ -42,8 +41,6 @@ public class ChunkRendererLegacy extends ChunkRenderer {
         renderableBlockEntities.clear();
         final int cacheRadius = 1;
         final ChunkCache chunkcache = new ChunkCache(world, minX - cacheRadius, minY - cacheRadius, minZ - cacheRadius, maxX + cacheRadius, maxY + cacheRadius, maxZ + cacheRadius);
-        final RenderBlocks renderblocks = new RenderBlocks(chunkcache);
-        BlockModel.setRenderBlocks(renderblocks);
         int renderPass = 0;
         Tessellator tessellator = Tessellator.instance;
         do
@@ -82,8 +79,8 @@ public class ChunkRendererLegacy extends ChunkRenderer {
                             }
                         }
                         if(renderPass == 0 && Blocks.isEntityTile[blockId]) {
-                            final TileEntity tileentity = chunkcache.getBlockEntity(x, y, z);
-                            if(BlockEntityRenderDispatcher.instance.hasRenderer(tileentity)) {
+                            final TileEntity tileentity = chunkcache.getTileEntity(x, y, z);
+                            if(TileEntityRenderDispatcher.instance.hasRenderer(tileentity)) {
                                 renderableBlockEntities.add(tileentity);
                             }
                         }
@@ -98,7 +95,7 @@ public class ChunkRendererLegacy extends ChunkRenderer {
                         		tessellator.setLightmapCoord(LightmapHelper.getLightmapCoord(15, 0));
                         	}
 
-    						hasRenderedBlock |= renderBlock(tessellator, renderblocks, model, x, y, z);
+    						hasRenderedBlock |= renderBlock(tessellator, world, model, x, y, z);
                         }
                     }
                 }
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 50ed053cb..183ece731 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
@@ -4,9 +4,8 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.culling.CameraFrustum;
@@ -61,9 +60,7 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
 		
 		final int cacheRadius = 1;
 		final ChunkCache chunkCache = new ChunkCache(world, minX - cacheRadius, minY - cacheRadius, minZ - cacheRadius, maxX + cacheRadius, maxY + cacheRadius, maxZ + cacheRadius);
-		final RenderBlocks renderBlocks = new RenderBlocks(chunkCache);
-		BlockModel.setRenderBlocks(renderBlocks);
-		
+
 		TessellatorStandard tessellator = (TessellatorStandard) Tessellator.instance;
 		for(int renderPass = 0; renderPass < renderPassCount; renderPass++) {
 			boolean needsMoreRenderPasses = false;
@@ -93,8 +90,8 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
 							tessellator.setTextureUV(0.0, 0.0);
 						}
 						if(renderPass == 0 && Blocks.isEntityTile[blockId]) {
-							final TileEntity tileentity = chunkCache.getBlockEntity(x, y, z);
-							if(BlockEntityRenderDispatcher.instance.hasRenderer(tileentity)) {
+							final TileEntity tileentity = chunkCache.getTileEntity(x, y, z);
+							if(TileEntityRenderDispatcher.instance.hasRenderer(tileentity)) {
 								renderableBlockEntities.add(tileentity);
 							}
 						}
@@ -106,7 +103,7 @@ public class ChunkRendererMultiDraw extends ChunkRenderer {
 							continue;
 						}
 						
-						hasRenderedBlock |= renderBlock(tessellator, renderBlocks, model, x, y, z);
+						hasRenderedBlock |= renderBlock(tessellator, world, model, x, y, z);
 					}
 				}
 			}
diff --git a/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java b/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
index 51ba2a7a7..b24352f5f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
+++ b/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
@@ -4,6 +4,8 @@ import com.mojang.logging.LogUtils;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.keyboard.KeyboardLayout;
 import net.minecraft.client.render.Font;
+import net.minecraft.client.render.block.model.BlockModelDispatcher;
+import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.sound.SoundRepository;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -97,7 +99,8 @@ public class TexturePackList
 		}
 		mc.textureManager.updateDynamicTextures(false);
 		SoundRepository.reload();
-
+		BlockModelDispatcher.getInstance().reload();
+		ItemModelDispatcher.getInstance().reload();
 		KeyboardLayout.defaultLayout = new KeyboardLayout();
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRenderer.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRenderer.java
similarity index 78%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRenderer.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRenderer.java
index a85f63e74..4d41ee199 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRenderer.java
@@ -1,8 +1,8 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
 import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.world.World;
@@ -23,7 +23,7 @@ public abstract class TileEntityRenderer<T extends TileEntity>
         textureManager.bindTexture(textureManager.loadTexture(texturePath));
     }
 
-    public void setRenderDispatcher(BlockEntityRenderDispatcher renderDispatcher)
+    public void setRenderDispatcher(TileEntityRenderDispatcher renderDispatcher)
     {
         this.renderDispatcher = renderDispatcher;
     }
@@ -38,5 +38,5 @@ public abstract class TileEntityRenderer<T extends TileEntity>
         return renderDispatcher.getFont();
     }
 
-    protected BlockEntityRenderDispatcher renderDispatcher;
+    protected TileEntityRenderDispatcher renderDispatcher;
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererFlag.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlag.java
similarity index 98%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererFlag.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlag.java
index e157aa28c..3e5d6e048 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererFlag.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlag.java
@@ -1,4 +1,4 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.FlagRenderer;
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererFlowerJar.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlowerJar.java
similarity index 52%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererFlowerJar.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlowerJar.java
index e14d148ce..739e5400a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererFlowerJar.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlowerJar.java
@@ -1,18 +1,17 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
+import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.RenderBlocks;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.TileEntityFlowerJar;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
 import org.lwjgl.opengl.GL11;
 
 import static org.lwjgl.opengl.GL11.GL_BLEND;
@@ -20,12 +19,7 @@ import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
 import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
 
 public class TileEntityRendererFlowerJar extends TileEntityRenderer<TileEntityFlowerJar> {
-    private RenderBlocks renderBlocks;
-    @Override
-    public void onWorldChanged(World world)
-    {
-        renderBlocks = new RenderBlocks(world);
-    }
+
     @Override
     public void doRender(Tessellator tessellator, TileEntityFlowerJar tileEntity, double x, double y, double z, float renderPartialTicks) {
         GL11.glPushMatrix();
@@ -36,29 +30,19 @@ public class TileEntityRendererFlowerJar extends TileEntityRenderer<TileEntityFl
             float scaleValue = 0.75F;
             GL11.glScalef(scaleValue, scaleValue, scaleValue);
             GL11.glTranslatef(0.66F, 0.75F, 0.66F);
-            float lightLevel = renderBlocks.getBlockBrightness(tileEntity.worldObj, tileEntity.x, tileEntity.y, tileEntity.z);
-            if (Global.accessor.isFullbrightEnabled()) lightLevel = 1.0f;
-            BlockModel.setRenderBlocks(renderBlocks);
-            Integer lmc = null;
-            if (LightmapHelper.isLightmapEnabled()){
-                if (Global.accessor.isFullbrightEnabled()){
-                    lmc = LightmapHelper.getOverbrightLightmapCoord(tileEntity.worldObj.getSavedLightValue(LightLayer.Sky, tileEntity.x, tileEntity.y, tileEntity.z));
-                } else {
-                    lmc = tileEntity.worldObj.getLightmapCoord(tileEntity.x, tileEntity.y, tileEntity.z, 0);
-                }
-                lightLevel = 1f;
-            }
             GL11.glEnable(GL_BLEND);
             GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-            if (LightmapHelper.isLightmapEnabled()) { // TODO remove these awful hardcoded fixes
-                Lighting.enableInventoryLight();
-            }
-            BlockModelDispatcher.getInstance().getDispatch(block).renderBlockOnInventory(tessellator, tileEntity.flowerData, lightLevel, lmc);
+            Lighting.disable();
+            BlockModelDispatcher.getInstance().getDispatch(block).renderStandalone(tessellator, tileEntity.flowerData, getBlockBrightness(tileEntity.worldObj, tileEntity.x, tileEntity.y, tileEntity.z), 1f, tileEntity.worldObj.getLightmapCoord(tileEntity.x, tileEntity.y, tileEntity.z, Minecraft.getMinecraft().isFullbrightEnabled() ? 15 : 0));
+            Lighting.enableLight();
             GL11.glDisable(GL_BLEND);
-            if (LightmapHelper.isLightmapEnabled()) { // This one too
-                Lighting.disable();
-            }
         }
         GL11.glPopMatrix();
     }
+
+    public float getBlockBrightness(WorldSource blockAccess, int x, int y, int z)
+    {
+        if (Minecraft.getMinecraft().fullbright || LightmapHelper.isLightmapEnabled()) return 1.0f;
+        return blockAccess.getBrightness(x, y, z, 0);
+    }
 }
\ No newline at end of file
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererJarButterfly.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererJarButterfly.java
similarity index 94%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererJarButterfly.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererJarButterfly.java
index 3d54a0304..3f95b2e7f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererJarButterfly.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererJarButterfly.java
@@ -1,4 +1,4 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
 import net.minecraft.client.render.entity.MobRendererButterfly;
 import net.minecraft.client.render.tessellator.Tessellator;
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMeshGold.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMeshGold.java
similarity index 51%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMeshGold.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMeshGold.java
index 3cac4a5a8..29862758c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMeshGold.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMeshGold.java
@@ -1,24 +1,17 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
 import net.minecraft.core.block.entity.TileEntityMeshGold;
-import net.minecraft.core.entity.EntityItem;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.EntityRenderDispatcher;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.Global;
 import net.minecraft.core.util.helper.MathHelper;
-import java.util.Random;
 import org.lwjgl.opengl.GL12;
+import org.useless.dragonfly.DisplayPos;
 
 public class TileEntityRendererMeshGold extends TileEntityRenderer<TileEntityMeshGold> {
-	
-	public EntityItem renderEntity = new EntityItem(null);
-
-    private Random rand = new Random();
 
     @Override
     public void doRender(Tessellator tessellator, TileEntityMeshGold tileEntity, double x, double y, double z, float renderPartialTicks) {
@@ -26,25 +19,13 @@ public class TileEntityRendererMeshGold extends TileEntityRenderer<TileEntityMes
         GL11.glPushMatrix();
 
         final float bobbingOffset = MathHelper.sin((tileEntity.ticksRan + renderPartialTicks) / 10F) * 0.1F + 0.1F;
-        final float f3 = (float) Math.toDegrees(((tileEntity.ticksRan + renderPartialTicks) / 20F));
+        final float yaw = (float) Math.toDegrees(((tileEntity.ticksRan + renderPartialTicks) / 20F));
 
         GL11.glTranslatef((float) x + 0.5f, (float) y + bobbingOffset + 0.25f, (float) z + 0.5f);
-        
-        renderEntity.world = tileEntity.worldObj;
-        renderEntity.x = renderEntity.xo = tileEntity.x + 0.5;
-        renderEntity.y = renderEntity.yo = tileEntity.y + 0.5;
-        renderEntity.z = renderEntity.zo = tileEntity.z + 0.5;
-        
+
         float lightLevel = Minecraft.getMinecraft().currentWorld.getLightBrightness(tileEntity.x, tileEntity.y, tileEntity.z);
         if (Global.accessor.isFullbrightEnabled()) lightLevel = 1.0f;
-        BlockModel.setRenderBlocks(EntityRenderDispatcher.instance.itemRenderer.renderBlocksInstance);
-        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
-        GL11.glEnable(GL11.GL_BLEND);
-        ItemModelDispatcher.getInstance().getDispatch(tileEntity.filterItem).renderAsItemEntity(Tessellator.instance, renderEntity, rand, tileEntity.filterItem, 1, f3, lightLevel, renderPartialTicks);
-        GL11.glDisable(GL11.GL_BLEND);
-        GL11.glDisable(GL12.GL_RESCALE_NORMAL);
+        ItemModelDispatcher.getInstance().getDispatch(tileEntity.filterItem).renderItemEntity(tessellator, tileEntity.filterItem, Minecraft.getMinecraft().gameSettings.items3D.value, 1, tileEntity.ticksRan, yaw, lightLevel, 1f, renderPartialTicks);
         GL11.glPopMatrix();
-        
-        renderEntity.world = null;
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMobSpawner.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMobSpawner.java
similarity index 97%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMobSpawner.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMobSpawner.java
index 65c0421d2..90b124037 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMobSpawner.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMobSpawner.java
@@ -1,4 +1,4 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMovingPiston.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMovingPiston.java
similarity index 58%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMovingPiston.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMovingPiston.java
index 12cbe6d64..5f981884b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererMovingPiston.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererMovingPiston.java
@@ -1,10 +1,8 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.BlockEntityRenderDispatcher;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.Lighting;
-import net.minecraft.client.render.RenderBlocks;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.block.model.BlockModelPiston;
 import net.minecraft.client.render.block.model.BlockModelPistonHead;
@@ -17,16 +15,13 @@ import net.minecraft.core.block.piston.BlockLogicPistonBaseSteel;
 import net.minecraft.core.block.piston.BlockLogicPistonHead;
 import net.minecraft.core.block.piston.TileEntityMovingPistonBlock;
 import net.minecraft.core.world.BlocksContainer;
-import net.minecraft.core.world.World;
 import org.lwjgl.opengl.GL11;
 
 public class TileEntityRendererMovingPiston extends TileEntityRenderer<TileEntityMovingPistonBlock>
 {
-    private RenderBlocks renderBlocks;
     private final Minecraft mc;
 
     private BlocksContainer container = null;
-    private RenderBlocks containerRenderBlock = null;
 
     public TileEntityRendererMovingPiston()
     {
@@ -34,21 +29,14 @@ public class TileEntityRendererMovingPiston extends TileEntityRenderer<TileEntit
     }
 
     @Override
-	public void onWorldChanged(World world)
-    {
-        renderBlocks = new RenderBlocks(world);
-    }
-
-    @Override
-	public void doRender(Tessellator tessellator, TileEntityMovingPistonBlock blockEntity, double x, double y, double z,
+	public void doRender(Tessellator tessellator, TileEntityMovingPistonBlock tileEntity, double x, double y, double z,
                          float partialTick)
     {
-        Block<?> block = Blocks.getBlock(blockEntity.getMovedId());
-        if(block != null && blockEntity.getProgress(partialTick) < 1.0F)
+        Block<?> block = Blocks.getBlock(tileEntity.getMovedId());
+        if(block != null && tileEntity.getProgress(partialTick) < 1.0F)
         {
-            if (container == null || container.world != blockEntity.worldObj) {
-                container = new BlocksContainer(blockEntity.worldObj);
-                containerRenderBlock = new RenderBlocks(container);
+            if (container == null || container.world != tileEntity.worldObj) {
+                container = new BlocksContainer(tileEntity.worldObj);
             }
             TextureRegistry.blockAtlas.bind();
             Lighting.disable();
@@ -63,34 +51,31 @@ public class TileEntityRendererMovingPiston extends TileEntityRenderer<TileEntit
                 GL11.glShadeModel(GL11.GL_FLAT);
             }
             tessellator.startDrawingQuads();
-            tessellator.setTranslation(((float)x - (float)blockEntity.x) + blockEntity.getXOff(partialTick), ((float)y - (float)blockEntity.y) + blockEntity.getYOff(partialTick), ((float)z - (float)blockEntity.z) + blockEntity.getZOff(partialTick));
-            if(Block.hasLogicClass(block, BlockLogicPistonHead.class) && blockEntity.getProgress(partialTick) < 0.5F)
+            tessellator.setTranslation(((float)x - (float)tileEntity.x) + tileEntity.getXOff(partialTick), ((float)y - (float)tileEntity.y) + tileEntity.getYOff(partialTick), ((float)z - (float)tileEntity.z) + tileEntity.getZOff(partialTick));
+            if(Block.hasLogicClass(block, BlockLogicPistonHead.class) && tileEntity.getProgress(partialTick) < 0.5F)
             {
-                BlockModel.setRenderBlocks(renderBlocks);
-                ((BlockModelPistonHead)BlockModelDispatcher.getInstance().getDispatch(block)).renderPistonHeadNoCulling(tessellator, (Block<BlockLogicPistonHead>) block, blockEntity.x, blockEntity.y, blockEntity.z, false);
+                ((BlockModelPistonHead)BlockModelDispatcher.getInstance().getDispatch(block)).renderPistonHeadNoCulling(tessellator, tileEntity.worldObj, (Block<BlockLogicPistonHead>) block, tileEntity.x, tileEntity.y, tileEntity.z, false);
             } else
-            if(blockEntity.isSourcePiston() && !blockEntity.isExtending())
+            if(tileEntity.isSourcePiston() && !tileEntity.isExtending())
             {
                 BlockModelPiston<?> pistonBase = (BlockModelPiston<?>) BlockModelDispatcher.getInstance().getDispatch(block);
-                BlockModel.setRenderBlocks(renderBlocks);
                 if (Block.hasLogicClass(block, BlockLogicPistonBaseSteel.class)) { // Todo remove this terrible hardcoded render code
                     BlockModelPistonHead blockModelPistonHead = ((BlockModelPistonHead) BlockModelDispatcher.getInstance().getDispatch(Blocks.PISTON_HEAD_STEEL));
                     blockModelPistonHead.setFaceTextureOverride(pistonBase.getFaceTexture());
-                    blockModelPistonHead.renderPistonHeadNoCulling(tessellator, Blocks.PISTON_HEAD_STEEL, blockEntity.x, blockEntity.y, blockEntity.z, blockEntity.getProgress(partialTick) < 0.5F);
+                    blockModelPistonHead.renderPistonHeadNoCulling(tessellator, tileEntity.worldObj, Blocks.PISTON_HEAD_STEEL, tileEntity.x, tileEntity.y, tileEntity.z, tileEntity.getProgress(partialTick) < 0.5F);
                     blockModelPistonHead.setFaceTextureOverride(null);
                 } else {
                     BlockModelPistonHead blockModelPistonHead = ((BlockModelPistonHead) BlockModelDispatcher.getInstance().getDispatch(Blocks.PISTON_HEAD));
                     blockModelPistonHead.setFaceTextureOverride(pistonBase.getFaceTexture());
-                    blockModelPistonHead.renderPistonHeadNoCulling(tessellator, Blocks.PISTON_HEAD, blockEntity.x, blockEntity.y, blockEntity.z, blockEntity.getProgress(partialTick) < 0.5F);
+                    blockModelPistonHead.renderPistonHeadNoCulling(tessellator, tileEntity.worldObj, Blocks.PISTON_HEAD, tileEntity.x, tileEntity.y, tileEntity.z, tileEntity.getProgress(partialTick) < 0.5F);
                     blockModelPistonHead.setFaceTextureOverride(null);
                 }
-                tessellator.setTranslation((float)x - (float)blockEntity.x, (float)y - (float)blockEntity.y, (float)z - (float)blockEntity.z);
-                pistonBase.renderHeadless(tessellator, blockEntity.x, blockEntity.y, blockEntity.z);
+                tessellator.setTranslation((float)x - (float)tileEntity.x, (float)y - (float)tileEntity.y, (float)z - (float)tileEntity.z);
+                pistonBase.renderHeadless(tessellator, tileEntity.worldObj, tileEntity.x, tileEntity.y, tileEntity.z);
             } else
             {
-                BlockModel.setRenderBlocks(containerRenderBlock);
-                container.setBlock(blockEntity.x, blockEntity.y, blockEntity.z, block.id(), blockEntity.getMovedData(), blockEntity.getMovedEntity());
-                BlockModelDispatcher.getInstance().getDispatch(block).renderNoCulling(tessellator, blockEntity.x, blockEntity.y, blockEntity.z);
+                container.setBlock(tileEntity.x, tileEntity.y, tileEntity.z, block.id(), tileEntity.getMovedData(), tileEntity.getMovedEntity());
+                BlockModelDispatcher.getInstance().getDispatch(block).renderNoCulling(tessellator, container, tileEntity.x, tileEntity.y, tileEntity.z);
                 container.setLightReferenceEntity(null);
                 container.clear();
             }
@@ -99,11 +84,11 @@ public class TileEntityRendererMovingPiston extends TileEntityRenderer<TileEntit
 
             Lighting.enableLight();
 
-            TileEntity movedEntity = blockEntity.getMovedEntity();
-            TileEntityRenderer<TileEntity> renderer = BlockEntityRenderDispatcher.instance.getRenderer(movedEntity);
+            TileEntity movedEntity = tileEntity.getMovedEntity();
+            TileEntityRenderer<TileEntity> renderer = TileEntityRenderDispatcher.instance.getRenderer(movedEntity);
             if (renderer != null) {
                 GL11.glPushMatrix();
-                GL11.glTranslatef(blockEntity.getXOff(partialTick), blockEntity.getYOff(partialTick), blockEntity.getZOff(partialTick));
+                GL11.glTranslatef(tileEntity.getXOff(partialTick), tileEntity.getYOff(partialTick), tileEntity.getZOff(partialTick));
                 renderer.doRender(tessellator, movedEntity, x, y, z, partialTick);
                 GL11.glPopMatrix();
             }
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererSign.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
similarity index 56%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererSign.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
index d9278d4a5..7696d6599 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererSign.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
@@ -1,4 +1,4 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.Font;
@@ -10,13 +10,13 @@ import net.minecraft.client.render.model.ModelZombie;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
-import net.minecraft.core.block.Block;
-import net.minecraft.core.block.Blocks;
+import net.minecraft.client.util.helper.Colors;
+import net.minecraft.core.block.BlockLogicSign;
 import net.minecraft.core.block.entity.TileEntitySign;
 import net.minecraft.core.enums.EnumSignPicture;
-import net.minecraft.client.util.helper.Colors;
 import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
 
 public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign>
 {
@@ -24,69 +24,62 @@ public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign>
     private final Minecraft mc = Minecraft.getMinecraft();
     private final ModelSign modelSign;
 
-
     public TileEntityRendererSign()
     {
         modelSign = new ModelSign();
     }
 
-    public void renderTileEntitySignAt(TileEntitySign tileEntity, double d, double d1, double d2,
-                                       float f)
+     @Override
+	public void doRender(Tessellator tessellator, TileEntitySign tileEntity, double x, double y, double z,
+                         float partialTick)
     {
-        Block<?> block = tileEntity.getBlock();
+        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
         GL11.glPushMatrix();
-        float scale = 0.6666667F;
-        if(block == Blocks.SIGN_POST_PLANKS_OAK)
-        {
-            GL11.glTranslatef((float)d + 0.5F, (float)d1 + 0.75F * scale, (float)d2 + 0.5F);
-            float f2 = (float)(tileEntity.getBlockMeta() * 360) / 16F;
-            GL11.glRotatef(-f2, 0.0F, 1.0F, 0.0F);
+        float scale = 2/3f;
+        GL11.glTranslatef((float)x + 0.5F, (float)y + 0.75F * scale, (float)z + 0.5F);
+        if (((BlockLogicSign) tileEntity.getBlock().getLogic()).isFreeStanding) {
+            float angle = (float)(tileEntity.getBlockMeta() * 360) / 16F;
+            GL11.glRotatef(-angle, 0.0F, 1.0F, 0.0F);
             modelSign.signStick.visible = true;
-        }
-        else
-        {
-            int i = tileEntity.getBlockMeta();
-            float f3 = 0.0F;
-            if(i == 2)
-            {
-                f3 = 180F;
-            }
-            if(i == 4)
-            {
-                f3 = 90F;
-            }
-            if(i == 5)
-            {
-                f3 = -90F;
+        } else {
+            float angle;
+            switch (tileEntity.getBlockMeta()) {
+                case BlockLogicSign.SIDE_NORTH:
+                    angle = 180F;
+                    break;
+                case BlockLogicSign.SIDE_SOUTH:
+                    angle = 0.0F;
+                    break;
+                case BlockLogicSign.SIDE_WEST:
+                    angle = 90F;
+                    break;
+                case BlockLogicSign.SIDE_EAST:
+                default:
+                    angle = -90F;
+                    break;
             }
-           /*GL11.glTranslatef((float)d + 0.5F, (float)d1 + 0.75F * scale, (float)d2 + 0.5F);
-            GL11.glRotatef(-f3, 0.0F, 1.0F, 0.0F);
-            GL11.glTranslatef(0.0F, -0.3125F, -0.825F);*/
-            GL11.glTranslatef((float)d + 0.5F, (float)d1 + 0.75F * scale, (float)d2 + 0.5F);
-            GL11.glRotatef(-f3, 0.0F, 1.0F, 0.0F);
+            GL11.glRotatef(-angle, 0.0F, 1.0F, 0.0F);
             GL11.glTranslatef(0.0F, -0.3125F, -0.4375F);
             modelSign.signStick.visible = false;
         }
-        loadTexture("/assets/minecraft/textures/entity/sign.png");
+
         GL11.glPushMatrix();
         GL11.glScalef(scale, -scale, -scale);
+        loadTexture("/assets/minecraft/textures/entity/sign.png");
         modelSign.render();
         GL11.glPopMatrix();
-        Font font = getFont();
 
         // Render overlay
         GL11.glPushMatrix();
-        float f4 = 0.01566F * scale;
-        GL11.glTranslatef(0.0F, 0.5F * scale, 0.065F * scale);
-        GL11.glScalef(f4, -f4, f4);
-        GL11.glNormal3f(0.0F, 0.0F, -1F * f4);
+        GL11.glTranslatef(0, 5.3672f/16f, 0.7f/16f);
         GL11.glDepthMask(false);
         EnumSignPicture picture = tileEntity.getPicture();
-        drawTexturedModalRect(-48, -24, 48, 24, TextureRegistry.getTexture(picture.getTextureKey()));
+        drawTexturedModalRect(1, 0.5,TextureRegistry.getTexture(picture.getTextureKey()));
         GL11.glPopMatrix();
 
         // Render text
-        float lightLevel = mc.currentWorld.getLightBrightness(tileEntity.x, tileEntity.y, tileEntity.z);
+        Font font = getFont();
+        float lightLevel = LightmapHelper.isLightmapEnabled() ? 1 : mc.currentWorld.getLightBrightness(tileEntity.x, tileEntity.y, tileEntity.z);
         float lightOffset = 0f;
         if (tileEntity.isGlowing()) {
             lightLevel = 1f;
@@ -98,13 +91,12 @@ public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign>
         }
 
         GL11.glPushMatrix();
-        f4 = 0.01666667F * scale;
+        float scale2 = 0.01666667F * scale;
         GL11.glTranslatef(0.0F, 0.5F * scale, 0.065F * scale);
-        GL11.glScalef(f4, -f4, f4);
-        GL11.glNormal3f(0.0F, 0.0F, -1F * f4);
+        GL11.glScalef(scale2, -scale2, scale2);
         GL11.glDepthMask(false);
         int color = Colors.allSignColors[tileEntity.getColor().id].getARGB();
-        int r = (int)MathHelper.clamp(((color >> 16) & 0xFF) * lightLevel + lightOffset, 0, 255);
+        int r = (int) MathHelper.clamp(((color >> 16) & 0xFF) * lightLevel + lightOffset, 0, 255);
         int g = (int)MathHelper.clamp(((color >>  8) & 0xFF) * lightLevel + lightOffset, 0, 255);
         int b = (int)MathHelper.clamp(((color >>  0) & 0xFF) * lightLevel + lightOffset, 0, 255);
         color = (r << 16) | (g << 8) | (b << 0);
@@ -122,24 +114,18 @@ public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign>
         GL11.glDepthMask(true);
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
         GL11.glPopMatrix();
+        GL11.glDisable(GL12.GL_RESCALE_NORMAL);
     }
 
-    @Override
-	public void doRender(Tessellator tessellator, TileEntitySign tileEntity, double x, double y, double z,
-                         float partialTick)
-    {
-        renderTileEntitySignAt(tileEntity, x, y, z, partialTick);
-    }
-
-    private void drawTexturedModalRect(int x, int y, int width, int height, IconCoordinate coordinate)
+    private void drawTexturedModalRect(double width, double height, IconCoordinate coordinate)
     {
         coordinate.parentAtlas.bind();
         Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x + 0,          y + height * 2, 0, coordinate.getIconUMin(),coordinate.getIconVMax());
-        tessellator.addVertexWithUV(x + width * 2,  y + height * 2, 0, coordinate.getIconUMax(),coordinate.getIconVMax());
-        tessellator.addVertexWithUV(x + width * 2,  y + 0,          0, coordinate.getIconUMax(),coordinate.getIconVMin());
-        tessellator.addVertexWithUV(x + 0,          y + 0,          0, coordinate.getIconUMin(),coordinate.getIconVMin());
+        tessellator.addVertexWithUV(-width/2,  height/2, 0, coordinate.getIconUMin(),coordinate.getIconVMin());
+        tessellator.addVertexWithUV(-width/2, -height/2, 0, coordinate.getIconUMin(),coordinate.getIconVMax());
+        tessellator.addVertexWithUV( width/2, -height/2, 0, coordinate.getIconUMax(),coordinate.getIconVMax());
+        tessellator.addVertexWithUV( width/2,  height/2, 0, coordinate.getIconUMax(),coordinate.getIconVMin());
         tessellator.draw();
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererStatue.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java
similarity index 50%
rename from game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererStatue.java
rename to game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java
index be550f04f..1f0593d94 100644
--- a/game/client/src/main/java/net/minecraft/client/render/blockentity/TileEntityRendererStatue.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java
@@ -1,46 +1,99 @@
-package net.minecraft.client.render.blockentity;
+package net.minecraft.client.render.tileentity;
 
-import net.minecraft.client.Minecraft;
+import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.model.ModelBiped;
+import net.minecraft.client.render.model.ModelPigman;
 import net.minecraft.client.render.model.ModelPlayer;
 import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.entity.TileEntityStatue;
+import net.minecraft.core.entity.IArmorWearing;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.item.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.useless.dragonfly.DisplayPos;
+
+import java.util.HashMap;
+import java.util.Map;
 
 public class TileEntityRendererStatue extends TileEntityRenderer<TileEntityStatue> {
+    public static final @NotNull Map<@NotNull Block<?>, @NotNull String> BLOCK_SKIN_MAP = new HashMap<>();
+    static {
+        final @NotNull String basePath = "/assets/minecraft/textures/entity/statue/";
+        BLOCK_SKIN_MAP.put(Blocks.STATUE_STONE_LOWER, basePath + "stone.png");
+        BLOCK_SKIN_MAP.put(Blocks.STATUE_BASALT_LOWER, basePath + "basalt.png");
+        BLOCK_SKIN_MAP.put(Blocks.STATUE_LIMESTONE_LOWER, basePath + "limestone.png");
+        BLOCK_SKIN_MAP.put(Blocks.STATUE_GRANITE_LOWER, basePath + "granite.png");
+        BLOCK_SKIN_MAP.put(Blocks.STATUE_MARBLE_LOWER, basePath + "marble.png");
+        BLOCK_SKIN_MAP.put(Blocks.STATUE_PIGMAN_LOWER, basePath + "pigman.png");
+    }
 
-    private final Minecraft mc = Minecraft.getMinecraft();
     private final ModelPlayer model;
     private final ModelBiped modelArmorA;
     private final ModelBiped modelArmorB;
-
+    private final ModelPigman modelPigman;
 
     public TileEntityRendererStatue() {
         this.model = new ModelPlayer(0.0f);
+        this.modelPigman = new ModelPigman(0.0f, 0.0f);
         this.modelArmorA = new ModelBiped(1.0f);
         this.modelArmorB = new ModelBiped(0.5f);
     }
 
-    public void renderAt(TileEntityStatue tileEntity, double x, double y, double z) {
-        TileEntityStatue.Pose pose = tileEntity.getPose();
+    private ModelBiped model(boolean isPigman) {
+        if (isPigman) {
+            return this.modelPigman;
+        } else {
+            return this.model;
+        }
+    }
+
+    public void renderAt(@Nullable ItemStack heldStack, final int meta, final @NotNull Block<?> lowerBlock, final @NotNull TileEntityStatue.Pose pose, final @Nullable IArmorWearing<HumanArmorShape> armorWearer, double x, double y, double z) {
+        final boolean isPigman = lowerBlock == Blocks.STATUE_PIGMAN_LOWER;
 
+        GL12.glEnable(GL12.GL_RESCALE_NORMAL);
         final float scale = 0.0625f;
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-        loadTexture("/assets/minecraft/textures/entity/statue_stone.png");
+        loadTexture(BLOCK_SKIN_MAP.getOrDefault(lowerBlock, BLOCK_SKIN_MAP.get(Blocks.STATUE_STONE_LOWER)));
         GL11.glPushMatrix();
-        GL11.glTranslatef((float) x + 0.5f, (float) y + 1.5f, (float) z + 0.5f);
-        float rotation = (float)(tileEntity.getBlockMeta() * 360) / 16F;
+        GL11.glTranslated(x + 0.5, y + 1.5, z + 0.5);
+        float rotation = (float)(meta * 360) / 16F;
         GL11.glRotatef(-rotation, 0.0F, 1.0F, 0.0F);
-        GL11.glScalef(scale, -scale, -scale);
+        GL11.glScalef(1, -1, -1);
         GL11.glDisable(GL11.GL_CULL_FACE);
-        renderModel(this.model, pose);
-        for (int i = 0; i < 4; i++) {
-            renderArmor(tileEntity, i, pose);
-        }
+
+            GL11.glPushMatrix();
+            GL11.glScalef(scale, scale, scale);
+            renderModel(this.model(isPigman), pose);
+            if (armorWearer != null) {
+                for (int i = 0; i < 4; i++) {
+                    renderArmor(armorWearer, i, pose);
+                }
+            }
+            GL11.glPopMatrix();
+
+        renderHeldItem(heldStack, isPigman);
         GL11.glEnable(GL11.GL_CULL_FACE);
         GL11.glPopMatrix();
+        GL12.glDisable(GL12.GL_RESCALE_NORMAL);
+    }
+
+    private void renderHeldItem(final @Nullable ItemStack itemStack, boolean isPigman) {
+        if(itemStack != null) {
+            GL12.glEnable(GL12.GL_RESCALE_NORMAL);
+            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
+            model(isPigman).armRight.translateTo(0.0625F);
+            GL11.glRotatef(-90, 1, 0, 0);
+            GL11.glScalef(-1, 1, -1);
+            GL11.glTranslatef(1/16f, 2/16f, -10f/16f);
+            ItemModelDispatcher.getInstance().getDispatch(itemStack).render(Tessellator.instance, null, itemStack, DisplayPos.THIRD_PERSON_RIGHT_HAND, true, 1, 1f, 1f, 1f, false);
+            GL11.glEnable(GL11.GL_CULL_FACE);
+            GL12.glDisable(GL12.GL_RESCALE_NORMAL);
+        }
     }
 
     private void applyPose(TileEntityStatue.Pose pose, ModelBiped model) {
@@ -50,12 +103,16 @@ public class TileEntityRendererStatue extends TileEntityRenderer<TileEntityStatu
         model.legRight.xRot = pose.rightLegPitch;
         model.head.xRot = pose.headPitch;
         model.head.yRot = pose.headYaw;
+        if (model instanceof ModelPigman) {
+            ((ModelPigman) model).nose.xRot = pose.headPitch;
+            ((ModelPigman) model).nose.yRot = pose.headYaw;
+        }
     }
 
     private void renderModel(ModelBiped model, TileEntityStatue.Pose pose) {
         final float scale = 1.0f;
 
-        model.setupAnimation(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, scale);
+        model.setupAnimation(null, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, scale, 1f);
         applyPose(pose, model);
 
         model.head.render(scale);
@@ -65,16 +122,19 @@ public class TileEntityRendererStatue extends TileEntityRenderer<TileEntityStatu
         model.legRight.render(scale);
         model.legLeft.render(scale);
         model.hair.render(scale);
+        if (model instanceof ModelPigman) {
+            ((ModelPigman) model).nose.render(scale);
+        }
     }
 
     @Override
     public void doRender(Tessellator tessellator, TileEntityStatue tileEntity, double x, double y, double z,
                          float partialTick) {
-        renderAt(tileEntity, x, y, z);
+        renderAt(tileEntity.getHeldItem(), tileEntity.getBlockMeta(), tileEntity.getBlock(), tileEntity.getPose(), tileEntity, x, y, z);
     }
 
-    private boolean renderArmor(TileEntityStatue entity, int layer, TileEntityStatue.Pose pose) {
-        ItemStack itemstack = entity.getItemInArmorSlot(HumanArmorShape.values()[(entity.getNumArmorSlots() - 1) - layer]);
+    private boolean renderArmor(final @NotNull IArmorWearing<HumanArmorShape> armorWearer, int layer, TileEntityStatue.Pose pose) {
+        ItemStack itemstack = armorWearer.getItemInArmorSlot(HumanArmorShape.values()[(armorWearer.getNumArmorSlots() - 1) - layer]);
         if (itemstack != null) {
             Item item = itemstack.getItem();
             ModelBiped toDraw = null;
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 10ebc53b9..b1b6991c4 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
@@ -16,6 +16,7 @@ import net.minecraft.core.world.season.SeasonManager;
 import net.minecraft.core.world.season.Seasons;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypes;
+import net.minecraft.core.world.weather.IPrecipitation;
 import net.minecraft.core.world.weather.WeatherManager;
 
 public class WorldClient extends World {
@@ -64,7 +65,7 @@ public class WorldClient extends World {
         float r = (float)(color >> 16 & 255) / 255F;
         float g = (float)(color >> 8 & 255) / 255F;
         float b = (float)(color & 255) / 255F;
-        float f6 = getCurrentWeather() != null && getCurrentWeather().isPrecipitation ? weatherManager.getWeatherIntensity() * weatherManager.getWeatherPower() : 0.0f;
+        float f6 = getCurrentWeather() != null && getCurrentWeather() instanceof IPrecipitation ? weatherManager.getWeatherIntensity() * weatherManager.getWeatherPower() : 0.0f;
         if(f6 > 0.0F)
         {
             float f7 = (r * 0.3F + g * 0.59F + b * 0.11F) * 0.6F;
@@ -121,7 +122,7 @@ public class WorldClient extends World {
         r *= f2;
         g *= f2;
         b *= f2;
-        float f7 = getCurrentWeather() != null && getCurrentWeather().isPrecipitation ? weatherManager.getWeatherIntensity() * weatherManager.getWeatherPower() : 0.0f;
+        float f7 = getCurrentWeather() != null && getCurrentWeather() instanceof IPrecipitation ? weatherManager.getWeatherIntensity() * weatherManager.getWeatherPower() : 0.0f;
         if(f7 > 0.0F)
         {
             float f8 = (r * 0.3F + g * 0.59F + b * 0.11F) * 0.6F;
diff --git a/game/client/src/main/java/org/useless/dragonfly/DisplayPos.java b/game/client/src/main/java/org/useless/dragonfly/DisplayPos.java
new file mode 100644
index 000000000..6dee67e1c
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/DisplayPos.java
@@ -0,0 +1,128 @@
+package org.useless.dragonfly;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import net.minecraft.client.render.block.model.BlockModel;
+import org.useless.dragonfly.data.block.mojang.BlockModelMojangData;
+import org.useless.util.GsonHelper;
+
+import java.lang.reflect.Type;
+
+public final class DisplayPos {
+    /**
+     * No Transformation, used in cases where a full block is meant to render without a world reference, mostly for legacy code reasons
+     */
+    public static final String NONE = "none";
+    /**
+     * Transformation while the item being rendered in the mob's third person right hand
+     */
+    public static final String THIRD_PERSON_RIGHT_HAND = "thirdperson_righthand";
+    /**
+     * Transformation while the item being rendered in the mob's third person left hand
+     */
+    public static final String THIRD_PERSON_LEFT_HAND = "thirdperson_lefthand";
+    /**
+     * Transformation while the item being rendered in the player's first person right hand
+     */
+    public static final String FIRST_PERSON_RIGHT_HAND = "firstperson_righthand";
+    /**
+     * Transformation while the item being rendered in the player's first person left hand
+     */
+    public static final String FIRST_PERSON_LEFT_HAND = "firstperson_lefthand";
+    /**
+     * Transformation while the item is being rendered in a gui
+     */
+    public static final String GUI = "gui";
+    /**
+     * Transformation while the item is equipped on the head slot (except for actual armor which uses a separate system)
+     */
+    public static final String HEAD = "head";
+    /**
+     * Transformation while the item is in entity form on the ground
+     */
+    public static final String GROUND = "ground";
+    /**
+     * Traditionally refers to the transformation while in an item frame, may end up getting used for the augment table
+     */
+    public static final String FIXED = "fixed";
+    /**
+     * Transformation while in a jar
+     */
+    public static final String JAR = "jar";
+
+
+    public static final DisplayPos DEFAULT_DISPLAY_POS = new DisplayPos(
+        0, 0, 0,
+        0, 0, 0,
+        1f, 1f, 1f);
+
+    public final float tx;
+    public final float ty;
+    public final float tz;
+
+    public final float rx;
+    public final float ry;
+    public final float rz;
+
+    public final float sx;
+    public final float sy;
+    public final float sz;
+
+    public DisplayPos(
+        float tx, float ty, float tz,
+        float rx, float ry, float rz,
+        float sx, float sy, float sz)
+    {
+        this.tx = tx;
+        this.ty = ty;
+        this.tz = tz;
+
+        this.rx = rx;
+        this.ry = ry;
+        this.rz = rz;
+
+        this.sx = sx;
+        this.sy = sy;
+        this.sz = sz;
+    }
+
+    @Override
+    public String toString() {
+        return "DisplayPos{" +
+            "tx=" + tx +
+            ", ty=" + ty +
+            ", tz=" + tz +
+            ", rx=" + rx +
+            ", ry=" + ry +
+            ", rz=" + rz +
+            ", sx=" + sx +
+            ", sy=" + sy +
+            ", sz=" + sz +
+            '}';
+    }
+
+    public static class Serializer implements JsonSerializer<DisplayPos>, JsonDeserializer<DisplayPos> {
+
+        @Override
+        public DisplayPos deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+            JsonObject object = json.getAsJsonObject();
+            float[] rotation = GsonHelper.getAsFloatArray(object.get("rotation"), 3);
+            float[] translation = GsonHelper.getAsFloatArray(object.get("translation"), 3);
+            float[] scale = GsonHelper.getAsFloatArray(object.get("scale"), 3);
+            return new DisplayPos(
+                translation[0] * BlockModelMojangData.BLOCKS_PER_UNIT, translation[1] * BlockModelMojangData.BLOCKS_PER_UNIT, translation[2] * BlockModelMojangData.BLOCKS_PER_UNIT,
+                rotation[0], rotation[1], rotation[2],
+                scale[0], scale[1], scale[2]);
+        }
+
+        @Override
+        public JsonElement serialize(DisplayPos src, Type typeOfSrc, JsonSerializationContext context) {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/game/client/src/main/java/org/useless/dragonfly/data/block/BlockModelData.java b/game/client/src/main/java/org/useless/dragonfly/data/block/BlockModelData.java
new file mode 100644
index 000000000..eb4a29f80
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/data/block/BlockModelData.java
@@ -0,0 +1,10 @@
+package org.useless.dragonfly.data.block;
+
+import net.minecraft.core.util.collection.NamespaceID;
+import org.jetbrains.annotations.NotNull;
+import org.useless.dragonfly.models.block.StaticBlockModel;
+
+public interface BlockModelData {
+    @NotNull NamespaceID modelId();
+    @NotNull StaticBlockModel asModel();
+}
diff --git a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/BlockModelMojangData.java b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/BlockModelMojangData.java
new file mode 100644
index 000000000..331864413
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/BlockModelMojangData.java
@@ -0,0 +1,355 @@
+package org.useless.dragonfly.data.block.mojang;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.google.gson.stream.JsonReader;
+import com.mojang.logging.LogUtils;
+import net.minecraft.client.render.texturepack.TexturePackList;
+import net.minecraft.core.util.HardIllegalArgumentException;
+import net.minecraft.core.util.collection.NamespaceID;
+import net.minecraft.core.util.helper.Direction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.useless.dragonfly.DisplayPos;
+import org.useless.dragonfly.data.block.BlockModelData;
+import org.useless.dragonfly.models.block.StaticBlockModel;
+import org.useless.dragonfly.models.block.mojang.StaticModelMojang;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * <p>Modern Minecraft Block Model Data scheme as laid out on the {@see <a href="https://minecraft.wiki/w/Model#Block_models">minecraft.wiki/w/Model#Block_models</a>} page of the minecraft wiki.</p>
+ * <p>Implementation should align with Modern's as of the release of 1.21.4</>
+ */
+public class BlockModelMojangData implements BlockModelData {
+    public static final float UNITS_PER_BLOCK = 16f;
+    public static final float BLOCKS_PER_UNIT = 1/16f;
+    protected final static Logger LOGGER = LogUtils.getLogger();
+    protected final static Gson gson = builder().create();
+
+    protected static GsonBuilder builder() {
+        GsonBuilder builder = new GsonBuilder();
+        builder.setPrettyPrinting();
+        builder.registerTypeAdapter(BlockModelMojangData.Builder.class, new BlockModelMojangData.Builder.Serializer());
+        builder.registerTypeAdapter(Element.Builder.class, new Element.Builder.Serializer());
+        builder.registerTypeAdapter(Face.Builder.class, new Face.Builder.Serializer());
+        builder.registerTypeAdapter(Rotation.Builder.class, new Rotation.Builder.Serializer());
+        builder.registerTypeAdapter(DisplayPos.class, new DisplayPos.Serializer());
+        return builder;
+    }
+
+    protected static final String DEFAULT_NAMESPACE = NamespaceID.DEFAULT_NAMESPACE;
+
+    protected static final String DEFAULT_PARENT = null;
+    protected static final boolean DEFAULT_AMBIENT_OCCLUSION = true;
+    protected static final int DEFAULT_RENDER_LAYER = 0;
+
+    protected final NamespaceID modelId;
+
+    /**
+     * <p>
+     * Loads a different model from the given path, in form of a resource location.
+     * If both "parent" and "elements" are set, the "elements" tag overrides the "elements" tag from the previous model.
+     * </p>
+     * Can be set to "builtin/generated" to use a model that is created out of the specified icon.
+     * Only the first layer is supported, and rotation can be achieved only by using block states files.
+     */
+    public final @Nullable String parent;
+    /**
+     * Whether to use ambient occlusion (true - default), or not (false).
+     */
+    public final boolean ambientOcclusion;
+
+    /**
+     * Render pass to render model on
+     */
+    public final @Nullable Integer renderLayer;
+
+    /**
+     * Holds the different transforms for where item models are displayed.
+     */
+    public final @Nullable  Map<@NotNull String, @NotNull DisplayPos> displayPositions;
+    /**
+     * Holds the textures of the model, in form of a resource location or can be another texture variable.
+     */
+    public final @Nullable  Map<@NotNull String, @NotNull String> textures;
+
+    /**
+     * Each direction's color index, -1 represents no color
+     */
+    public final @Nullable Map<@NotNull Direction, @NotNull Integer> particleIndices;
+
+    /**
+     * Contains all the elements of the model.
+     * They can have only cubic forms.
+     */
+    public final @Nullable List<@NotNull Element> elements;
+
+    protected BlockModelMojangData(
+        @NotNull TexturePackList texturePackList,
+        @NotNull NamespaceID id,
+        @Nullable String parent,
+        boolean ambientOcclusion,
+        @Nullable Integer renderLayer,
+        @Nullable Map<@NotNull String, @NotNull DisplayPos> displayPositions,
+        @Nullable Map<@NotNull String, @NotNull String> textures,
+        @Nullable Map<@NotNull Direction, @NotNull Integer> particleIndices,
+        @Nullable List<@NotNull Element> elements)
+    {
+        this.modelId = id;
+        this.parent = parent;
+        if (parent != null) {
+            BlockModelMojangData parentData = BlockModelMojangData.Cache.loadModelData(texturePackList, parent);
+            this.ambientOcclusion = ambientOcclusion;
+            if (parentData != null) {
+                this.displayPositions = new HashMap<>();
+                this.textures = new HashMap<>();
+                this.particleIndices = new HashMap<>();
+                // Elements overrides parent's elements rather than merges them like other fields
+                this.elements = (parentData.elements != null && elements == null) ? new ArrayList<>(parentData.elements) : elements;
+                this.renderLayer = (parentData.renderLayer != null && renderLayer == null) ? parentData.renderLayer : renderLayer;
+
+                if (parentData.displayPositions != null) this.displayPositions.putAll(parentData.displayPositions);
+                if (displayPositions != null) this.displayPositions.putAll(displayPositions);
+                if (parentData.textures != null) this.textures.putAll(parentData.textures);
+                if (textures != null) this.textures.putAll(textures);
+                if (parentData.particleIndices != null) this.particleIndices.putAll(parentData.particleIndices);
+                if (particleIndices != null) this.particleIndices.putAll(particleIndices);
+            } else {
+                this.displayPositions = displayPositions;
+                this.particleIndices = particleIndices;
+                this.renderLayer = renderLayer;
+                this.textures = textures;
+                this.elements = elements;
+            }
+        } else {
+            this.ambientOcclusion = ambientOcclusion;
+            this.displayPositions = displayPositions;
+            this.particleIndices = particleIndices;
+            this.renderLayer = renderLayer;
+            this.textures = textures;
+            this.elements = elements;
+        }
+
+    }
+
+    @Override
+    public @NotNull NamespaceID modelId() {
+        return modelId;
+    }
+
+    @Override
+    public @NotNull StaticBlockModel asModel() {
+        return new StaticModelMojang(this);
+    }
+
+    @Override
+    public String toString() {
+        return "BlockModelMojangData{" +
+            "modelId=" + modelId +
+            ", parent='" + parent + '\'' +
+            ", ambientOcclusion=" + ambientOcclusion +
+            ", displayPositions=" + displayPositions +
+            ", textures=" + textures +
+            ", particleIndices=" + particleIndices +
+            ", elements=" + elements +
+            '}';
+    }
+
+    @SuppressWarnings("unused")
+    public static class Builder {
+        protected @Nullable String parent = DEFAULT_PARENT;
+        protected boolean ambientOcclusion = DEFAULT_AMBIENT_OCCLUSION;
+        protected int renderLayer = DEFAULT_RENDER_LAYER;
+        protected @Nullable Map<@NotNull String, @NotNull DisplayPos> displayPosMap = null;
+        protected @Nullable Map<@NotNull String, @NotNull String> textures = null;
+        protected @Nullable Map<@NotNull Direction, @NotNull Integer> particleIndices = null;
+        protected @Nullable List<Element. @NotNull Builder> elements = null;
+
+        public @NotNull Builder setParent(@Nullable String parent) {
+            this.parent = parent;
+            return this;
+        }
+
+        public @NotNull Builder setAO(boolean ao) {
+            this.ambientOcclusion = ao;
+            return this;
+        }
+
+        public @NotNull Builder setRenderLayer(int renderLayer) {
+            this.renderLayer = renderLayer;
+            return this;
+        }
+
+        public @NotNull Builder setDisplay(@NotNull String id, @Nullable DisplayPos displayPos) {
+            if (displayPos == null && displayPosMap != null) {
+                displayPosMap.remove(id);
+            } else if (displayPos != null) {
+                prepareDisplayPosMap().put(id, displayPos);
+            }
+            return this;
+        }
+
+        public @NotNull Builder setTexture(@NotNull String textureVariable, @NotNull String textureSymbol) {
+            prepareTextureMap().put(textureVariable, textureSymbol);
+            return this;
+        }
+
+        public @NotNull Builder setParticleIndex(@NotNull Direction direction, int index) {
+            prepareParticleIndicesMap().put(direction, index);
+            return this;
+        }
+
+        public @NotNull Builder addElement(Element. @NotNull Builder elementBuilder) {
+            prepareElementsList().add(elementBuilder);
+            return this;
+        }
+
+        private @NotNull Map<@NotNull String, @NotNull DisplayPos> prepareDisplayPosMap() {
+            if (displayPosMap == null) displayPosMap = new HashMap<>();
+            return displayPosMap;
+        }
+
+        private @NotNull Map<@NotNull String, @NotNull String> prepareTextureMap() {
+            if (textures == null) textures = new HashMap<>();
+            return textures;
+        }
+
+        private @NotNull Map<@NotNull Direction, @NotNull Integer> prepareParticleIndicesMap() {
+            if (particleIndices == null) particleIndices = new HashMap<>();
+            return particleIndices;
+        }
+
+        private @NotNull List<Element. @NotNull Builder> prepareElementsList() {
+            if (elements == null) elements = new ArrayList<>();
+            return elements;
+        }
+
+        protected @NotNull BlockModelMojangData build(@NotNull TexturePackList texturePackList, @NotNull String id) {
+            if (!id.contains(":")) {
+                id = DEFAULT_NAMESPACE + ":" + id;
+            }
+            List<Element> elementList = null;
+            if (elements != null) {
+                elementList = new ArrayList<>();
+                for (Element.Builder b : elements) {
+                    elementList.add(b.build());
+                }
+            }
+            try {
+                return new BlockModelMojangData(texturePackList, new NamespaceID(id), parent, ambientOcclusion, renderLayer, displayPosMap, textures, particleIndices, elementList);
+            } catch (HardIllegalArgumentException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+
+        public static class Serializer implements JsonSerializer<BlockModelMojangData.Builder>, JsonDeserializer<BlockModelMojangData.Builder> {
+            @Override
+            public BlockModelMojangData.Builder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+                JsonObject object = json.getAsJsonObject();
+                BlockModelMojangData.Builder dataBuilder = new BlockModelMojangData.Builder();
+                if (object.has("parent")) dataBuilder.setParent(object.get("parent").getAsString());
+                if (object.has("ambientocclusion")) dataBuilder.setAO(object.get("ambientocclusion").getAsBoolean());
+                if (object.has("renderlayer")) dataBuilder.setRenderLayer(object.get("renderlayer").getAsInt());
+                if (object.has("display")) {
+                    JsonObject display = object.getAsJsonObject("display");
+                    for (Map.Entry<String, JsonElement> e : display.entrySet()) {
+                        dataBuilder.setDisplay(e.getKey(), context.deserialize(e.getValue(), DisplayPos.class));
+                    }
+                }
+                if (object.has("textures")) {
+                    JsonObject textures = object.getAsJsonObject("textures");
+                    for (Map.Entry<String, JsonElement> e : textures.entrySet()) {
+                        dataBuilder.setTexture(e.getKey(), e.getValue().getAsString());
+                    }
+                }
+                if (object.has("elements")) {
+                    JsonArray elements = object.getAsJsonArray("elements");
+                    for (JsonElement e : elements) {
+                        dataBuilder.addElement(context.deserialize(e, Element.Builder.class));
+                    }
+                }
+                if (object.has("particles")) {
+                    JsonObject textures = object.getAsJsonObject("particles");
+                    for (Map.Entry<String, JsonElement> e : textures.entrySet()) {
+                        dataBuilder.setParticleIndex(Direction.valueOf(e.getKey().toUpperCase(Locale.ROOT)), e.getValue().getAsInt());
+                    }
+                }
+
+                return dataBuilder;
+            }
+
+            @Override
+            public JsonElement serialize(BlockModelMojangData.Builder src, Type typeOfSrc, JsonSerializationContext context) {
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static class Cache {
+        protected static final Map<String, BlockModelMojangData> modelDataCache = new HashMap<>();
+
+        protected static final String RESOURCE_PATH = "/assets/%s/models/%s.json";
+
+        public static @Nullable BlockModelMojangData loadModelData(@NotNull TexturePackList texturePackList, @NotNull NamespaceID id) {
+            String s = id.toString();
+            if (modelDataCache.containsKey(s)) return modelDataCache.get(s);
+            BlockModelMojangData.Builder data = loadFromStream(texturePackList.getResourceAsStream(String.format(RESOURCE_PATH, id.namespace, id.value)));
+            if (data == null) {
+                LOGGER.error("Could not locate block model data for id '{}'!", id);
+                return null;
+            }
+            BlockModelMojangData model = data.build(texturePackList, id.toString());
+            modelDataCache.put(model.modelId().toString(), model);
+            return model;
+        }
+        public static @Nullable BlockModelMojangData loadModelData(@NotNull TexturePackList texturePackList, @NotNull String id) {
+            String namespace;
+            String value;
+            if (!id.contains(":")) {
+                namespace = DEFAULT_NAMESPACE;
+                value = id;
+            } else {
+                String[] strings = id.split(":");
+                if (strings.length != 2) throw new  IllegalArgumentException("Block model id '" + id + "' cannot have more then 1 ':' character!");
+                namespace = strings[0];
+                value = strings[1];
+            }
+            if (modelDataCache.containsKey(id)) return modelDataCache.get(id);
+            BlockModelMojangData.Builder data = loadFromStream(texturePackList.getResourceAsStream(String.format(RESOURCE_PATH, namespace, value)));
+            if (data == null) {
+                LOGGER.error("Could not locate block model data for id '{}'!", id);
+                return null;
+            }
+            BlockModelMojangData model = data.build(texturePackList, namespace + ":" + value);
+            modelDataCache.put(model.modelId().toString(), model);
+            return model;
+        }
+
+        public static void resetCache() {
+            modelDataCache.clear();
+        }
+
+        protected static @Nullable BlockModelMojangData.Builder loadFromStream(@Nullable InputStream stream) {
+            if (stream == null) return null;
+            return gson.fromJson(new JsonReader(new InputStreamReader(stream)), BlockModelMojangData.Builder.class);
+        }
+    }
+}
diff --git a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/CompiledBlockModelMojangData.java b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/CompiledBlockModelMojangData.java
new file mode 100644
index 000000000..3bd050f7a
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/CompiledBlockModelMojangData.java
@@ -0,0 +1,450 @@
+package org.useless.dragonfly.data.block.mojang;
+
+import com.mojang.logging.LogUtils;
+import net.minecraft.client.render.block.model.BlockModelStandard;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.util.collection.NamespaceID;
+import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.useless.dragonfly.DisplayPos;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.useless.dragonfly.data.block.mojang.BlockModelMojangData.BLOCKS_PER_UNIT;
+
+public class CompiledBlockModelMojangData {
+    protected static final Logger LOGGER = LogUtils.getLogger();
+
+    public final BlockModelMojangData data;
+
+    public final @NotNull Map<@NotNull String, @NotNull IconCoordinate> textures = new HashMap<>();
+    public final @NotNull C_Element @NotNull [] elements;
+    public final int @NotNull [] particleIndices;
+    public final @NotNull Map<@NotNull String, @NotNull DisplayPos> displayPosMap;
+    public final int renderLayer;
+
+    public CompiledBlockModelMojangData(BlockModelMojangData data) {
+        this.data = data;
+
+        if (this.data.textures == null) {
+            LOGGER.error("Model '{}' does not have assigned texture data!", data.modelId());
+        } else {
+            for (String key : data.textures.keySet()) {
+                IconCoordinate coordinate = getTexture("#" + key, null, true);
+                if (coordinate != null) textures.put("#" + key, coordinate);
+            }
+        }
+
+        IconCoordinate particleAll = textures.get("#particle");
+
+        if (particleAll != null) { // Modern mojang format support, the modern mc version only has a global particle texture symbol rather than per side
+            textures.putIfAbsent("#particle_up", particleAll);
+            textures.putIfAbsent("#particle_down", particleAll);
+            textures.putIfAbsent("#particle_north", particleAll);
+            textures.putIfAbsent("#particle_south", particleAll);
+            textures.putIfAbsent("#particle_west", particleAll);
+            textures.putIfAbsent("#particle_east", particleAll);
+            textures.putIfAbsent("#overlay", particleAll);
+        } else {
+            if (textures.get("#particle_up") == null) LOGGER.warn("Model '{}' does not have an assigned '#particle_up' symbol!", data.modelId());
+            if (textures.get("#particle_down") == null) LOGGER.warn("Model '{}' does not have an assigned '#particle_down' symbol!", data.modelId());
+            if (textures.get("#particle_north") == null) LOGGER.warn("Model '{}' does not have an assigned '#particle_north' symbol!", data.modelId());
+            if (textures.get("#particle_south") == null) LOGGER.warn("Model '{}' does not have an assigned '#particle_south' symbol!", data.modelId());
+            if (textures.get("#particle_west") == null) LOGGER.warn("Model '{}' does not have an assigned '#particle_west' symbol!", data.modelId());
+            if (textures.get("#particle_east") == null) LOGGER.warn("Model '{}' does not have an assigned '#particle_east' symbol!", data.modelId());
+        }
+        if (textures.get("#overlay") == null) LOGGER.warn("Model '{}' does not have an assigned '#overlay' symbol!", data.modelId());
+
+        displayPosMap = new HashMap<>();
+        if (data.displayPositions != null) displayPosMap.putAll(data.displayPositions);
+
+        particleIndices = new int[6];
+        if (data.particleIndices != null) {
+            particleIndices[Direction.UP.getId()] = data.particleIndices.getOrDefault(Direction.UP, 0);
+            particleIndices[Direction.DOWN.getId()] = data.particleIndices.getOrDefault(Direction.DOWN, 0);
+            particleIndices[Direction.NORTH.getId()] = data.particleIndices.getOrDefault(Direction.NORTH, 0);
+            particleIndices[Direction.SOUTH.getId()] = data.particleIndices.getOrDefault(Direction.SOUTH, 0);
+            particleIndices[Direction.WEST.getId()] = data.particleIndices.getOrDefault(Direction.WEST, 0);
+            particleIndices[Direction.EAST.getId()] = data.particleIndices.getOrDefault(Direction.EAST, 0);
+        }
+
+        renderLayer = data.renderLayer == null ? 0 : data.renderLayer;
+
+        elements = new C_Element[data.elements == null ? 0 : data.elements.size()];
+        if (data.elements != null) {
+            int i = 0;
+            for (Element e : data.elements) {
+                elements[i++] = new C_Element(e);
+            }
+        }
+    }
+
+    protected IconCoordinate getTexture(@NotNull final String textureSymbol, @Nullable final IconCoordinate defaultCoordinate, final boolean logWarnings) {
+        try {
+            if (data.textures == null) {
+                if (logWarnings) LOGGER.warn("Model '{}' does not have assigned texture data!", data.modelId());
+                return defaultCoordinate;
+            }
+
+            @Nullable String path = data.textures.get(textureSymbol.startsWith("#") ? textureSymbol.substring(1) : textureSymbol);
+
+            if (path == null) {
+                if (logWarnings) LOGGER.warn("Texture for symbol '{}' is not assigned to any value!", textureSymbol);
+                return defaultCoordinate;
+            } else if (path.startsWith("#")) { // Texture variable
+                return getTexture(path.substring(1), defaultCoordinate, logWarnings);
+            } else {
+                if (!path.contains(":")) path = NamespaceID.DEFAULT_NAMESPACE + ":" + path;
+                if (TextureRegistry.hasTexture(path)) {
+                    return TextureRegistry.getTexture(path);
+                } else {
+                    if (logWarnings) LOGGER.warn("Texture for id '{}' does not exist!", path);
+                    return BlockModelStandard.BLOCK_TEXTURE_MISSING;
+                }
+            }
+
+        } catch (StackOverflowError stackOverflowError) {
+            LOGGER.error("Recursive texture lookup from symbol '{}' in model '{}'!", textureSymbol, data.modelId());
+            return defaultCoordinate;
+        }
+    }
+
+    public static class C_Element {
+        public static final int VERTEX_TOP_LEFT = 0;
+        public static final int VERTEX_TOP_RIGHT = 3;
+        public static final int VERTEX_BOTTOM_RIGHT = 2;
+        public static final int VERTEX_BOTTOM_LEFT = 1;
+
+        public static final int VERTEX_FLOAT_X = 0;
+        public static final int VERTEX_FLOAT_Y = 1;
+        public static final int VERTEX_FLOAT_Z = 2;
+        public static final int VERTEX_FLOAT_U = 3;
+        public static final int VERTEX_FLOAT_V = 4;
+        public static final int FLOATS_PER_VERTEX = 5;
+
+        public static final int NORMAL_FLOAT_X = 0;
+        public static final int NORMAL_FLOAT_Y = 1;
+        public static final int NORMAL_FLOAT_Z = 2;
+        public static final int FLOATS_PER_NORMAL = 3;
+
+        public final int lightEmission;
+        public final boolean shade;
+
+        public final float minX;
+        public final float minY;
+        public final float minZ;
+        public final float maxX;
+        public final float maxY;
+        public final float maxZ;
+
+        public final int faces;
+        public final float @NotNull [] vertexData;
+        public final float @NotNull [] normalData;
+        public final int @NotNull [] tintIndices;
+        public final @Nullable Direction @NotNull [] cullfaces;
+        public final @NotNull Direction @NotNull [] directions;
+        public final @NotNull String @NotNull [] textures;
+
+        public C_Element(Element element) {
+            faces = element.faces.size();
+            vertexData = new float[faces * 4 * FLOATS_PER_VERTEX];
+            normalData = new float[faces * FLOATS_PER_NORMAL];
+            tintIndices = new int[faces];
+            cullfaces = new Direction[faces];
+            directions = new Direction[faces];
+            textures = new String[faces];
+
+            shade = element.shade;
+            lightEmission = element.lightEmission;
+
+            if (element.rotation != null && element.rotation.rescale) {
+                float x = (45 - Math.abs(((element.rotation.angle + 360) % 360) - 45))/45f;
+                float scalar = MathHelper.sqrt_float(1 + x * x);
+
+                float cx = element.rotation.originX * BLOCKS_PER_UNIT;
+                float cy = element.rotation.originY * BLOCKS_PER_UNIT;
+                float cz = element.rotation.originZ * BLOCKS_PER_UNIT;
+
+                switch (element.rotation.axis) {
+                    case X:
+                        minX = element.fromX * BLOCKS_PER_UNIT;
+                        minY = (((element.fromY * BLOCKS_PER_UNIT) - cy) * scalar) + cy;
+                        minZ = (((element.fromZ * BLOCKS_PER_UNIT) - cz) * scalar) + cz;
+
+                        maxX = element.toX * BLOCKS_PER_UNIT;
+                        maxY = (((element.toY * BLOCKS_PER_UNIT) - cy) * scalar) + cy;
+                        maxZ = (((element.toZ * BLOCKS_PER_UNIT) - cz) * scalar) + cz;
+                        break;
+                    case Y:
+                        minY = element.fromY * BLOCKS_PER_UNIT;
+                        minX = (((element.fromX * BLOCKS_PER_UNIT) - cx) * scalar) + cx;
+                        minZ = (((element.fromZ * BLOCKS_PER_UNIT) - cz) * scalar) + cz;
+
+                        maxY = element.toY * BLOCKS_PER_UNIT;
+                        maxX = (((element.toX * BLOCKS_PER_UNIT) - cx) * scalar) + cx;
+                        maxZ = (((element.toZ * BLOCKS_PER_UNIT) - cz) * scalar) + cz;
+                        break;
+                    case Z:
+                    default:
+                        minZ = element.fromZ * BLOCKS_PER_UNIT;
+                        minX = (((element.fromX * BLOCKS_PER_UNIT) - cx) * scalar) + cx;
+                        minY = (((element.fromY * BLOCKS_PER_UNIT) - cy) * scalar) + cy;
+
+                        maxZ = element.toZ * BLOCKS_PER_UNIT;
+                        maxX = (((element.toX * BLOCKS_PER_UNIT) - cx) * scalar) + cx;
+                        maxY = (((element.toY * BLOCKS_PER_UNIT) - cy) * scalar) + cy;
+                        break;
+                }
+            } else {
+                minX = element.fromX * BLOCKS_PER_UNIT;
+                minY = element.fromY * BLOCKS_PER_UNIT;
+                minZ = element.fromZ * BLOCKS_PER_UNIT;
+
+                maxX = element.toX * BLOCKS_PER_UNIT;
+                maxY = element.toY * BLOCKS_PER_UNIT;
+                maxZ = element.toZ * BLOCKS_PER_UNIT;
+            }
+
+
+
+            int i = 0;
+            for (Map.Entry<Direction, Face> e : element.faces.entrySet()) {
+                Direction d = e.getKey();
+                Face f = e.getValue();
+
+                float minU = f.u1 * BLOCKS_PER_UNIT;
+                float maxU = f.u2 * BLOCKS_PER_UNIT;
+                float minV = f.v1 * BLOCKS_PER_UNIT;
+                float maxV = f.v2 * BLOCKS_PER_UNIT;
+
+                tintIndices[i] = f.tintIndex;
+                cullfaces[i] = f.cullFace;
+                directions[i] = d;
+                textures[i] = f.texture;
+                int offset = i * 4 * FLOATS_PER_VERTEX;
+                int rot = 4 - f.rotation;
+                switch (d) {
+                    case UP:
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+                        break;
+                    case DOWN:
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+                        break;
+                    case NORTH:
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+                        break;
+                    case SOUTH:
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+                        break;
+                    case WEST:
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = minX;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+                        break;
+                    case EAST:
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_TOP_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_TOP_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = maxZ;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = minU;
+                        vertexData[offset + ((VERTEX_TOP_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = maxY;
+                        vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_BOTTOM_RIGHT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = minV;
+
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] = maxX;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] = minY;
+                        vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] = minZ;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_U] = maxU;
+                        vertexData[offset + ((VERTEX_BOTTOM_LEFT + rot) % 4 * FLOATS_PER_VERTEX) + VERTEX_FLOAT_V] = maxV;
+                        break;
+                }
+                i++;
+            }
+
+            if (element.rotation != null) {
+                for (int f = 0; f < faces; f++) {
+                    for (int v = 0; v < 4; v++) {
+                        final int offset = f * 4 * FLOATS_PER_VERTEX + v * FLOATS_PER_VERTEX;
+                        final float x = vertexData[offset + VERTEX_FLOAT_X] - element.rotation.originX * BLOCKS_PER_UNIT;
+                        final float y = vertexData[offset + VERTEX_FLOAT_Y] - element.rotation.originY * BLOCKS_PER_UNIT;
+                        final float z = vertexData[offset + VERTEX_FLOAT_Z] - element.rotation.originZ * BLOCKS_PER_UNIT;
+                        final float nx;
+                        final float ny;
+                        final float nz;
+                        final float sin = MathHelper.sin(MathHelper.toRadians(element.rotation.angle));
+                        final float cos = MathHelper.cos(MathHelper.toRadians(element.rotation.angle));
+                        switch (element.rotation.axis) {
+                            case X:
+                                nx = x;
+                                ny = y * cos - z * sin;
+                                nz = z * cos + y * sin;
+                                break;
+                            case Y:
+                                nx = x * cos - z * sin;
+                                ny = y;
+                                nz = z * cos + x * sin;
+                                break;
+                            case Z:
+                            default:
+                                nx = x * cos - y * sin;
+                                ny = y * cos + x * sin;
+                                nz = z;
+                                break;
+                        }
+                        vertexData[offset + VERTEX_FLOAT_X] = nx + element.rotation.originX * BLOCKS_PER_UNIT;
+                        vertexData[offset + VERTEX_FLOAT_Y] = ny + element.rotation.originY * BLOCKS_PER_UNIT;
+                        vertexData[offset + VERTEX_FLOAT_Z] = nz + element.rotation.originZ * BLOCKS_PER_UNIT;
+                    }
+                }
+            }
+
+            for (int f = 0; f < faces; f++) {
+                int offset = f * 4 * FLOATS_PER_VERTEX;
+                float ax = vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] - vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X];
+                float ay = vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] - vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y];
+                float az = vertexData[offset + (VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] - vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z];
+
+                float bx = vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X] - vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_X];
+                float by = vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y] - vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Y];
+                float bz = vertexData[offset + (VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z] - vertexData[offset + (VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX) + VERTEX_FLOAT_Z];
+
+                float nx = (ay * bz) - (az * by);
+                float ny = (az * bx) - (ax * bz);
+                float nz = (ax * by) - (ay * bx);
+
+                float length = MathHelper.sqrt_float(nx * nx + ny * ny + nz * nz);
+
+                nx /= length;
+                ny /= length;
+                nz /= length;
+
+                normalData[f * FLOATS_PER_NORMAL + NORMAL_FLOAT_X] = nx;
+                normalData[f * FLOATS_PER_NORMAL + NORMAL_FLOAT_Y] = ny;
+                normalData[f * FLOATS_PER_NORMAL + NORMAL_FLOAT_Z] = nz;
+            }
+        }
+    }
+}
diff --git a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Element.java b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Element.java
new file mode 100644
index 000000000..809e1e305
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Element.java
@@ -0,0 +1,167 @@
+package org.useless.dragonfly.data.block.mojang;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import net.minecraft.core.util.helper.Direction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.useless.util.GsonHelper;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class Element {
+    protected static final boolean DEFAULT_SHADE = true;
+    protected static final int DEFAULT_LIGHT_EMISSION = 0;
+
+    public final float fromX;
+    public final float fromY;
+    public final float fromZ;
+
+    public final float toX;
+    public final float toY;
+    public final float toZ;
+
+    /**
+     *  Defines the rotation of an element.
+     */
+    public final @Nullable Rotation rotation;
+
+    /**
+     * Defines if shadows are rendered (true - default), not (false).
+     */
+    public final boolean shade;
+    /**
+     * Defines the minimum light level that the element can receive. Can be 0-15, defaults to 0.
+     */
+    public final int lightEmission;
+    public final @NotNull Map<@NotNull Direction, @NotNull Face> faces;
+
+    protected Element(
+        float fromX, float fromY, float fromZ,
+        float toX, float toY, float toZ,
+        @Nullable Rotation rotation,
+        boolean shade,
+        int lightEmission,
+        @NotNull Map<@NotNull Direction, @NotNull Face> faces)
+    {
+        this.fromX = fromX;
+        this.fromY = fromY;
+        this.fromZ = fromZ;
+        this.toX = toX;
+        this.toY = toY;
+        this.toZ = toZ;
+        this.rotation = rotation;
+        this.shade = shade;
+        this.lightEmission = lightEmission;
+        this.faces = faces;
+    }
+
+    @Override
+    public String toString() {
+        return "Element{" +
+            "fromX=" + fromX +
+            ", fromY=" + fromY +
+            ", fromZ=" + fromZ +
+            ", toX=" + toX +
+            ", toY=" + toY +
+            ", toZ=" + toZ +
+            ", rotation=" + rotation +
+            ", shade=" + shade +
+            ", lightEmission=" + lightEmission +
+            ", faces=" + faces +
+            '}';
+    }
+
+    @SuppressWarnings("unused")
+    public static class Builder {
+        protected final float fromX;
+        protected final float fromY;
+        protected final float fromZ;
+        protected final float toX;
+        protected final float toY;
+        protected final float toZ;
+
+        protected @Nullable Rotation rotation = null;
+        protected boolean shade = DEFAULT_SHADE;
+        protected int lightEmission = DEFAULT_LIGHT_EMISSION;
+        protected final @NotNull Map<@NotNull Direction, Face. @NotNull Builder> faces = new HashMap<>();
+
+        public Builder(float fromX, float fromY, float fromZ,
+                       float toX, float toY, float toZ) {
+            this.fromX = fromX;
+            this.fromY = fromY;
+            this.fromZ = fromZ;
+            this.toX = toX;
+            this.toY = toY;
+            this.toZ = toZ;
+        }
+
+        public @NotNull Builder setRotation(@Nullable Rotation.Builder rotation) {
+            this.rotation = rotation == null ? null : rotation.build();
+            return this;
+        }
+
+        public @NotNull Builder setShade(boolean shade) {
+            this.shade = shade;
+            return this;
+        }
+
+        public @NotNull Builder setLightEmission(int lightEmission) {
+            this.lightEmission = lightEmission;
+            return this;
+        }
+
+        public @NotNull Builder addFace(@NotNull Direction direction, Face. @NotNull Builder face) {
+            faces.put(direction, face);
+            return this;
+        }
+
+        protected @NotNull Element build() {
+            Map<Direction, Face> faceMap = new HashMap<>();
+            for (Map.Entry<Direction, Face.Builder> e : faces.entrySet()) {
+                faceMap.put(e.getKey(), e.getValue().build(fromX, fromY, fromZ, toX, toY, toZ, e.getKey()));
+            }
+            return new Element(
+                fromX, fromY, fromZ,
+                toX, toY, toZ,
+                rotation,
+                shade,
+                lightEmission,
+                faceMap);
+        }
+
+        public static class Serializer implements JsonSerializer<Builder>, JsonDeserializer<Builder> {
+
+            @Override
+            public Builder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+                JsonObject object = json.getAsJsonObject();
+                float[] from = GsonHelper.getAsFloatArray(object.get("from"), 3);
+                float[] to = GsonHelper.getAsFloatArray(object.get("to"), 3);
+                Builder builder = new Builder(from[0], from[1], from[2], to[0], to[1], to[2]);
+                if (object.has("rotation")) builder.setRotation(context.deserialize(object.get("rotation"), Rotation.Builder.class));
+                if (object.has("shade")) builder.setShade(object.get("shade").getAsBoolean());
+                if (object.has("light_emission")) builder.setLightEmission(object.get("light_emission").getAsInt());
+                JsonObject faces = object.getAsJsonObject("faces");
+                for (Map.Entry<String, JsonElement> e : faces.entrySet()) {
+                    builder.addFace(Direction.valueOf(e.getKey().toUpperCase(Locale.ROOT)), context.deserialize(e.getValue(), Face.Builder.class));
+                }
+                return builder;
+            }
+
+            @Override
+            public JsonElement serialize(Builder src, Type typeOfSrc, JsonSerializationContext context) {
+                throw new UnsupportedOperationException();
+            }
+
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Face.java b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Face.java
new file mode 100644
index 000000000..4e73e6f42
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Face.java
@@ -0,0 +1,223 @@
+package org.useless.dragonfly.data.block.mojang;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import net.minecraft.core.util.helper.Direction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.useless.util.GsonHelper;
+
+import java.lang.reflect.Type;
+import java.util.Locale;
+
+public class Face {
+    protected static final int DEFAULT_ROTATION = 0;
+    protected static final int DEFAULT_TINT_INDEX = -1;
+
+    public final float u1;
+    public final float u2;
+    public final float v1;
+    public final float v2;
+
+    /**
+     * Specifies the texture in form of the texture variable prepended with a <code>#</code>.
+     */
+    public final String texture;
+    /**
+     * Specifies whether a face does not need to be rendered when there is a block touching it in the specified position.
+     * The position can any {@link Direction}.
+     * It also determines the side of the block to use the light level from for lighting the face, and if unset, defaults to the side.
+     */
+    public final @Nullable Direction cullFace;
+
+    /**
+     * Rotates the texture clockwise by the specified number of degrees. Can be 0, 90, 180, or 270. Defaults to 0.
+     * Rotation does not affect which part of the texture is used.
+     * Instead, it amounts to permutation of the selected texture vertexes (selected implicitly, or explicitly though uv).
+     */
+    public final int rotation;
+
+    /**
+     * Determines whether to tint the texture using a hardcoded tint index.
+     * The default value, -1, indicates not to use the tint.
+     * Any other number is provided to BlockColors to get the tint value corresponding to that index.
+     * However, most blocks do not have a tint value defined (in which case white is used).
+     */
+    public final int tintIndex;
+
+    protected Face(float u1, float u2, float v1, float v2, @NotNull String texture, @Nullable Direction cullFace, int rotation, int tintIndex) {
+        this.u1 = u1;
+        this.u2 = u2;
+        this.v1 = v1;
+        this.v2 = v2;
+        this.texture = texture;
+        this.cullFace = cullFace;
+        this.rotation = rotation;
+        this.tintIndex = tintIndex;
+    }
+
+    @Override
+    public String toString() {
+        return "Face{" +
+            "u1=" + u1 +
+            ", u2=" + u2 +
+            ", v1=" + v1 +
+            ", v2=" + v2 +
+            ", texture='" + texture + '\'' +
+            ", cullFace=" + cullFace +
+            ", rotation=" + rotation +
+            ", tintIndex=" + tintIndex +
+            '}';
+    }
+
+    @SuppressWarnings("unused")
+    public static class Builder {
+        protected @Nullable Float u1 = null;
+        protected @Nullable Float u2 = null;
+        protected @Nullable Float v1 = null;
+        protected @Nullable Float v2 = null;
+
+        protected boolean mirrorU = false;
+        protected boolean mirrorV = false;
+
+        protected final @NotNull String texture;
+        protected @Nullable Direction cullFace = null;
+        protected int rotation = DEFAULT_ROTATION;
+        protected int tintIndex = DEFAULT_TINT_INDEX;
+
+        public Builder(@NotNull String texture) {
+            this.texture = texture;
+        }
+
+        public @NotNull Builder setUVs(float u1, float v1, float u2, float v2) {
+            this.u1 = u1;
+            this.u2 = u2;
+            this.v1 = v1;
+            this.v2 = v2;
+            return this;
+        }
+
+        public @NotNull Builder setMirrorU(boolean mirrorU) {
+            this.mirrorU = mirrorU;
+            return this;
+        }
+
+        public @NotNull Builder setMirrorV(boolean mirrorV) {
+            this.mirrorV = mirrorV;
+            return this;
+        }
+
+        public @NotNull Builder setCullFace(@NotNull Direction cullFace) {
+            this.cullFace = cullFace;
+            return this;
+        }
+
+        public @NotNull Builder setRotation(int rotation) {
+            this.rotation = rotation;
+            return this;
+        }
+
+        public @NotNull Builder setTintIndex(int tintIndex) {
+            this.tintIndex = tintIndex;
+            return this;
+        }
+
+        protected @NotNull Face build(float fromX, float fromY, float fromZ, float toX, float toY, float toZ, @NotNull Direction sideFacing) {
+            float x1;
+            float x2;
+            float y1;
+            float y2;
+            if (u1 == null || u2 == null || v1 == null || v2 == null) {
+                switch (sideFacing) {
+                    case UP:
+                        x1 = fromX;
+                        x2 = toX;
+                        y1 = fromZ;
+                        y2 = toZ;
+                        break;
+                    case DOWN:
+                        x1 = fromX;
+                        x2 = toX;
+                        y1 = BlockModelMojangData.UNITS_PER_BLOCK - toZ;
+                        y2 = BlockModelMojangData.UNITS_PER_BLOCK - fromZ;
+                        break;
+                    case NORTH:
+                        x1 = BlockModelMojangData.UNITS_PER_BLOCK - toX;
+                        x2 = BlockModelMojangData.UNITS_PER_BLOCK - fromX;
+                        y1 = BlockModelMojangData.UNITS_PER_BLOCK - toY;
+                        y2 = BlockModelMojangData.UNITS_PER_BLOCK - fromY;
+                        break;
+                    case SOUTH:
+                        x1 = fromX;
+                        x2 = toX;
+                        y1 = BlockModelMojangData.UNITS_PER_BLOCK - toY;
+                        y2 = BlockModelMojangData.UNITS_PER_BLOCK - fromY;
+                        break;
+                    case WEST:
+                        x1 = fromZ;
+                        x2 = toZ;
+                        y1 = BlockModelMojangData.UNITS_PER_BLOCK - toY;
+                        y2 = BlockModelMojangData.UNITS_PER_BLOCK - fromY;
+                        break;
+                    case EAST:
+                        x1 = BlockModelMojangData.UNITS_PER_BLOCK - toZ;
+                        x2 = BlockModelMojangData.UNITS_PER_BLOCK - fromZ;
+                        y1 = BlockModelMojangData.UNITS_PER_BLOCK - toY;
+                        y2 = BlockModelMojangData.UNITS_PER_BLOCK - fromY;
+                        break;
+                    default:
+                        x1 = 0;
+                        x2 = BlockModelMojangData.UNITS_PER_BLOCK;
+                        y1 = 0;
+                        y2 = BlockModelMojangData.UNITS_PER_BLOCK;
+                }
+            } else {
+                x1 = u1;
+                x2 = u2;
+                y1 = v1;
+                y2 = v2;
+            }
+
+            if (mirrorU) {
+                float _x = x2;
+                x2 = x1;
+                x1 = _x;
+            }
+
+            if (mirrorV) {
+                float _y = y2;
+                y2 = y1;
+                y1 = _y;
+            }
+
+            return new Face(x1, x2, y1, y2, texture, cullFace, rotation, tintIndex);
+        }
+
+        public static class Serializer implements JsonSerializer<Builder>, JsonDeserializer<Builder> {
+
+            @Override
+            public Builder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+                JsonObject object = json.getAsJsonObject();
+                Builder builder = new Builder(object.get("texture").getAsString());
+                if (object.has("uv")) {
+                    float[] uvs = GsonHelper.getAsFloatArray(object.get("uv"), 4);
+                    builder.setUVs(uvs[0], uvs[1], uvs[2], uvs[3]);
+                }
+                if (object.has("cullface")) builder.setCullFace(Direction.valueOf(object.get("cullface").getAsString().toUpperCase(Locale.ROOT)));
+                if (object.has("rotation")) builder.setRotation(object.get("rotation").getAsInt());
+                if (object.has("tintindex")) builder.setTintIndex(object.get("tintindex").getAsInt());
+                return builder;
+            }
+
+            @Override
+            public JsonElement serialize(Builder src, Type typeOfSrc, JsonSerializationContext context) {
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+}
diff --git a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Rotation.java b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Rotation.java
new file mode 100644
index 000000000..383cd4897
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/Rotation.java
@@ -0,0 +1,109 @@
+package org.useless.dragonfly.data.block.mojang;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import net.minecraft.core.util.helper.Axis;
+import org.jetbrains.annotations.NotNull;
+import org.useless.util.GsonHelper;
+
+import java.lang.reflect.Type;
+import java.util.Locale;
+import java.util.Objects;
+
+public class Rotation {
+    protected static final boolean DEFAULT_RESCALE = false;
+
+    public final float originX;
+    public final float originY;
+    public final float originZ;
+
+    /**
+     * Specifies the direction of rotation
+     */
+    public final Axis axis;
+
+    /**
+     * Specifies the angle of rotation.
+     */
+    public final float angle;
+
+    /**
+     * Specifies whether or not to scale the faces across the whole block. Can be true or false. Defaults to false
+     */
+    public final boolean rescale;
+
+    protected Rotation(float originX, float originY, float originZ, @NotNull Axis axis, float angle, boolean rescale) {
+        this.originX = originX;
+        this.originY = originY;
+        this.originZ = originZ;
+        this.axis = axis;
+        this.angle = angle;
+        this.rescale = rescale;
+    }
+
+    @Override
+    public String toString() {
+        return "Rotation{" +
+            "originX=" + originX +
+            ", originY=" + originY +
+            ", originZ=" + originZ +
+            ", axis=" + axis +
+            ", angle=" + angle +
+            ", rescale=" + rescale +
+            '}';
+    }
+
+    @SuppressWarnings("unused")
+    public static class Builder {
+        protected final float originX;
+        protected final float originY;
+        protected final float originZ;
+        protected final @NotNull Axis axis;
+        protected final float angle;
+
+        public boolean rescale = DEFAULT_RESCALE;
+
+        public Builder(
+            float originX, float originY, float originZ,
+            @NotNull Axis axis,
+            float angle
+        ) {
+            this.originX = originX;
+            this.originY = originY;
+            this.originZ = originZ;
+            this.axis = Objects.requireNonNull(axis);
+            this.angle = angle;
+        }
+
+        public @NotNull Builder setRescale(boolean rescale) {
+            this.rescale = rescale;
+            return this;
+        }
+
+        protected @NotNull Rotation build() {
+            return new Rotation(originX, originY, originZ, axis, angle, rescale);
+        }
+
+        public static class Serializer implements JsonSerializer<Rotation.Builder>, JsonDeserializer<Rotation.Builder> {
+
+            @Override
+            public Builder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+                JsonObject object = json.getAsJsonObject();
+                float[] origin = GsonHelper.getAsFloatArray(object.get("origin"), 3);
+                Rotation.Builder builder = new Builder(origin[0], origin[1], origin[2], Axis.valueOf(object.get("axis").getAsString().toUpperCase(Locale.ROOT)), object.get("angle").getAsFloat());
+                if (object.has("rescale")) builder.setRescale(object.get("rescale").getAsBoolean());
+                return builder;
+            }
+
+            @Override
+            public JsonElement serialize(Builder src, Type typeOfSrc, JsonSerializationContext context) {
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+}
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
new file mode 100644
index 000000000..4c3804439
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/models/block/StaticBlockModel.java
@@ -0,0 +1,50 @@
+package org.useless.dragonfly.models.block;
+
+import net.minecraft.client.render.block.color.BlockColor;
+import net.minecraft.client.render.block.model.BlockModel;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.core.block.BlockLogic;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.useless.dragonfly.DisplayPos;
+
+public interface StaticBlockModel {
+
+    /**
+     * @return True if anything rendered, false otherwise
+     */
+    boolean renderStandalone(@NotNull BlockModel<? extends BlockLogic> sourceModel, @NotNull Tessellator tessellator, double x, double y, double z, int metadata, @NotNull BlockColor color, float brightness, float alpha);
+
+    /**
+     * @return True if anything rendered, false otherwise
+     */
+    boolean renderAttached(@NotNull BlockModel<? extends BlockLogic> sourceModel, @NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z, double xOff, double yOff, double zOff, boolean cullFaces, @Nullable IconCoordinate overrideTexture);
+
+    /**
+     * @return Block texture to overlay when inside a block
+     */
+    @Nullable IconCoordinate getOverlay();
+
+    /**
+     * @return Block texture to use for particles when being broken from a specific side
+     */
+    @Nullable IconCoordinate getParticle(@NotNull Side side);
+
+    /**
+     * @return Color index for particle to use from side, default -1 for no color
+     */
+    int particleColorIndex(@NotNull Side side);
+
+    /**
+     * @return Return the render pass to render the model on
+     */
+    int renderLayer();
+
+    /**
+     * @return Return the display position to use for the given id
+     */
+    @NotNull DisplayPos getItemDisplayPos(@NotNull String id);
+}
diff --git a/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticModelMojang.java b/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticModelMojang.java
new file mode 100644
index 000000000..6490736fc
--- /dev/null
+++ b/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticModelMojang.java
@@ -0,0 +1,449 @@
+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.BlockModel;
+import net.minecraft.client.render.block.model.BlockModelStandard;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.core.block.BlockLogic;
+import net.minecraft.core.util.helper.Color;
+import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.opengl.GL11;
+import org.useless.dragonfly.DisplayPos;
+import org.useless.dragonfly.data.block.mojang.BlockModelMojangData;
+import org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData;
+import org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element;
+import org.useless.dragonfly.models.block.StaticBlockModel;
+
+import java.util.Locale;
+
+import static net.minecraft.client.render.block.model.BlockModel.ENABLE_DIRECTIONAL_LIGHTING;
+import static net.minecraft.client.render.block.model.BlockModel.FULL_CUBE_THRESHOLD;
+import static net.minecraft.client.render.block.model.BlockModel.SIDE_LIGHT_MULTIPLIER;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.FLOATS_PER_NORMAL;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.FLOATS_PER_VERTEX;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.NORMAL_FLOAT_X;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.NORMAL_FLOAT_Y;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.NORMAL_FLOAT_Z;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_BOTTOM_LEFT;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_BOTTOM_RIGHT;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_FLOAT_U;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_FLOAT_V;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_FLOAT_X;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_FLOAT_Y;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_FLOAT_Z;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_TOP_LEFT;
+import static org.useless.dragonfly.data.block.mojang.CompiledBlockModelMojangData.C_Element.VERTEX_TOP_RIGHT;
+
+public class StaticModelMojang implements StaticBlockModel {
+    protected static final Minecraft MC = Minecraft.getMinecraft();
+    protected static final LightingCache LIGHTING_CACHE = new LightingCache();
+
+    protected static final byte[] V_TOP_X = new byte[] {0, 0, -1, 0, 0, 0};
+    protected static final byte[] V_TOP_Y = new byte[] {0, 0, 0, 1, 0, 0};
+    protected static final byte[] V_TOP_Z = new byte[] {1, 1, 0, 0, 1, 1};
+
+    protected static final byte[] V_LEF_X = new byte[] {-1, 1, 0, -1, 0, 0};
+    protected static final byte[] V_LEF_Y = new byte[] {0, 0, 1, 0, 1, -1};
+    protected static final byte[] V_LEF_Z = new byte[] {0, 0, 0, 0, 0, 0};
+
+    protected final CompiledBlockModelMojangData compiled;
+    public StaticModelMojang(BlockModelMojangData data) {
+        this.compiled = new CompiledBlockModelMojangData(data);
+    }
+
+    @Override
+    public boolean renderStandalone(@NotNull BlockModel<? extends BlockLogic> sourceModel, @NotNull Tessellator tessellator, double x, double y, double z, int metadata, @NotNull BlockColor color, float brightness, float alpha) {
+        if (compiled.elements.length == 0) return false;
+
+        GL11.glPushMatrix();
+        for (int i = 0; i < compiled.elements.length; i++) {
+            C_Element element = compiled.elements[i];
+
+            if (element.shade) {
+                GL11.glEnable(GL11.GL_LIGHTING);
+            } else {
+                GL11.glDisable(GL11.GL_LIGHTING);
+            }
+
+            tessellator.startDrawingQuads();
+            for (int face = 0; face < element.faces; face++) {
+                IconCoordinate coordinate = compiled.textures.getOrDefault(element.textures[face], BlockModelStandard.BLOCK_TEXTURE_UNASSIGNED);
+
+                // Todo fix this needing to be hardcoded to get overbright looking right
+                if (LightmapHelper.isLightmapEnabled() && element.lightEmission == 15) {
+                    brightness = 1f;
+                    LightmapHelper.setLightmapCoord(15, 15);
+                } else {
+                    brightness = Math.max(brightness, element.lightEmission/15f);
+                }
+
+                float r = 1;
+                float g = 1;
+                float b = 1;
+                if (element.tintIndices[face] >= 0) {
+                    int c = color.getFallbackColor(metadata, element.tintIndices[face]);
+                    r = Color.redFromInt(c) / 255f;
+                    g = Color.greenFromInt(c) / 255f;
+                    b = Color.blueFromInt(c) / 255f;
+                }
+
+                final int offset = face * 4 * FLOATS_PER_VERTEX;
+                for (int v = 0; v < 4; v++) {
+                    tessellator.setNormal(element.normalData[face * FLOATS_PER_NORMAL + NORMAL_FLOAT_X], element.normalData[face * FLOATS_PER_NORMAL + NORMAL_FLOAT_Y], element.normalData[face * FLOATS_PER_NORMAL + NORMAL_FLOAT_Z]);
+                    tessellator.setColorOpaque_F(r * brightness, g * brightness, b * brightness);
+                    tessellator.addVertexWithUV(
+                        element.vertexData[offset + v * FLOATS_PER_VERTEX + VERTEX_FLOAT_X] - 0.5f,
+                        element.vertexData[offset + v * FLOATS_PER_VERTEX + VERTEX_FLOAT_Y] - 0.5f,
+                        element.vertexData[offset + v * FLOATS_PER_VERTEX + VERTEX_FLOAT_Z] - 0.5f,
+                        coordinate.getSubIconU(element.vertexData[offset + v * FLOATS_PER_VERTEX + VERTEX_FLOAT_U]),
+                        coordinate.getSubIconV(element.vertexData[offset + v * FLOATS_PER_VERTEX + VERTEX_FLOAT_V]));
+                }
+            }
+            tessellator.draw();
+        }
+        GL11.glPopMatrix();
+        return true;
+    }
+
+    @Override
+    public boolean renderAttached(@NotNull BlockModel<? extends BlockLogic> sourceModel, @NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z, double xOff, double yOff, double zOff, boolean cullFaces, @Nullable IconCoordinate overrideTexture) {
+        if (compiled.elements.length == 0) return false;
+        boolean didRender = false;
+        LIGHTING_CACHE.setupCache(sourceModel.block, worldSource, x, y, z);
+
+        BlockColor color = BlockColorDispatcher.getInstance().getDispatch(sourceModel.block);
+        for (int i = 0; i < compiled.elements.length; i++) {
+            final C_Element element = compiled.elements[i];
+            for (int face = 0; face < element.faces; face++) {
+                if (cullFaces && cullSide(worldSource, x, y, z, element.cullfaces[face])) continue;
+                final IconCoordinate coordinate = overrideTexture == null ? compiled.textures.getOrDefault(element.textures[face], BlockModelStandard.BLOCK_TEXTURE_UNASSIGNED) : overrideTexture;
+                final Direction direction = element.directions[face];
+
+                final float minBrightness = element.lightEmission/15f;
+
+                final int topX = V_TOP_X[direction.getId()];
+                final int topY = V_TOP_Y[direction.getId()];
+                final int topZ = V_TOP_Z[direction.getId()];
+                final float topP;
+                final float botP;
+                final int lefX = V_LEF_X[direction.getId()];
+                final int lefY = V_LEF_Y[direction.getId()];
+                final int lefZ = V_LEF_Z[direction.getId()];
+                final float lefP;
+                final float rigP;
+                final float depth;
+                switch (direction) {
+                    case DOWN:
+                        depth = 0 + element.minY;
+                        topP = element.maxZ; botP = element.minZ;
+                        lefP = 1 - element.minX; rigP = 1 - element.maxX;
+                        break;
+                    case UP:
+                        depth = 1 - element.maxY;
+                        topP = element.maxZ; botP = element.minZ;
+                        lefP = element.maxX; rigP = element.minX;
+                        break;
+                    case NORTH:
+                        depth = 0 + element.minZ;
+                        topP = 1 - element.minX; botP = 1 - element.maxX;
+                        lefP = element.maxY; rigP = element.minY;
+                        break;
+                    case SOUTH:
+                        depth = 1 - element.maxZ;
+                        topP = element.maxY; botP = element.minY;
+                        lefP = 1 - element.minX; rigP = 1 - element.maxX;
+                        break;
+                    case WEST:
+                        depth = 0 + element.minX;
+                        topP = element.maxZ; botP = element.minZ;
+                        lefP = element.maxY; rigP = element.minY;
+                        break;
+                    case EAST:
+                    default:
+                        depth = 1 - element.maxX;
+                        topP = element.maxZ; botP = element.minZ;
+                        lefP = 1 - element.minY; rigP = 1 - element.maxY;
+                        break;
+                }
+
+                final boolean useAO = compiled.data.ambientOcclusion && MC.isAmbientOcclusionEnabled() && element.shade;
+                final boolean isFullCube = depth <= FULL_CUBE_THRESHOLD && element.shade;
+
+                final float r;
+                final float g;
+                final float b;
+                if (element.tintIndices[face] >= 0) {
+                    int c = color.getWorldColor(worldSource, x, y, z, element.tintIndices[face]);
+                    r = Color.redFromInt(c) / 255f;
+                    g = Color.greenFromInt(c) / 255f;
+                    b = Color.blueFromInt(c) / 255f;
+                } else {
+                    r = 1;
+                    g = 1;
+                    b = 1;
+                }
+
+                final int dirX = direction.getOffsetX();
+                final int dirY = direction.getOffsetY();
+                final int dirZ = direction.getOffsetZ();
+
+                final int lightmapCoordTopLeft;
+                final int lightmapCoordBottomLeft;
+                final int lightmapCoordBottomRight;
+                final int lightmapCoordTopRight;
+
+                if(LightmapHelper.isLightmapEnabled()) {
+                    if (useAO) {
+                        final int dirX2;
+                        final int dirY2;
+                        final int dirZ2;
+                        if (!isFullCube) {
+                            dirX2 = 0;
+                            dirY2 = 0;
+                            dirZ2 = 0;
+                        } else {
+                            dirX2 = dirX;
+                            dirY2 = dirY;
+                            dirZ2 = dirZ;
+                        }
+
+                        final boolean topT = LIGHTING_CACHE.getOpacity(dirX2 + topX, dirY2 + topY, dirZ2 + topZ);
+                        final boolean botT = LIGHTING_CACHE.getOpacity(dirX2 - topX, dirY2 - topY, dirZ2 - topZ);
+                        final boolean lefT = LIGHTING_CACHE.getOpacity(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ);
+                        final boolean rigT = LIGHTING_CACHE.getOpacity(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ);
+
+                        final boolean topLefT = LIGHTING_CACHE.getOpacity(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ);
+                        final boolean topRigT = LIGHTING_CACHE.getOpacity(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ);
+                        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 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 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));
+
+                        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);
+                    } else {
+                        final int lmc;
+                        if (!isFullCube) {
+                            lmc = getLightmap(0, 0, 0, element.lightEmission);
+                        } else {
+                            lmc = getLightmap(dirX, dirY,  dirZ, element.lightEmission);
+                        }
+                        lightmapCoordTopLeft = lightmapCoordBottomLeft = lightmapCoordBottomRight = lightmapCoordTopRight = lmc;
+                    }
+                } else {
+                    lightmapCoordTopLeft = 0;
+                    lightmapCoordBottomLeft = 0;
+                    lightmapCoordBottomRight = 0;
+                    lightmapCoordTopRight = 0;
+                }
+
+                float lightTR;
+                float lightBR;
+                float lightBL;
+                float lightTL;
+
+                if (useAO) {
+                    {
+                        final float dirB = getBrightness(dirX, dirY, dirZ, minBrightness);
+                        final boolean lefT = LIGHTING_CACHE.getOpacity(dirX + lefX, dirY + lefY, dirZ + lefZ);
+                        final boolean botT = LIGHTING_CACHE.getOpacity(dirX - topX, dirY - topY, dirZ - topZ);
+                        final boolean topT = LIGHTING_CACHE.getOpacity(dirX + topX, dirY + topY, dirZ + topZ);
+                        final boolean rigT = LIGHTING_CACHE.getOpacity(dirX - lefX, dirY - lefY, dirZ - lefZ);
+                        final float lB = getBrightness(dirX + lefX, dirY + lefY, dirZ + lefZ, minBrightness);
+                        final float bB = getBrightness(dirX - topX, dirY - topY, dirZ - topZ, minBrightness);
+                        final float tB = getBrightness(dirX + topX, dirY + topY, dirZ + topZ, minBrightness);
+                        final float rB = getBrightness(dirX - lefX, dirY - lefY, dirZ - lefZ, minBrightness);
+                        final float blB = botT && lefT ? lB : getBrightness(dirX + lefX - topX, dirY + lefY - topY, dirZ + lefZ - topZ, minBrightness);
+                        final float tlB = topT && lefT ? lB : getBrightness(dirX + lefX + topX, dirY + lefY + topY, dirZ + lefZ + topZ, minBrightness);
+                        final float brB = botT && rigT ? rB : getBrightness(dirX - lefX - topX, dirY - lefY - topY, dirZ - lefZ - topZ, minBrightness);
+                        final float trB = topT && rigT ? rB : getBrightness(dirX - lefX + topX, dirY - lefY + topY, dirZ - lefZ + topZ, minBrightness);
+                        lightTL = (tlB + lB + tB + dirB) / 4.0F;
+                        lightTR = (tB + dirB + trB + rB) / 4.0F;
+                        lightBR = (dirB + bB + rB + brB) / 4.0F;
+                        lightBL = (lB + blB + dirB + bB) / 4.0F;
+                    }
+                    if (!isFullCube) {
+                        final float dirB = getBrightness(0, 0, 0, minBrightness);
+                        final boolean lefT = LIGHTING_CACHE.getOpacity(lefX, lefY, lefZ);
+                        final boolean botT = LIGHTING_CACHE.getOpacity(-topX, -topY, -topZ);
+                        final boolean topT = LIGHTING_CACHE.getOpacity(topX, topY, topZ);
+                        final boolean rigT = LIGHTING_CACHE.getOpacity(-lefX, -lefY, -lefZ);
+                        final float lB = getBrightness(lefX, lefY, lefZ, minBrightness);
+                        final float bB = getBrightness(-topX, -topY, -topZ, minBrightness);
+                        final float tB = getBrightness(topX, topY, topZ, minBrightness);
+                        final float rB = getBrightness(-lefX, -lefY, -lefZ, minBrightness);
+                        final float blB = botT && lefT ? lB : getBrightness(lefX - topX, lefY - topY, lefZ - topZ, minBrightness);
+                        final float tlB = topT && lefT ? lB : getBrightness(lefX + topX, lefY + topY, lefZ + topZ, minBrightness);
+                        final float brB = botT && rigT ? rB : getBrightness(-lefX - topX, -lefY - topY, -lefZ - topZ, minBrightness);
+                        final float trB = topT && rigT ? rB : getBrightness(-lefX + topX, -lefY + topY, -lefZ + topZ, minBrightness);
+                        lightTL = (tlB + lB + tB + dirB) / 4.0F * depth + lightTL * (1 - depth);
+                        lightTR = (tB + dirB + trB + rB) / 4.0F * depth + lightTR * (1 - depth);
+                        lightBR = (dirB + bB + rB + brB) / 4.0F * depth + lightBR * (1 - depth);
+                        lightBL = (lB + blB + dirB + bB) / 4.0F * depth + lightBL * (1 - depth);
+                    }
+                } else {
+                    final int dirX2;
+                    final int dirY2;
+                    final int dirZ2;
+                    if (!isFullCube) {
+                        dirX2 = 0;
+                        dirY2 = 0;
+                        dirZ2 = 0;
+                    } else {
+                        dirX2 = dirX;
+                        dirY2 = dirY;
+                        dirZ2 = dirZ;
+                    }
+
+                    lightTL = lightBL = lightBR = lightTR = getBrightness(dirX2, dirY2, dirZ2, minBrightness);
+                }
+
+                final float sideLight = (element.shade && ENABLE_DIRECTIONAL_LIGHTING) ? SIDE_LIGHT_MULTIPLIER[direction.getId()] : 1;
+                float colorRedBottomLeft = r * sideLight;
+                float colorRedBottomRight = colorRedBottomLeft;
+                float colorRedTopRight = colorRedBottomLeft;
+                float colorRedTopLeft = colorRedBottomLeft;
+
+                float colorGreenBottomLeft = g * sideLight;
+                float colorGreenBottomRight = colorGreenBottomLeft;
+                float colorGreenTopRight = colorGreenBottomLeft;
+                float colorGreenTopLeft = colorGreenBottomLeft;
+
+                float colorBlueBottomLeft = b * sideLight;
+                float colorBlueBottomRight = colorBlueBottomLeft;
+                float colorBlueTopRight = colorBlueBottomLeft;
+                float colorBlueTopLeft = colorBlueBottomLeft;
+
+                final float tl = topP * lightTL + (1 - topP) * lightBL;
+                final float tr = topP * lightTR + (1 - topP) * lightBR;
+                final float bl = botP * lightTL + (1 - botP) * lightBL;
+                final float br = botP * lightTR + (1 - botP) * lightBR;
+                final float ltl = lefP * tl + (1 - lefP) * tr;
+                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 * FLOATS_PER_VERTEX;
+
+                tessellator.setColorOpaque_F(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
+                if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
+                tessellator.addVertexWithUV(
+                    element.vertexData[offset + VERTEX_TOP_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_X] + x + xOff,
+                    element.vertexData[offset + VERTEX_TOP_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_Y] + y + yOff,
+                    element.vertexData[offset + VERTEX_TOP_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_Z] + z + zOff,
+                    coordinate.getSubIconU(element.vertexData[offset + VERTEX_TOP_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_U]),
+                    coordinate.getSubIconV(element.vertexData[offset + VERTEX_TOP_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_V]));
+
+                tessellator.setColorOpaque_F(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
+                if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomLeft);
+                tessellator.addVertexWithUV(
+                    element.vertexData[offset + VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_X] + x + xOff,
+                    element.vertexData[offset + VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_Y] + y + yOff,
+                    element.vertexData[offset + VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_Z] + z + zOff,
+                    coordinate.getSubIconU(element.vertexData[offset + VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_U]),
+                    coordinate.getSubIconV(element.vertexData[offset + VERTEX_BOTTOM_LEFT * FLOATS_PER_VERTEX + VERTEX_FLOAT_V]));
+
+                tessellator.setColorOpaque_F(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
+                if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomRight);
+                tessellator.addVertexWithUV(
+                    element.vertexData[offset + VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_X] + x + xOff,
+                    element.vertexData[offset + VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_Y] + y + yOff,
+                    element.vertexData[offset + VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_Z] + z + zOff,
+                    coordinate.getSubIconU(element.vertexData[offset + VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_U]),
+                    coordinate.getSubIconV(element.vertexData[offset + VERTEX_BOTTOM_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_V]));
+
+                tessellator.setColorOpaque_F(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
+                if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopRight);
+                tessellator.addVertexWithUV(
+                    element.vertexData[offset + VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_X] + x + xOff,
+                    element.vertexData[offset + VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_Y] + y + yOff,
+                    element.vertexData[offset + VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_Z] + z + zOff,
+                    coordinate.getSubIconU(element.vertexData[offset + VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_U]),
+                    coordinate.getSubIconV(element.vertexData[offset + VERTEX_TOP_RIGHT * FLOATS_PER_VERTEX + VERTEX_FLOAT_V]));
+
+                didRender = true;
+            }
+        }
+        return didRender;
+    }
+
+    @Override
+    public @Nullable IconCoordinate getOverlay() {
+        // This breaks the modern mc format of using the "#particle" symbol for the overlay, but due to our changes to the spec this is the best way of going about it
+        return compiled.textures.get("#overlay");
+    }
+
+    @Override
+    public @Nullable IconCoordinate getParticle(@NotNull Side side) {
+        return compiled.textures.get("#particle_" + side.getDirection().name().toLowerCase(Locale.ROOT));
+    }
+
+    @Override
+    public int particleColorIndex(@NotNull Side side) {
+        return compiled.particleIndices[side.getId()];
+    }
+
+    @Override
+    public int renderLayer() {
+        return compiled.renderLayer;
+    }
+
+    @Override
+    public @NotNull DisplayPos getItemDisplayPos(@NotNull String id) {
+        return compiled.displayPosMap.getOrDefault(id, DisplayPos.DEFAULT_DISPLAY_POS);
+    }
+
+    protected boolean cullSide(WorldSource worldSource, int x, int y, int z, @Nullable Direction direction) {
+        return direction != null && worldSource.isBlockOpaqueCube(x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ());
+    }
+
+    protected float getBrightness(int relX, int relY, int relZ, float min) {
+        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);
+        if (block < min) {
+            coord = LightmapHelper.setBlocklightValue(coord, min);
+        }
+        return coord;
+    }
+
+}
diff --git a/game/client/src/main/java/org/useless/util/GsonHelper.java b/game/client/src/main/java/org/useless/util/GsonHelper.java
new file mode 100644
index 000000000..08d5e7129
--- /dev/null
+++ b/game/client/src/main/java/org/useless/util/GsonHelper.java
@@ -0,0 +1,132 @@
+package org.useless.util;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import org.jetbrains.annotations.NotNull;
+
+@SuppressWarnings("unused")
+public final class GsonHelper {
+    private GsonHelper() {}
+
+    public static float[] getAsFloatArray(@NotNull JsonElement element, int expectedSize) throws JsonParseException {
+        if (!element.isJsonArray()) throw new JsonParseException("Provided element is not a jsonArray! " + element);
+        JsonArray arr = element.getAsJsonArray();
+        if (arr.size() != expectedSize) throw new JsonParseException("Provided array is of size '" + arr.size() + "' not expected size of '" + expectedSize + "'!");
+        float[] returnArr = new float[expectedSize];
+        for (int i = 0; i < expectedSize; i++) {
+            JsonElement e = arr.get(i);
+            if (!e.isJsonPrimitive()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            JsonPrimitive p = e.getAsJsonPrimitive();
+            if (!p.isNumber()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            returnArr[i] = p.getAsFloat();
+        }
+        return returnArr;
+    }
+
+    public static double[] getAsDoubleArray(@NotNull JsonElement element, int expectedSize) throws JsonParseException {
+        if (!element.isJsonArray()) throw new JsonParseException("Provided element is not a jsonArray! " + element);
+        JsonArray arr = element.getAsJsonArray();
+        if (arr.size() != expectedSize) throw new JsonParseException("Provided array is of size '" + arr.size() + "' not expected size of '" + expectedSize + "'!");
+        double[] returnArr = new double[expectedSize];
+        for (int i = 0; i < expectedSize; i++) {
+            JsonElement e = arr.get(i);
+            if (!e.isJsonPrimitive()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            JsonPrimitive p = e.getAsJsonPrimitive();
+            if (!p.isNumber()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            returnArr[i] = p.getAsDouble();
+        }
+        return returnArr;
+    }
+
+    public static long[] getAsLongArray(@NotNull JsonElement element, int expectedSize) throws JsonParseException {
+        if (!element.isJsonArray()) throw new JsonParseException("Provided element is not a jsonArray! " + element);
+        JsonArray arr = element.getAsJsonArray();
+        if (arr.size() != expectedSize) throw new JsonParseException("Provided array is of size '" + arr.size() + "' not expected size of '" + expectedSize + "'!");
+        long[] returnArr = new long[expectedSize];
+        for (int i = 0; i < expectedSize; i++) {
+            JsonElement e = arr.get(i);
+            if (!e.isJsonPrimitive()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            JsonPrimitive p = e.getAsJsonPrimitive();
+            if (!p.isNumber()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            returnArr[i] = p.getAsLong();
+        }
+        return returnArr;
+    }
+
+    public static int[] getAsIntArray(@NotNull JsonElement element, int expectedSize) throws JsonParseException {
+        if (!element.isJsonArray()) throw new JsonParseException("Provided element is not a jsonArray! " + element);
+        JsonArray arr = element.getAsJsonArray();
+        if (arr.size() != expectedSize) throw new JsonParseException("Provided array is of size '" + arr.size() + "' not expected size of '" + expectedSize + "'!");
+        int[] returnArr = new int[expectedSize];
+        for (int i = 0; i < expectedSize; i++) {
+            JsonElement e = arr.get(i);
+            if (!e.isJsonPrimitive()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            JsonPrimitive p = e.getAsJsonPrimitive();
+            if (!p.isNumber()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            returnArr[i] = p.getAsInt();
+        }
+        return returnArr;
+    }
+
+    public static short[] getAsShortArray(@NotNull JsonElement element, int expectedSize) throws JsonParseException {
+        if (!element.isJsonArray()) throw new JsonParseException("Provided element is not a jsonArray! " + element);
+        JsonArray arr = element.getAsJsonArray();
+        if (arr.size() != expectedSize) throw new JsonParseException("Provided array is of size '" + arr.size() + "' not expected size of '" + expectedSize + "'!");
+        short[] returnArr = new short[expectedSize];
+        for (int i = 0; i < expectedSize; i++) {
+            JsonElement e = arr.get(i);
+            if (!e.isJsonPrimitive()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            JsonPrimitive p = e.getAsJsonPrimitive();
+            if (!p.isNumber()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            returnArr[i] = p.getAsShort();
+        }
+        return returnArr;
+    }
+
+    public static byte[] getAsByteArray(@NotNull JsonElement element, int expectedSize) throws JsonParseException {
+        if (!element.isJsonArray()) throw new JsonParseException("Provided element is not a jsonArray! " + element);
+        JsonArray arr = element.getAsJsonArray();
+        if (arr.size() != expectedSize) throw new JsonParseException("Provided array is of size '" + arr.size() + "' not expected size of '" + expectedSize + "'!");
+        byte[] returnArr = new byte[expectedSize];
+        for (int i = 0; i < expectedSize; i++) {
+            JsonElement e = arr.get(i);
+            if (!e.isJsonPrimitive()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            JsonPrimitive p = e.getAsJsonPrimitive();
+            if (!p.isNumber()) throw new JsonParseException("Element '" + i + "' in array is not a number!");
+            returnArr[i] = p.getAsByte();
+        }
+        return returnArr;
+    }
+
+    public static boolean[] getAsBooleanArray(@NotNull JsonElement element, int expectedSize) throws JsonParseException {
+        if (!element.isJsonArray()) throw new JsonParseException("Provided element is not a jsonArray! " + element);
+        JsonArray arr = element.getAsJsonArray();
+        if (arr.size() != expectedSize) throw new JsonParseException("Provided array is of size '" + arr.size() + "' not expected size of '" + expectedSize + "'!");
+        boolean[] returnArr = new boolean[expectedSize];
+        for (int i = 0; i < expectedSize; i++) {
+            JsonElement e = arr.get(i);
+            if (!e.isJsonPrimitive()) throw new JsonParseException("Element '" + i + "' in array is not a boolean!");
+            JsonPrimitive p = e.getAsJsonPrimitive();
+            if (!p.isBoolean()) throw new JsonParseException("Element '" + i + "' in array is not a boolean!");
+            returnArr[i] = p.getAsBoolean();
+        }
+        return returnArr;
+    }
+
+    public static String[] getAsStringArray(@NotNull JsonElement element, int expectedSize) throws JsonParseException {
+        if (!element.isJsonArray()) throw new JsonParseException("Provided element is not a jsonArray! " + element);
+        JsonArray arr = element.getAsJsonArray();
+        if (arr.size() != expectedSize) throw new JsonParseException("Provided array is of size '" + arr.size() + "' not expected size of '" + expectedSize + "'!");
+        String[] returnArr = new String[expectedSize];
+        for (int i = 0; i < expectedSize; i++) {
+            JsonElement e = arr.get(i);
+            if (!e.isJsonPrimitive()) throw new JsonParseException("Element '" + i + "' in array is not a string!");
+            JsonPrimitive p = e.getAsJsonPrimitive();
+            if (!p.isString()) throw new JsonParseException("Element '" + i + "' in array is not a string!");
+            returnArr[i] = p.getAsString();
+        }
+        return returnArr;
+    }
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/block.json b/game/client/src/main/resources/assets/minecraft/models/block/block.json
new file mode 100644
index 000000000..aefa892bf
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/block.json
@@ -0,0 +1,35 @@
+{
+    "gui_light": "side",
+    "display": {
+        "gui": {
+            "rotation": [ 30, 225, 0 ],
+            "translation": [ 0, 0, 0],
+            "scale":[ 0.625, 0.625, 0.625 ]
+        },
+        "ground": {
+            "rotation": [ 0, 0, 0 ],
+            "translation": [ 0, 3, 0],
+            "scale":[ 0.25, 0.25, 0.25 ]
+        },
+        "fixed": {
+            "rotation": [ 0, 0, 0 ],
+            "translation": [ 0, 0, 0],
+            "scale":[ 0.5, 0.5, 0.5 ]
+        },
+        "thirdperson_righthand": {
+            "rotation": [ 75, 45, 0 ],
+            "translation": [ 0, 2.5, 0],
+            "scale": [ 0.375, 0.375, 0.375 ]
+        },
+        "firstperson_righthand": {
+            "rotation": [ 0, 45, 0 ],
+            "translation": [ 0, 0, 0 ],
+            "scale": [ 0.40, 0.40, 0.40 ]
+        },
+        "firstperson_lefthand": {
+            "rotation": [ 0, 225, 0 ],
+            "translation": [ 0, 0, 0 ],
+            "scale": [ 0.40, 0.40, 0.40 ]
+        }
+    }
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/cross.json b/game/client/src/main/resources/assets/minecraft/models/block/cross.json
new file mode 100644
index 000000000..37c8b09f2
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/cross.json
@@ -0,0 +1,26 @@
+{
+    "ambientocclusion": false,
+    "textures": {
+        "particle": "#cross"
+    },
+    "elements": [
+        {   "from": [ 0.8, 0, 8 ],
+            "to": [ 15.2, 16, 8 ],
+            "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true },
+            "shade": false,
+            "faces": {
+                "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" },
+                "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" }
+            }
+        },
+        {   "from": [ 8, 0, 0.8 ],
+            "to": [ 8, 16, 15.2 ],
+            "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true },
+            "shade": false,
+            "faces": {
+                "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" },
+                "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" }
+            }
+        }
+    ]
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/cube.json b/game/client/src/main/resources/assets/minecraft/models/block/cube.json
new file mode 100644
index 000000000..25da1167d
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/cube.json
@@ -0,0 +1,25 @@
+{
+    "parent": "block/block",
+    "textures": {
+        "overlay": "#north",
+        "particle_up": "#up",
+        "particle_down": "#down",
+        "particle_north": "#north",
+        "particle_south": "#south",
+        "particle_west": "#west",
+        "particle_east": "#east"
+    },
+    "elements": [
+        {   "from": [ 0, 0, 0 ],
+            "to": [ 16, 16, 16 ],
+            "faces": {
+                "down":  { "texture": "#down", "cullface": "down" },
+                "up":    { "texture": "#up", "cullface": "up" },
+                "north": { "texture": "#north", "cullface": "north" },
+                "south": { "texture": "#south", "cullface": "south" },
+                "west":  { "texture": "#west", "cullface": "west" },
+                "east":  { "texture": "#east", "cullface": "east" }
+            }
+        }
+    ]
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/cube_all.json b/game/client/src/main/resources/assets/minecraft/models/block/cube_all.json
new file mode 100644
index 000000000..9af8ca854
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/cube_all.json
@@ -0,0 +1,11 @@
+{
+    "parent": "block/cube",
+    "textures": {
+        "down": "#all",
+        "up": "#all",
+        "north": "#all",
+        "east": "#all",
+        "south": "#all",
+        "west": "#all"
+    }
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/cube_emissive.json b/game/client/src/main/resources/assets/minecraft/models/block/cube_emissive.json
new file mode 100644
index 000000000..434e02d87
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/cube_emissive.json
@@ -0,0 +1,39 @@
+{
+    "parent": "block/block",
+    "textures": {
+        "overlay": "#north",
+        "particle_up": "#up",
+        "particle_down": "#down",
+        "particle_north": "#north",
+        "particle_south": "#south",
+        "particle_west": "#west",
+        "particle_east": "#east"
+    },
+    "elements": [
+        {   "from": [ 0, 0, 0 ],
+            "to": [ 16, 16, 16 ],
+            "faces": {
+                "down":  { "texture": "#down", "cullface": "down" },
+                "up":    { "texture": "#up", "cullface": "up" },
+                "north": { "texture": "#north", "cullface": "north" },
+                "south": { "texture": "#south", "cullface": "south" },
+                "west":  { "texture": "#west", "cullface": "west" },
+                "east":  { "texture": "#east", "cullface": "east" }
+            }
+        },
+        {   
+            "from": [ 0, 0, 0 ],
+            "to": [ 16, 16, 16 ],
+            "light_emission": 15,
+            "shade": false,
+            "faces": {
+                "down":  { "texture": "#down_emissive", "cullface": "down" },
+                "up":    { "texture": "#up_emissive", "cullface": "up" },
+                "north": { "texture": "#north_emissive", "cullface": "north" },
+                "south": { "texture": "#south_emissive", "cullface": "south" },
+                "west":  { "texture": "#west_emissive", "cullface": "west" },
+                "east":  { "texture": "#east_emissive", "cullface": "east" }
+            }
+    }
+    ]
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/cube_emissive_all.json b/game/client/src/main/resources/assets/minecraft/models/block/cube_emissive_all.json
new file mode 100644
index 000000000..bcd6347a8
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/cube_emissive_all.json
@@ -0,0 +1,17 @@
+{
+    "parent": "block/cube_emissive",
+    "textures": {
+        "down": "#all",
+        "up": "#all",
+        "north": "#all",
+        "east": "#all",
+        "south": "#all",
+        "west": "#all",
+        "down_emissive": "#all_emissive",
+        "up_emissive": "#all_emissive",
+        "north_emissive": "#all_emissive",
+        "east_emissive": "#all_emissive",
+        "south_emissive": "#all_emissive",
+        "west_emissive": "#all_emissive"
+    }
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/furnace_stone_idle.json b/game/client/src/main/resources/assets/minecraft/models/block/furnace_stone_idle.json
new file mode 100644
index 000000000..6ac0b1d4e
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/furnace_stone_idle.json
@@ -0,0 +1,8 @@
+{
+  "parent": "minecraft:block/orientable",
+  "textures": {
+    "front": "minecraft:block/furnace_stone/idle_front",
+    "side": "minecraft:block/furnace_stone/side",
+    "top": "minecraft:block/furnace_stone/top"
+  }
+}
\ 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
new file mode 100644
index 000000000..ba0297669
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/grass.json
@@ -0,0 +1,44 @@
+{   "parent": "block/block",
+    "textures": {
+        "overlay": "#side",
+        "particle_up": "#top",
+        "particle_down": "#bottom",
+        "particle_north": "#side",
+        "particle_south": "#side",
+        "particle_west": "#side",
+        "particle_east": "#side",
+        "bottom": "block/dirt",
+        "top": "block/grass/top",
+        "side": "block/grass/side",
+        "render_overlay": "block/grass/side_overlay"
+    },
+    "particles": {
+        "down": -1,
+        "north": -1,
+        "south": -1,
+        "west": -1,
+        "east": -1
+    },
+    "elements": [
+        {   "from": [ 0, 0, 0 ],
+            "to": [ 16, 16, 16 ],
+            "faces": {
+                "down":  { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" },
+                "up":    { "uv": [ 0, 0, 16, 16 ], "texture": "#top",    "cullface": "up", "tintindex": 0 },
+                "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#side",   "cullface": "north" },
+                "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#side",   "cullface": "south" },
+                "west":  { "uv": [ 0, 0, 16, 16 ], "texture": "#side",   "cullface": "west" },
+                "east":  { "uv": [ 0, 0, 16, 16 ], "texture": "#side",   "cullface": "east" }
+            }
+        },
+        {   "from": [ 0, 0, 0 ],
+            "to": [ 16, 16, 16 ],
+            "faces": {
+                "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#render_overlay", "tintindex": 0, "cullface": "north" },
+                "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#render_overlay", "tintindex": 0, "cullface": "south" },
+                "west":  { "uv": [ 0, 0, 16, 16 ], "texture": "#render_overlay", "tintindex": 0, "cullface": "west" },
+                "east":  { "uv": [ 0, 0, 16, 16 ], "texture": "#render_overlay", "tintindex": 0, "cullface": "east" }
+            }
+        }
+    ]
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/ore_nethercoal_netherrack.json b/game/client/src/main/resources/assets/minecraft/models/block/ore_nethercoal_netherrack.json
new file mode 100644
index 000000000..2ac6d7672
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/ore_nethercoal_netherrack.json
@@ -0,0 +1,7 @@
+{
+  "parent": "minecraft:block/cube_emissive_all",
+  "textures": {
+    "all": "minecraft:block/ore/nethercoal/netherrack",
+    "all_emissive": "minecraft:block/ore/nethercoal/netherrack_overlay"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/orientable.json b/game/client/src/main/resources/assets/minecraft/models/block/orientable.json
new file mode 100644
index 000000000..ad7bf9a73
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/orientable.json
@@ -0,0 +1,6 @@
+{
+    "parent": "block/orientable_with_bottom",
+    "textures": {
+        "bottom": "#top"
+    }
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/orientable_with_bottom.json b/game/client/src/main/resources/assets/minecraft/models/block/orientable_with_bottom.json
new file mode 100644
index 000000000..d03a89bdb
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/orientable_with_bottom.json
@@ -0,0 +1,19 @@
+{
+    "parent": "block/cube",
+    "display": {
+        "firstperson_righthand": {
+            "rotation": [ 0, 135, 0 ],
+            "translation": [ 0, 0, 0 ],
+            "scale": [ 0.40, 0.40, 0.40 ]
+        }
+    },
+    "textures": {
+        "particle": "#front",
+        "down": "#bottom",
+        "up": "#top",
+        "north": "#front",
+        "east": "#side",
+        "south": "#side",
+        "west": "#side"
+    }
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/sapling_oak.json b/game/client/src/main/resources/assets/minecraft/models/block/sapling_oak.json
new file mode 100644
index 000000000..5919f4fa8
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/sapling_oak.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:block/cross",
+  "textures": {
+    "cross": "minecraft:block/sapling/oak"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/stairs.json b/game/client/src/main/resources/assets/minecraft/models/block/stairs.json
new file mode 100644
index 000000000..986ce9c6e
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/stairs.json
@@ -0,0 +1,45 @@
+{   "parent": "block/block",
+    "display": {
+        "gui": {
+            "rotation": [ 30, 135, 0 ],
+            "translation": [ 0, 0, 0],
+            "scale":[ 0.625, 0.625, 0.625 ]
+        },
+        "head": {
+            "rotation": [ 0, -90, 0 ],
+            "translation": [ 0, 0, 0 ],
+            "scale": [ 1, 1, 1 ]
+        },
+        "thirdperson_lefthand": {
+            "rotation": [ 75, -135, 0 ],
+            "translation": [ 0, 2.5, 0],
+            "scale": [ 0.375, 0.375, 0.375 ]
+        }
+    },
+    "textures": {
+        "particle": "#side"
+    },
+    "elements": [
+        {   "from": [ 0, 0, 0 ],
+            "to": [ 16, 8, 16 ],
+            "faces": {
+                "down":  { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" },
+                "up":    { "uv": [ 0, 0, 16, 16 ], "texture": "#top" },
+                "north": { "uv": [ 0, 8, 16, 16 ], "texture": "#side", "cullface": "north" },
+                "south": { "uv": [ 0, 8, 16, 16 ], "texture": "#side", "cullface": "south" },
+                "west":  { "uv": [ 0, 8, 16, 16 ], "texture": "#side", "cullface": "west" },
+                "east":  { "uv": [ 0, 8, 16, 16 ], "texture": "#side", "cullface": "east" }
+            }
+        },
+        {   "from": [ 8, 8, 0 ],
+            "to": [ 16, 16, 16 ],
+            "faces": {
+                "up":    { "uv": [ 8, 0, 16, 16 ], "texture": "#top", "cullface": "up" },
+                "north": { "uv": [ 0, 0,  8,  8 ], "texture": "#side", "cullface": "north" },
+                "south": { "uv": [ 8, 0, 16,  8 ], "texture": "#side", "cullface": "south" },
+                "west":  { "uv": [ 0, 0, 16,  8 ], "texture": "#side" },
+                "east":  { "uv": [ 0, 0, 16,  8 ], "texture": "#side", "cullface": "east" }
+            }
+        }
+    ]
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/stairs_oak.json b/game/client/src/main/resources/assets/minecraft/models/block/stairs_oak.json
new file mode 100644
index 000000000..27542819e
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/stairs_oak.json
@@ -0,0 +1,8 @@
+{
+  "parent": "minecraft:block/stairs",
+  "textures": {
+    "bottom": "minecraft:block/planks/oak",
+    "side": "minecraft:block/planks/oak",
+    "top": "minecraft:block/planks/oak"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/stone.json b/game/client/src/main/resources/assets/minecraft/models/block/stone.json
new file mode 100644
index 000000000..1a2f6a79a
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/stone.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:block/cube_all",
+  "textures": {
+    "all": "minecraft:block/stone"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/tall_grass.json b/game/client/src/main/resources/assets/minecraft/models/block/tall_grass.json
new file mode 100644
index 000000000..533f92bc8
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/tall_grass.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:block/tinted_cross",
+  "textures": {
+    "cross": "minecraft:block/tallgrass"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/template_torch_wall.json b/game/client/src/main/resources/assets/minecraft/models/block/template_torch_wall.json
new file mode 100644
index 000000000..a7083f018
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/template_torch_wall.json
@@ -0,0 +1,21 @@
+{
+    "ambientocclusion": false,
+    "textures": {
+        "particle": "#torch"
+    },
+    "elements": [
+        {   "from": [ -1, 3.5, 7 ],
+            "to": [ 1, 13.5, 9 ],
+            "rotation": { "origin": [ 0, 3.5, 8 ], "axis": "z", "angle": -22.5 },
+            "shade": false,
+            "faces": {
+                "down":  { "uv": [ 7, 13, 9, 15 ], "texture": "#torch" },
+                "up":    { "uv": [ 7,  6, 9,  8 ], "texture": "#torch" },
+                "north": { "uv": [ 7,  6, 9, 16 ], "texture": "#torch" },
+                "east":  { "uv": [ 7,  6, 9, 16 ], "texture": "#torch" },
+                "south": { "uv": [ 7,  6, 9, 16 ], "texture": "#torch" },
+                "west":  { "uv": [ 7,  6, 9, 16 ], "texture": "#torch" }
+            }
+        }
+    ]
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/tinted_cross.json b/game/client/src/main/resources/assets/minecraft/models/block/tinted_cross.json
new file mode 100644
index 000000000..d3b5474e8
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/tinted_cross.json
@@ -0,0 +1,26 @@
+{
+    "ambientocclusion": false,
+    "textures": {
+        "particle": "#cross"
+    },
+    "elements": [
+        {   "from": [ 0.8, 0, 8 ],
+            "to": [ 15.2, 16, 8 ],
+            "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true },
+            "shade": false,
+            "faces": {
+                "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross", "tintindex": 0 },
+                "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross", "tintindex": 0 }
+            }
+        },
+        {   "from": [ 8, 0, 0.8 ],
+            "to": [ 8, 16, 15.2 ],
+            "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true },
+            "shade": false,
+            "faces": {
+                "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross", "tintindex": 0 },
+                "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross", "tintindex": 0 }
+            }
+        }
+    ]
+}
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/torch_wall.json b/game/client/src/main/resources/assets/minecraft/models/block/torch_wall.json
new file mode 100644
index 000000000..b891f712a
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/models/block/torch_wall.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:block/template_torch_wall",
+  "textures": {
+    "torch": "minecraft:block/torch_coal"
+  }
+}
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/trommel/bottom.png b/game/client/src/main/resources/assets/minecraft/textures/block/trommel/bottom.png
index be7cead3e..d19a2ea14 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/trommel/bottom.png and b/game/client/src/main/resources/assets/minecraft/textures/block/trommel/bottom.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/anactualsign.png b/game/client/src/main/resources/assets/minecraft/textures/entity/anactualsign.png
deleted file mode 100644
index 373d18525..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/entity/anactualsign.png and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/ghast_vehicle/0.png b/game/client/src/main/resources/assets/minecraft/textures/entity/ghast_vehicle/0.png
deleted file mode 100644
index 9ed4fbf0d..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/entity/ghast_vehicle/0.png and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/pigman/0.png b/game/client/src/main/resources/assets/minecraft/textures/entity/pigman/0.png
index c900b3624..61194519c 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/entity/pigman/0.png and b/game/client/src/main/resources/assets/minecraft/textures/entity/pigman/0.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/pigzombie/0.png b/game/client/src/main/resources/assets/minecraft/textures/entity/pigzombie/0.png
index 0a0a25a45..9bd883118 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/entity/pigzombie/0.png and b/game/client/src/main/resources/assets/minecraft/textures/entity/pigzombie/0.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue/basalt.png b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/basalt.png
new file mode 100644
index 000000000..179e46cc5
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/basalt.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue/granite.png b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/granite.png
new file mode 100644
index 000000000..ab903daad
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/granite.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue/limestone.png b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/limestone.png
new file mode 100644
index 000000000..8cc43c97a
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/limestone.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue/marble.png b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/marble.png
new file mode 100644
index 000000000..34d46e4b3
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/marble.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue/pigman.png b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/pigman.png
new file mode 100644
index 000000000..d41f8d4fb
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/pigman.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue/stone.png b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/stone.png
new file mode 100644
index 000000000..d6e78569f
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/stone.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue/template.pdn b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/template.pdn
new file mode 100644
index 000000000..6a9f79e04
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/entity/statue/template.pdn differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue_stone.pdn b/game/client/src/main/resources/assets/minecraft/textures/entity/statue_stone.pdn
deleted file mode 100644
index 55a93528c..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/entity/statue_stone.pdn and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/entity/statue_stone.png b/game/client/src/main/resources/assets/minecraft/textures/entity/statue_stone.png
deleted file mode 100644
index d71316769..000000000
Binary files a/game/client/src/main/resources/assets/minecraft/textures/entity/statue_stone.png and /dev/null differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/statue_basalt.png b/game/client/src/main/resources/assets/minecraft/textures/item/statue_basalt.png
new file mode 100644
index 000000000..202f121e6
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/statue_basalt.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/statue_granite.png b/game/client/src/main/resources/assets/minecraft/textures/item/statue_granite.png
new file mode 100644
index 000000000..ff08200ca
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/statue_granite.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/statue_limestone.png b/game/client/src/main/resources/assets/minecraft/textures/item/statue_limestone.png
new file mode 100644
index 000000000..725ffa1ed
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/statue_limestone.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/statue_marble.png b/game/client/src/main/resources/assets/minecraft/textures/item/statue_marble.png
new file mode 100644
index 000000000..69158337a
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/statue_marble.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/statue_pigman.png b/game/client/src/main/resources/assets/minecraft/textures/item/statue_pigman.png
new file mode 100644
index 000000000..2acbb92b5
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/statue_pigman.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/statue_stone.png b/game/client/src/main/resources/assets/minecraft/textures/item/statue_stone.png
index f59edb0fc..1e46d5991 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/item/statue_stone.png and b/game/client/src/main/resources/assets/minecraft/textures/item/statue_stone.png differ
diff --git a/game/client/src/test/java/TestItemModelDispatcher.java b/game/client/src/test/java/TestItemModelDispatcher.java
index c437ee87e..d976a6a88 100644
--- a/game/client/src/test/java/TestItemModelDispatcher.java
+++ b/game/client/src/test/java/TestItemModelDispatcher.java
@@ -25,7 +25,7 @@ public class TestItemModelDispatcher {
         Colors.loadDummyColors();
 
         // Map model requires mc font reference
-        Minecraft mc = new Minecraft();
+        Minecraft mc = new Minecraft(null,true);
         mc.gameSettings = new GameSettings(mc, mc.getMinecraftDir());
         mc.texturePackList = new TexturePackList(mc, mc.getMinecraftDir());
         mc.textureManager = new TextureManager(mc, mc.texturePackList, mc.gameSettings);
diff --git a/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java b/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java
index 6c6afcc1f..c8246ab29 100644
--- a/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java
+++ b/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java
@@ -58,10 +58,10 @@ public class Achievement extends Stat
     {
         if(statStringFormatter != null)
         {
-            return statStringFormatter.formatString(I18n.getInstance().translateDescKey(description));
+            return statStringFormatter.formatString(I18n.getInstance().translateKey(description + ".desc"));
         } else
         {
-            return I18n.getInstance().translateDescKey(description);
+            return I18n.getInstance().translateKey(description + ".desc");
         }
     }
 
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 c39207287..5a6044ada 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
@@ -455,7 +455,7 @@ public final class Block<T extends BlockLogic>
     @Override
     public void onBlockPlacedByWorld(World world, int x, int y, int z) {
         if (isEntityTile && !disableNormalEntityLogic && entitySupplier != null) {
-            world.setBlockTileEntity(x, y, z, entitySupplier.get());
+            world.setTileEntity(x, y, z, entitySupplier.get());
         }
         logic.onBlockPlacedByWorld(world, x, y, z);
     }
@@ -465,7 +465,7 @@ public final class Block<T extends BlockLogic>
         logic.onBlockRemoved(world, x, y, z, data);
         if (isEntityTile && !disableNormalEntityLogic) {
             if (!world.isClientSide) {
-                TileEntity tileEntity = world.getBlockEntity(x, y, z);
+                TileEntity tileEntity = world.getTileEntity(x, y, z);
                 if(tileEntity != null) {
                     tileEntity.dropContents(world, x, y, z);
                 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
index 1a7108d55..cfa71e5c2 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
@@ -31,8 +31,8 @@ public class BlockLogicActivator extends BlockLogicVeryRotatable
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
     {
         if (!world.isClientSide) {
-            TileEntityActivator dispenserBlockEntity = (TileEntityActivator) world.getBlockEntity(x, y, z);
-            player.displayActivatorScreen(dispenserBlockEntity);
+            TileEntityActivator tileEntityActivator = (TileEntityActivator) world.getTileEntity(x, y, z);
+            player.displayActivatorScreen(tileEntityActivator);
         }
         return true;
     }
@@ -44,7 +44,7 @@ public class BlockLogicActivator extends BlockLogicVeryRotatable
         int yOffset = direction.getOffsetY();
         int zOffset = direction.getOffsetZ();
 
-        TileEntityActivator activator = (TileEntityActivator)world.getBlockEntity(x, y, z);
+        TileEntityActivator activator = (TileEntityActivator)world.getTileEntity(x, y, z);
         if (!activator.locked(activator.stackSelector)) {
             ItemStack itemStack = activator.getNextStack();
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java
index 5fe216bcb..1b8ffb04e 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java
@@ -23,7 +23,7 @@ public class BlockLogicBasket extends BlockLogic
     @Override
     public boolean onBlockRightClicked(final World world, final int x, final int y, final int z, final Player entityplayer, Side side, double xPlaced, double yPlaced)
     {
-        final TileEntityBasket te = (TileEntityBasket) world.getBlockEntity(x, y, z);
+        final TileEntityBasket te = (TileEntityBasket) world.getTileEntity(x, y, z);
 
         if (te.getNumUnitsInside() > 0)
         {
@@ -37,7 +37,7 @@ public class BlockLogicBasket extends BlockLogic
 
     @Override
     public void onActivatorInteract(World world, int x, int y, int z, TileEntityActivator activator, Direction direction) {
-        final TileEntityBasket te = (TileEntityBasket) world.getBlockEntity(x, y, z);
+        final TileEntityBasket te = (TileEntityBasket) world.getTileEntity(x, y, z);
 
         if (te.getNumUnitsInside() > 0)
         {
@@ -52,7 +52,7 @@ public class BlockLogicBasket extends BlockLogic
 
     public int getFillLevel(final WorldSource world, final int x, final int y, final int z)
     {
-        final TileEntityBasket te = (TileEntityBasket) world.getBlockEntity(x, y, z);
+        final TileEntityBasket te = (TileEntityBasket) world.getTileEntity(x, y, z);
 
         final float fill = te.getNumUnitsInside() / (float)te.getMaxUnits();
 
@@ -80,7 +80,7 @@ public class BlockLogicBasket extends BlockLogic
     @Override
     public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side)
     {
-        TileEntityBasket basketTileEntity = (TileEntityBasket) worldSource.getBlockEntity(x, y, z);
+        TileEntityBasket basketTileEntity = (TileEntityBasket) worldSource.getTileEntity(x, y, z);
         if(basketTileEntity != null){
             return basketTileEntity.getNumUnitsInside() == basketTileEntity.getMaxUnits();
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java
index c62c3d4c6..0a43f9201 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java
@@ -5,7 +5,7 @@ import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.vehicle.EntityBoat;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.IBonemealable;
 import net.minecraft.core.item.ItemStack;
@@ -126,7 +126,7 @@ public class BlockLogicCactus extends BlockLogic implements IBonemealable
     @Override
     public void onEntityCollidedWithBlock(World world, int x, int y, int z, Entity entity)
     {
-        if(entity instanceof Mob || entity instanceof MinecartEntity || entity instanceof EntityBoat) {
+        if(entity instanceof Mob || entity instanceof EntityMinecart || entity instanceof EntityBoat) {
         	entity.hurt(null, 1, DamageType.COMBAT);
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java
index c5ce4404e..9c081b1cf 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java
@@ -313,7 +313,7 @@ public class BlockLogicChest extends BlockLogic implements IPaintable {
 	}
 	
 	public static Container getInventory(World world, int x, int y, int z) {
-		Container inventory = (Container) world.getBlockEntity(x, y, z);
+		Container inventory = (Container) world.getTileEntity(x, y, z);
 
         int meta = world.getBlockMetadata(x, y, z);
 		Type type = getTypeFromMeta(meta);
@@ -348,11 +348,11 @@ public class BlockLogicChest extends BlockLogic implements IPaintable {
 				if(getDirectionFromMeta(otherMeta) == direction) {
 					Type otherType = getTypeFromMeta(otherMeta);
 					if(type == Type.LEFT && otherType == Type.RIGHT) {
-						inv2 = (Container) world.getBlockEntity(otherChestX, y, otherChestZ);
+						inv2 = (Container) world.getTileEntity(otherChestX, y, otherChestZ);
 					}
 					if(type == Type.RIGHT && otherType == Type.LEFT) {
 						inv2 = inventory;
-						inventory = (Container) world.getBlockEntity(otherChestX, y, otherChestZ);
+						inventory = (Container) world.getTileEntity(otherChestX, y, otherChestZ);
 					}
 				}
 			}
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChestLegacy.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChestLegacy.java
index 6824d42a4..4161e5036 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChestLegacy.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChestLegacy.java
@@ -36,7 +36,7 @@ public class BlockLogicChestLegacy extends BlockLogic {
 	
 	@Override
 	public void onBlockRemoved(World world, int x, int y, int z, int data) {
-		TileEntity entity = world.getBlockEntity(x, y, z);
+		TileEntity entity = world.getTileEntity(x, y, z);
 		if (entity != null) {
 			entity.dropContents(world, x, y, z);
 		}
@@ -174,7 +174,7 @@ public class BlockLogicChestLegacy extends BlockLogic {
 	}
 	
 	private ItemStack[] getAndClearChestInventory(World world, int x, int y, int z) {
-		TileEntityChest tileEntityChest = (TileEntityChest) world.getBlockEntity(x, y, z);
+		TileEntityChest tileEntityChest = (TileEntityChest) world.getTileEntity(x, y, z);
 		
 		ItemStack[] items = new ItemStack[tileEntityChest.getContainerSize()];
 		
@@ -187,7 +187,7 @@ public class BlockLogicChestLegacy extends BlockLogic {
 	}
 	
 	private void setChestInventory(World world, int x, int y, int z, ItemStack[] items) {
-		TileEntityChest tileEntityChest = (TileEntityChest) world.getBlockEntity(x, y, z);
+		TileEntityChest tileEntityChest = (TileEntityChest) world.getTileEntity(x, y, z);
 		
 		for(int i=0; i < items.length; i++) {
 			tileEntityChest.setItem(i, items[i]);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
index da7d5665b..42e6dab32 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
@@ -38,7 +38,7 @@ public class BlockLogicDispenser extends BlockLogicVeryRotatable
             return true;
         } else
         {
-            TileEntityDispenser tileEntityDispenser = (TileEntityDispenser)world.getBlockEntity(x, y, z);
+            TileEntityDispenser tileEntityDispenser = (TileEntityDispenser)world.getTileEntity(x, y, z);
             player.displayDispenserScreen(tileEntityDispenser);
             return true;
         }
@@ -51,7 +51,7 @@ public class BlockLogicDispenser extends BlockLogicVeryRotatable
         int yOffset = direction.getOffsetY();
         int zOffset = direction.getOffsetZ();
 
-        TileEntityDispenser tileEntity = (TileEntityDispenser)world.getBlockEntity(x, y, z);
+        TileEntityDispenser tileEntity = (TileEntityDispenser)world.getTileEntity(x, y, z);
         ItemStack itemStack = tileEntity.getRandomStackFromInventory();
         double px = (double)x + (double)xOffset * 0.6D + 0.5D;
         double py = (double)y + (double)yOffset * 0.6D + 0.5D;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java
index 87de3a52e..cd6f60d66 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java
@@ -10,6 +10,7 @@ import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.weather.IPrecipitation;
 
 import java.util.Random;
 
@@ -124,7 +125,7 @@ public class BlockLogicFire extends BlockLogic {
 		}
 		
 		//Extinguish fire (Rain / Snow)
-		if (!infiniBurn && world.getCurrentWeather() != null && world.getCurrentWeather().isPrecipitation && (
+		if (!infiniBurn && world.getCurrentWeather() != null && world.getCurrentWeather() instanceof IPrecipitation && (
 				   world.canBlockBeRainedOn(x, y, z)
 				|| world.canBlockBeRainedOn(x - 1, y, z)
 				|| world.canBlockBeRainedOn(x + 1, y, z)
@@ -177,7 +178,7 @@ public class BlockLogicFire extends BlockLogic {
 					}
 					
 					int c = (b + 40) / (meta + 30);
-					if (c <= 0 || rand.nextInt(a) > c || (world.getCurrentWeather() != null && world.getCurrentWeather().isPrecipitation) &&
+					if (c <= 0 || rand.nextInt(a) > c || (world.getCurrentWeather() != null && world.getCurrentWeather() instanceof IPrecipitation) &&
 							   world.canBlockBeRainedOn(x1, y1, z1)
 							|| world.canBlockBeRainedOn(x1 - 1, y1, z)
 							|| world.canBlockBeRainedOn(x1 + 1, y1, z1)
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java
index 1f3bdb28e..acd8067e1 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java
@@ -3,6 +3,7 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.weather.IPrecipitation;
 
 import java.util.Random;
 
@@ -22,7 +23,7 @@ public class BlockLogicFireCold extends BlockLogicFire {
         }
 
         //Extinguish fire (Rain / Snow)
-        if (!infiniBurn && world.getCurrentWeather() != null && world.getCurrentWeather().isPrecipitation && (
+        if (!infiniBurn && world.getCurrentWeather() != null && world.getCurrentWeather() instanceof IPrecipitation && (
             world.canBlockBeRainedOn(x, y, z)
                 || world.canBlockBeRainedOn(x - 1, y, z)
                 || world.canBlockBeRainedOn(x + 1, y, z)
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java
index 5bcae9e0e..22d4b469a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java
@@ -57,7 +57,7 @@ public class BlockLogicFlag extends BlockLogic {
 	@Override
 	public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced) {
 		if (!world.isClientSide) {
-			TileEntityFlag flag = (TileEntityFlag) world.getBlockEntity(x, y, z);
+			TileEntityFlag flag = (TileEntityFlag) world.getTileEntity(x, y, z);
 			if (flag.owner != null && !player.uuid.equals(flag.owner)) {
 				return false;
 			}
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnace.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnace.java
index bd351d32a..f28006039 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnace.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnace.java
@@ -80,7 +80,7 @@ public class BlockLogicFurnace extends BlockLogicRotatable
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
     {
         if (!world.isClientSide) {
-            TileEntityFurnace tileentityfurnace = (TileEntityFurnace) world.getBlockEntity(x, y, z);
+            TileEntityFurnace tileentityfurnace = (TileEntityFurnace) world.getTileEntity(x, y, z);
             player.displayFurnaceScreen(tileentityfurnace);
         }
         return true;
@@ -88,7 +88,7 @@ public class BlockLogicFurnace extends BlockLogicRotatable
 
 	public static void updateFurnaceBlockState(boolean lit, @NotNull World world, int x, int y, int z) {
 		int meta = world.getBlockMetadata(x, y, z);
-		TileEntity tileEntity = world.getBlockEntity(x, y, z);
+		TileEntity tileEntity = world.getTileEntity(x, y, z);
 		if(tileEntity == null) {
 			String msg = "Furnace is missing Tile Entity at x: "+x+" y: "+y+" z: "+z+", block will be removed!";
 			if(Global.BUILD_CHANNEL.isUnstableBuild()) {
@@ -107,7 +107,7 @@ public class BlockLogicFurnace extends BlockLogicRotatable
 		keepFurnaceInventory = false;
 		world.setBlockMetadataWithNotify(x, y, z, meta);
 		tileEntity.validate();
-		world.setBlockTileEntity(x, y, z, tileEntity);
+		world.setTileEntity(x, y, z, tileEntity);
 	}
 
     protected Random furnaceRand;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java
index 643132270..85a8210c5 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java
@@ -42,7 +42,7 @@ public class BlockLogicFurnaceBlast extends BlockLogicFurnace
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
     {
         if (!world.isClientSide) {
-            TileEntityFurnaceBlast furnaceBlast = (TileEntityFurnaceBlast) world.getBlockEntity(x, y, z);
+            TileEntityFurnaceBlast furnaceBlast = (TileEntityFurnaceBlast) world.getTileEntity(x, y, z);
             player.displayFurnaceScreen(furnaceBlast);
         }
         return true;
@@ -85,7 +85,7 @@ public class BlockLogicFurnaceBlast extends BlockLogicFurnace
 
 	public static void updateFurnaceBlockState(boolean lit, World world, int x, int y, int z) {
 		int meta = world.getBlockMetadata(x, y, z);
-		TileEntity tileEntity = world.getBlockEntity(x, y, z);
+		TileEntity tileEntity = world.getTileEntity(x, y, z);
 		if(tileEntity == null) {
 			String msg = "Blast Furnace is missing Tile Entity at x: "+x+" y: "+y+" z: "+z+", block will be removed!";
 			if(Global.BUILD_CHANNEL.isUnstableBuild()) {
@@ -104,7 +104,7 @@ public class BlockLogicFurnaceBlast extends BlockLogicFurnace
 		keepFurnaceInventory = false;
 		world.setBlockMetadataWithNotify(x, y, z, meta);
 		tileEntity.validate();
-		world.setBlockTileEntity(x, y, z, tileEntity);
+		world.setTileEntity(x, y, z, tileEntity);
 	}
 
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
index 1efef53b4..18e93dacf 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
@@ -62,7 +62,7 @@ public class BlockLogicJar extends BlockLogic {
                     world.dropItem(x, y, z, new ItemStack(itemSupplier.get(), 1, 0));
                 }
             } else {
-                TileEntityFlowerJar tileEntity = (TileEntityFlowerJar) world.getBlockEntity(x, y, z);
+                TileEntityFlowerJar tileEntity = (TileEntityFlowerJar) world.getTileEntity(x, y, z);
                 int flowerInPot = tileEntity.flowerInPot;
                 int flowerData = tileEntity.flowerData;
                 if (flowerInPot > 0 && Blocks.hasTag(flowerInPot, BlockTags.PLANTABLE_IN_JAR)) {
@@ -77,7 +77,7 @@ public class BlockLogicJar extends BlockLogic {
         } else if (player.getHeldItem().getItem() instanceof ItemBlock) {
             Block<?> blockInHand = ((ItemBlock<?>) player.getHeldItem().getItem()).getBlock();
             if (Blocks.hasTag(blockInHand.id(), BlockTags.PLANTABLE_IN_JAR)) {
-                TileEntityFlowerJar tileEntity = (TileEntityFlowerJar) world.getBlockEntity(x, y, z);
+                TileEntityFlowerJar tileEntity = (TileEntityFlowerJar) world.getTileEntity(x, y, z);
                 if(world.getBlockMetadata(x, y, z) == 0) {
                     player.getHeldItem().consumeItem(player);
                     world.setBlockMetadataWithNotify(x, y, z, 1);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJukebox.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJukebox.java
index 9b1844041..622fd8959 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJukebox.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJukebox.java
@@ -41,7 +41,7 @@ public class BlockLogicJukebox extends BlockLogic
     public void playRecord(World world, int x, int y, int z, int recordId)
     {
         if (!world.isClientSide) {
-            TileEntityJukebox jukebox = (TileEntityJukebox) world.getBlockEntity(x, y, z);
+            TileEntityJukebox jukebox = (TileEntityJukebox) world.getTileEntity(x, y, z);
             jukebox.record = recordId;
             jukebox.setChanged();
             world.setBlockMetadataWithNotify(x, y, z, 1);
@@ -54,7 +54,7 @@ public class BlockLogicJukebox extends BlockLogic
         {
             return;
         }
-        TileEntity tileEntity = world.getBlockEntity(x, y, z);
+        TileEntity tileEntity = world.getTileEntity(x, y, z);
         tileEntity.dropContents(world, x, y, z);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMeshGold.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMeshGold.java
index d8468e00d..6dbe4c92a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMeshGold.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMeshGold.java
@@ -17,7 +17,7 @@ public class BlockLogicMeshGold extends BlockLogicMesh {
     @Override
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
     {
-        TileEntityMeshGold meshGold = (TileEntityMeshGold) world.getBlockEntity(x, y, z);
+        TileEntityMeshGold meshGold = (TileEntityMeshGold) world.getTileEntity(x, y, z);
         ItemStack heldItem = player.getHeldItem();
         boolean flag = meshGold.setFilterItem(player, heldItem);
         if(heldItem != null && heldItem.stackSize <= 0)
@@ -30,7 +30,7 @@ public class BlockLogicMeshGold extends BlockLogicMesh {
     @Override
     public boolean collidesWithEntity(Entity entity, World world, int x, int y, int z) {
         if (entity instanceof EntityItem){
-            TileEntityMeshGold mesh = (TileEntityMeshGold) world.getBlockEntity(x, y, z);
+            TileEntityMeshGold mesh = (TileEntityMeshGold) world.getTileEntity(x, y, z);
             if (mesh.filterItem == null) return true;
 
             ItemStack entityStack = ((EntityItem) entity).item;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMobSpawner.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMobSpawner.java
index b586c93e1..105332d41 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMobSpawner.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMobSpawner.java
@@ -33,7 +33,7 @@ public class BlockLogicMobSpawner extends BlockLogicMobSpawnerDeactivated
 
     @Override
 	public void onBlockPlacedOnSide(World world, int x, int y, int z, @NotNull Side side, double xPlaced, double yPlaced) {
-    	TileEntityMobSpawner tileEntity = (TileEntityMobSpawner) world.getBlockEntity(x, y, z);
+    	TileEntityMobSpawner tileEntity = (TileEntityMobSpawner) world.getTileEntity(x, y, z);
     	tileEntity.setMobId("none");
     }
 
@@ -41,7 +41,7 @@ public class BlockLogicMobSpawner extends BlockLogicMobSpawnerDeactivated
     public void onBlockRemoved(World world, int x, int y, int z, int data)
     {
         if (!world.isClientSide) {
-            TileEntityMobSpawner tileEntityMobSpawner = (TileEntityMobSpawner) world.getBlockEntity(x, y, z);
+            TileEntityMobSpawner tileEntityMobSpawner = (TileEntityMobSpawner) world.getTileEntity(x, y, z);
             if (tileEntityMobSpawner == null) return;
             int amountToDrop = world.rand.nextInt(10) + 10;
             label0:
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
index df2c001f8..e912ac8c7 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
@@ -4,7 +4,7 @@ import java.util.List;
 import java.util.Random;
 
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
@@ -67,7 +67,7 @@ public class BlockLogicRailDetector extends BlockLogicRail {
         boolean isPowered = (meta & MASK_POWERED) != 0;
         boolean minecartPresent = false;
         float offset = 0.125f;
-        List<MinecartEntity> list = world.getEntitiesWithinAABB(MinecartEntity.class, AABB.getTemporaryBB(x + offset, y + offset, z + offset, x + 1 - offset, y + 1 - offset, z + 1 - offset));
+        List<EntityMinecart> list = world.getEntitiesWithinAABB(EntityMinecart.class, AABB.getTemporaryBB(x + offset, y + offset, z + offset, x + 1 - offset, y + 1 - offset, z + 1 - offset));
         if(!list.isEmpty()) {
             minecartPresent = true;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
index 7a46e4ab6..b971b8d49 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
@@ -24,7 +24,7 @@ public class BlockLogicSeat extends BlockLogic
             return false;
         }
         if (!world.isClientSide) {
-            TileEntitySeat tileEntity = (TileEntitySeat) world.getBlockEntity(x, y, z);
+            TileEntitySeat tileEntity = (TileEntitySeat) world.getTileEntity(x, y, z);
             if (tileEntity.getPassenger() == null) {
                 player.startRiding(tileEntity);
             }
@@ -36,7 +36,7 @@ public class BlockLogicSeat extends BlockLogic
     @Override
     public void onBlockRemoved(World world, int x, int y, int z, int data) {
         if (!world.isClientSide) {
-            TileEntitySeat tileEntity = (TileEntitySeat) world.getBlockEntity(x, y, z);
+            TileEntitySeat tileEntity = (TileEntitySeat) world.getTileEntity(x, y, z);
             if (tileEntity != null && tileEntity.getPassenger() != null) {
                 tileEntity.ejectRider();
             }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
index 11124b42c..25b5d10d0 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
@@ -15,7 +15,11 @@ import net.minecraft.core.world.WorldSource;
 
 public class BlockLogicSign extends BlockLogic
 {
-    private final boolean isFreeStanding;
+    public static final int SIDE_NORTH = 2;
+    public static final int SIDE_SOUTH = 3;
+    public static final int SIDE_WEST = 4;
+    public static final int SIDE_EAST = 5;
+    public final boolean isFreeStanding;
 
 	public BlockLogicSign(Block<?> block, boolean isFreeStanding)
     {
@@ -36,48 +40,22 @@ public class BlockLogicSign extends BlockLogic
     @Override
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z)
     {
-        if(isFreeStanding)
-        {
+        if(isFreeStanding) {
             return getBounds();
         }
-        int l = world.getBlockMetadata(x, y, z);
-        float f = 0.28125F;
-        float f1 = 0.78125F;
-        float f2 = 0.0F;
-        float f3 = 1.0F;
-        float f4 = 0.125F;
-                /*int l = world.getBlockMetadata(i, j, k);
-        float f = 0.28125F;
-        float f1 = 0.78125F;
-        float f2 = 0.0F;
-        float f3 = 1.0F;
-        float f4 = -0.275F;
-        setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
-        if(l == 2)
-        {
-            setBlockBounds(f2, f, 1.5F - f4, f3, f1, 1.275F);
-        }
-        if(l == 3)
-        {
-            setBlockBounds(f2, f, -0.375F, f3, f1, f4);
-        }
-        if(l == 4)
-        {
-            setBlockBounds(1.5F - f4, f, f2, 1.275F, f1, f3);
-        }
-        if(l == 5)
-        {
-            setBlockBounds(-0.375F, f, f2, f4, f1, f3);
-        }*/
-        switch (l) {
-            case 2:
-                return AABB.getTemporaryBB(f2, f, 1.0F - f4, f3, f1, 1.0F);
-            case 3:
-                return AABB.getTemporaryBB(f2, f, 0.0F, f3, f1, f4);
-            case 4:
-                return AABB.getTemporaryBB(1.0F - f4, f, f2, 1.0F, f1, f3);
-            case 5:
-                return AABB.getTemporaryBB(0.0F, f, f2, f4, f1, f3);
+        float bottom = 4.5f / 16f;
+        float top = 12.5f / 16f;
+        float width = 16f / 16f;
+        float thickness = 2.0f / 16f;
+        switch (world.getBlockMetadata(x, y, z)) {
+            case SIDE_NORTH:
+                return AABB.getTemporaryBB(0.0F, bottom, 1.0F - thickness, width, top, 1.0F);
+            case SIDE_SOUTH:
+                return AABB.getTemporaryBB(0.0F, bottom, 0.0F, width, top, thickness);
+            case SIDE_WEST:
+                return AABB.getTemporaryBB(1.0F - thickness, bottom, 0.0F, 1.0F, top, width);
+            case SIDE_EAST:
+                return AABB.getTemporaryBB(0.0F, bottom, 0.0F, thickness, top, width);
             default:
                 return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
         }
@@ -98,35 +76,33 @@ public class BlockLogicSign extends BlockLogic
     @Override
 	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId)
     {
-        boolean flag = false;
+        boolean isUnstable = false;
         if(isFreeStanding)
         {
             if(!world.getBlockMaterial(x, y - 1, z).isSolid())
             {
-                flag = true;
+                isUnstable = true;
             }
         } else
         {
-            int i1 = world.getBlockMetadata(x, y, z);
-            flag = true;
-            if(i1 == 2 && world.getBlockMaterial(x, y, z + 1).isSolid())
-            {
-                flag = false;
-            }
-            if(i1 == 3 && world.getBlockMaterial(x, y, z - 1).isSolid())
-            {
-                flag = false;
-            }
-            if(i1 == 4 && world.getBlockMaterial(x + 1, y, z).isSolid())
-            {
-                flag = false;
-            }
-            if(i1 == 5 && world.getBlockMaterial(x - 1, y, z).isSolid())
-            {
-                flag = false;
+            switch (world.getBlockMetadata(x, y, z)) {
+                case SIDE_NORTH:
+                    isUnstable = !world.getBlockMaterial(x, y, z + 1).isSolid();
+                    break;
+                case SIDE_SOUTH:
+                    isUnstable = !world.getBlockMaterial(x, y, z - 1).isSolid();
+                    break;
+                case SIDE_WEST:
+                    isUnstable = !world.getBlockMaterial(x + 1, y, z).isSolid();
+                    break;
+                case SIDE_EAST:
+                    isUnstable = !world.getBlockMaterial(x - 1, y, z).isSolid();
+                    break;
+                default:
+                    isUnstable = true;
             }
         }
-        if(flag)
+        if(isUnstable)
         {
             dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), null, null);
             world.setBlockWithNotify(x, y, z, 0);
@@ -140,7 +116,7 @@ public class BlockLogicSign extends BlockLogic
     }
     @Override
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced) {
-        TileEntitySign signEntity = (TileEntitySign)world.getBlockEntity(x, y, z);
+        TileEntitySign signEntity = (TileEntitySign)world.getTileEntity(x, y, z);
         if (signEntity != null && player != null) {
             if (player.getHeldItem() != null && player.getHeldItem().itemID == Items.DUST_GLOWSTONE.id && !signEntity.isGlowing()) {
                 signEntity.setGlowing(true);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
index 12f9b7a20..871d61085 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
@@ -42,73 +42,101 @@ public class BlockLogicStatue extends BlockLogic {
 
     @Override
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xHit, double yHit) {
-        final @NotNull HumanArmorShape armorShape;
+        final @Nullable TileEntityStatue statueEntity = getTileEntity(world, x, y, z);
+        if (statueEntity == null) {
+            return false;
+        }
+
+        // Sneaking overrides all - next pose
+        if (player.isSneaking()) {
+            statueEntity.nextPose();
+            return true;
+        }
+
+        final @Nullable HumanArmorShape interactSlot;
         if (side == Side.TOP || yHit >= 0.5f) {
             if (this.isBottom) {
-                armorShape = HumanArmorShape.LEGS;
+                interactSlot = HumanArmorShape.LEGS;
             } else {
-                armorShape = HumanArmorShape.HEAD;
+                interactSlot = HumanArmorShape.HEAD;
             }
         } else if (side == Side.BOTTOM || yHit < 0.5f) {
             if (this.isBottom) {
-                armorShape = HumanArmorShape.BOOTS;
+                interactSlot = HumanArmorShape.BOOTS;
             } else {
-                armorShape = HumanArmorShape.CHEST;
+                interactSlot = HumanArmorShape.CHEST;
             }
         } else {
-            return false;
-        }
-
-        final @Nullable TileEntityStatue statueEntity = getTileEntity(world, x, y, z);
-        if (statueEntity == null) {
-            return false;
-        }
-        final @Nullable ItemStack storedItemStack = statueEntity.getItemInArmorSlot(armorShape);
-
-        boolean takeItem = false;
-        if (storedItemStack != null && storedItemStack.getItem() != null) {
-            takeItem = true;
+            interactSlot = null;
         }
 
-        boolean storeItem = false;
-        final @Nullable ItemStack heldItemStack = player.getHeldItem();
-        if (heldItemStack != null) {
-            final @Nullable Item heldItem = heldItemStack.getItem();
-            if (heldItem != null) {
-                if (heldItem instanceof IArmorItem<?> && ((IArmorItem<?>) heldItem).getArmorShape() == armorShape) {
-                    storeItem = true;
-                }
+        final @Nullable ItemStack statueHeldItemStack = statueEntity.getHeldItem();
+        final @Nullable Item statueHeldItem = statueHeldItemStack != null ? statueHeldItemStack.getItem() : null;
+        final @Nullable ItemStack statueArmorItemStack = interactSlot != null ? statueEntity.getItemInArmorSlot(interactSlot) : null;
+        final @Nullable Item statueArmorItem = statueArmorItemStack != null ? statueArmorItemStack.getItem() : null;
+        final @Nullable ItemStack playerHeldItemStack = player.getHeldItem();
+        final @Nullable Item playerHeldItem = playerHeldItemStack != null ? playerHeldItemStack.getItem() : null;
+
+        final boolean isPlayerHoldingArmor = playerHeldItem instanceof IArmorItem && ((IArmorItem<?>) playerHeldItem).getArmorShape() == interactSlot;
+        final boolean isPlayerHandEmpty = playerHeldItem == null;
+        final boolean isStatueHandEmpty = statueHeldItem == null;
+        final boolean isStatueArmorEmpty = statueArmorItem == null;
+
+        final boolean shouldTakeItem = !isStatueHandEmpty && !isPlayerHoldingArmor;
+        final boolean shouldInsertItem = !isPlayerHandEmpty && !isPlayerHoldingArmor;
+        final boolean shouldTakeArmor = interactSlot != null && !isStatueArmorEmpty && isStatueHandEmpty;
+        final boolean shouldInsertArmor = interactSlot != null && isPlayerHoldingArmor;
+
+        // Handle item interaction
+        if (shouldTakeItem && shouldInsertItem) {
+            if (playerHeldItemStack.consumeItem(player)) {
+                final @NotNull ItemStack newStack = playerHeldItemStack.copy();
+                newStack.stackSize = 1;
+                player.inventory.insertItem(statueHeldItemStack, true);
+                statueEntity.setHeldItem(newStack);
+                return true;
+            } else {
+                return false;
+            }
+        } else if (shouldTakeItem) {
+            player.inventory.insertItem(statueHeldItemStack, true);
+            statueEntity.setHeldItem(null);
+            return true;
+        } else if (shouldInsertItem) {
+            if (playerHeldItemStack.consumeItem(player)) {
+                final @NotNull ItemStack newStack = playerHeldItemStack.copy();
+                newStack.stackSize = 1;
+                statueEntity.setHeldItem(newStack);
+                return true;
+            } else {
+                return false;
             }
         }
 
-        if (takeItem && storeItem) {
-            if (heldItemStack.consumeItem(player)) {
-                final @NotNull ItemStack newStack = heldItemStack.copy();
+        // Handle armor interaction
+        if (shouldTakeArmor && shouldInsertArmor) {
+            if (playerHeldItemStack.consumeItem(player)) {
+                final @NotNull ItemStack newStack = playerHeldItemStack.copy();
                 newStack.stackSize = 1;
-                player.inventory.insertItem(storedItemStack, true);
-                statueEntity.setItemInArmorSlot(armorShape, newStack);
+                player.inventory.insertItem(statueArmorItemStack, true);
+                statueEntity.setItemInArmorSlot(interactSlot, newStack);
                 return true;
             } else {
                 return false;
             }
-        } else if (takeItem) {
-            player.inventory.insertItem(storedItemStack, true);
-            statueEntity.setItemInArmorSlot(armorShape, null);
+        } else if (shouldTakeArmor) {
+            player.inventory.insertItem(statueArmorItemStack, true);
+            statueEntity.setItemInArmorSlot(interactSlot, null);
             return true;
-        } else if (storeItem) {
-            if (heldItemStack.consumeItem(player)) {
-                final @NotNull ItemStack newStack = heldItemStack.copy();
+        } else if (shouldInsertArmor) {
+            if (playerHeldItemStack.consumeItem(player)) {
+                final @NotNull ItemStack newStack = playerHeldItemStack.copy();
                 newStack.stackSize = 1;
-                statueEntity.setItemInArmorSlot(armorShape, newStack);
+                statueEntity.setItemInArmorSlot(interactSlot, newStack);
                 return true;
             } else {
                 return false;
             }
-        } else {
-            if (heldItemStack == null || heldItemStack.getItem() == null) {
-                statueEntity.nextPose();
-                return true;
-            }
         }
 
         return false;
@@ -130,7 +158,7 @@ public class BlockLogicStatue extends BlockLogic {
             return null;
         }
 
-        final @Nullable TileEntity tileEntity = world.getBlockEntity(x, this.isBottom ? y : y - 1, z);
+        final @Nullable TileEntity tileEntity = world.getTileEntity(x, this.isBottom ? y : y - 1, z);
         if (!(tileEntity instanceof TileEntityStatue)) {
             return null;
         }
@@ -142,7 +170,7 @@ public class BlockLogicStatue extends BlockLogic {
     public void onBlockRemoved(World world, int x, int y, int z, int data) {
         if (this.isBottom) {
             List<ItemStack> stacks = new ArrayList<>();
-            final @Nullable TileEntity tileEntity = world.getBlockEntity(x, y, z);
+            final @Nullable TileEntity tileEntity = world.getTileEntity(x, y, z);
             if (tileEntity != null) {
                 TileEntityStatue statueEntity = (TileEntityStatue) tileEntity;
                 for (HumanArmorShape armorShape : HumanArmorShape.values()) {
@@ -151,6 +179,10 @@ public class BlockLogicStatue extends BlockLogic {
                         stacks.add(armorStack);
                     }
                 }
+                @Nullable ItemStack heldItemStack = statueEntity.getHeldItem();
+                if (heldItemStack != null) {
+                    stacks.add(heldItemStack);
+                }
             }
 
             for (ItemStack stack : stacks) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
index 58b7e4e4f..f8b623f48 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
@@ -144,7 +144,7 @@ public class BlockLogicTrapDoor extends BlockLogic implements IPaintable {
             BlockLogicLadder ladder = (BlockLogicLadder) block.getLogic();
             Side ladderSide = ladder.getSideFromMeta(world.getBlockMetadata(x, y - 1, z));
             Direction trapdoorDirection = getDirectionForMeta(meta);
-            return ladderSide.getDirection().getOpposite() == trapdoorDirection;
+            return ladderSide.getDirection() == trapdoorDirection.getOpposite();
         }
         return false;
     }
@@ -190,7 +190,17 @@ public class BlockLogicTrapDoor extends BlockLogic implements IPaintable {
     }
 
     public Direction getDirectionForMeta(int meta) {
-        return Direction.getDirectionById(meta & MASK_DIRECTION);
+        switch (meta & MASK_DIRECTION) {
+            case DIRECTION_SOUTH:
+                return Direction.SOUTH;
+            case DIRECTION_NORTH:
+                return Direction.NORTH;
+            case DIRECTION_EAST:
+                return Direction.EAST;
+            case DIRECTION_WEST:
+                return Direction.WEST;
+        }
+        return Direction.NONE;
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrommel.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrommel.java
index facc7586c..bcb02c841 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrommel.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrommel.java
@@ -43,7 +43,7 @@ public class BlockLogicTrommel extends BlockLogicRotatable
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
     {
         if (!world.isClientSide) {
-            TileEntityTrommel tileEntityTrommel = (TileEntityTrommel) world.getBlockEntity(x, y, z);
+            TileEntityTrommel tileEntityTrommel = (TileEntityTrommel) world.getTileEntity(x, y, z);
             player.displayTrommelScreen(tileEntityTrommel);
         }
         return true;
@@ -63,7 +63,7 @@ public class BlockLogicTrommel extends BlockLogicRotatable
     public static void updateTrommelBlockState(boolean lit, World world, int x, int y, int z)
     {
         int l = world.getBlockMetadata(x, y, z);
-        TileEntity tileEntity = world.getBlockEntity(x, y, z);
+        TileEntity tileEntity = world.getTileEntity(x, y, z);
         if(tileEntity == null) {
             String msg = "Trommel is missing Tile Entity at x: " + x + " y: " + y + " z: " + z + ", block will be removed!";
             if(Global.BUILD_CHANNEL.isUnstableBuild()) {
@@ -84,7 +84,7 @@ public class BlockLogicTrommel extends BlockLogicRotatable
         keepTrommelInventory = false;
         world.setBlockMetadataWithNotify(x, y, z, l);
         tileEntity.validate();
-        world.setBlockTileEntity(x, y, z, tileEntity);
+        world.setTileEntity(x, y, z, tileEntity);
     }
 
     private boolean isActive;
diff --git a/game/core/src/main/java/net/minecraft/core/block/Blocks.java b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
index 0e8aedef7..31cb0d1ab 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Blocks.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
@@ -983,10 +983,10 @@ public final class Blocks {
         .withSound(BlockSounds.GRAVEL).withHardness(0.6F).withLitInteriorSurface(true).withDisabledNeighborNotifyOnMetadataChange()
         .withTags(BlockTags.MINEABLE_BY_SHOVEL);
 
-    public static final Block<?> SIGN_POST_PLANKS_OAK = register("sign.post.planks.oak", "minecraft:block/sign_post_planks_oak", 710, (b) -> new BlockLogicSign(b, true))
+    public static final Block<BlockLogicSign> SIGN_POST_PLANKS_OAK = register("sign.post.planks.oak", "minecraft:block/sign_post_planks_oak", 710, (BlockLogicSupplier<BlockLogicSign>)(b) -> new BlockLogicSign(b, true))
         .withSound(BlockSounds.WOOD).withHardness(1.0F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> Items.SIGN)
         .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_AXE);
-    public static final Block<?> SIGN_WALL_PLANKS_OAK = register("sign.wall.planks.oak", "minecraft:block/sign_wall_planks_oak", 711, (b) -> new BlockLogicSign(b, false))
+    public static final Block<BlockLogicSign> SIGN_WALL_PLANKS_OAK = register("sign.wall.planks.oak", "minecraft:block/sign_wall_planks_oak", 711, (BlockLogicSupplier<BlockLogicSign>)(b) -> new BlockLogicSign(b, false))
         .withSound(BlockSounds.WOOD).withHardness(1.0F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> SIGN_POST_PLANKS_OAK)
         .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_AXE);
 
@@ -1205,12 +1205,43 @@ public final class Blocks {
         .withSound(BlockSounds.PERMAFROST).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true)
         .withTags(BlockTags.MINEABLE_BY_PICKAXE);
 
-    public static final Block<BlockLogicStatue> STATUE_STONE_LOWER = register("statue.stone.lower", "minecraft:block/statue_lower", 1010, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, true, () -> Items.STATUE_STONE))
+    public static final Block<BlockLogicStatue> STATUE_STONE_LOWER = register("statue.stone.lower", "minecraft:block/statue_stone_lower", 1010, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, true, () -> Items.STATUE_STONE))
         .withSound(BlockSounds.STONE).withHardness(1.5F)
         .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
-    public static final Block<BlockLogicStatue> STATUE_STONE_UPPER = register("statue.stone.upper", "minecraft:block/statue_upper", 1011, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, false, () -> Items.STATUE_STONE))
+    public static final Block<BlockLogicStatue> STATUE_STONE_UPPER = register("statue.stone.upper", "minecraft:block/statue_stone_upper", 1011, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, false, () -> Items.STATUE_STONE))
         .withSound(BlockSounds.STONE).withHardness(1.5F)
         .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_BASALT_LOWER = register("statue.basalt.lower", "minecraft:block/statue_basalt_lower", 1012, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, true, () -> Items.STATUE_BASALT))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_BASALT_UPPER = register("statue.basalt.upper", "minecraft:block/statue_basalt_upper", 1013, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, false, () -> Items.STATUE_BASALT))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_LIMESTONE_LOWER = register("statue.limestone.lower", "minecraft:block/statue_limestone_lower", 1014, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, true, () -> Items.STATUE_LIMESTONE))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_LIMESTONE_UPPER = register("statue.limestone.upper", "minecraft:block/statue_limestone_upper", 1015, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, false, () -> Items.STATUE_LIMESTONE))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_GRANITE_LOWER = register("statue.granite.lower", "minecraft:block/statue_granite_lower", 1016, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, true, () -> Items.STATUE_GRANITE))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_GRANITE_UPPER = register("statue.granite.upper", "minecraft:block/statue_granite_upper", 1017, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, false, () -> Items.STATUE_GRANITE))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_MARBLE_LOWER = register("statue.marble.lower", "minecraft:block/statue_marble_lower", 1018, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, true, () -> Items.STATUE_MARBLE))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_MARBLE_UPPER = register("statue.marble.upper", "minecraft:block/statue_marble_upper", 1019, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, false, () -> Items.STATUE_MARBLE))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_PIGMAN_LOWER = register("statue.pigman.lower", "minecraft:block/statue_pigman_lower", 1020, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, true, () -> Items.STATUE_PIGMAN))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block<BlockLogicStatue> STATUE_PIGMAN_UPPER = register("statue.pigman.upper", "minecraft:block/statue_pigman_upper", 1021, (BlockLogicSupplier<BlockLogicStatue>) b -> new BlockLogicStatue(b, Material.stone, false, () -> Items.STATUE_PIGMAN))
+        .withSound(BlockSounds.STONE).withHardness(1.5F)
+        .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU);
+
 
     public static <T extends BlockLogic> Block<T> register(String key, String namespaceId, int id, BlockLogicSupplier<T> logicSupplier) {
         Block<T> container = new Block<>(id, key, namespaceId, logicSupplier);
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java
index 39c94be5b..ecbc1c78a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java
@@ -139,7 +139,7 @@ public class TileEntity implements ICarriable
         worldObj = world;
         this.validate();
         world.removeBlockTileEntity(x, y, z);
-        world.setBlockTileEntity(x, y, z, this);
+        world.setTileEntity(x, y, z, this);
         Block<?> b = world.getBlock(x, y, z);
         if (b != null && holder instanceof Mob) {
             b.onBlockPlacedByMob(world, x, y, z, side, (Mob) holder, xPlaced, yPlaced);
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityActivator.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityActivator.java
index f678818a5..cdcd2ebd8 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityActivator.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityActivator.java
@@ -184,7 +184,7 @@ public class TileEntityActivator extends TileEntity implements Container {
     @Override
     public boolean stillValid(Player entityplayer)
     {
-        if(worldObj.getBlockEntity(x, y, z) != this)
+        if(worldObj == null || worldObj.getTileEntity(x, y, z) != this)
         {
             return false;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java
index b9be6cd03..13e4abeb3 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java
@@ -11,7 +11,7 @@ import net.minecraft.core.item.ItemStack;
 import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.tags.ListTag;
 import net.minecraft.core.net.packet.Packet;
-import net.minecraft.core.net.packet.PacketBlockEntityData;
+import net.minecraft.core.net.packet.PacketTileEntityData;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 
@@ -203,7 +203,7 @@ public class TileEntityBasket extends TileEntity
 
     @Override
     public Packet getDescriptionPacket() {
-        return new PacketBlockEntityData(this);
+        return new PacketTileEntityData(this);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityChest.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityChest.java
index 43b4edcb5..3c7504611 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityChest.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityChest.java
@@ -125,7 +125,7 @@ public class TileEntityChest extends TileEntity
     @Override
 	public boolean stillValid(Player entityplayer)
     {
-        if(worldObj.getBlockEntity(x, y, z) != this)
+        if(worldObj == null || worldObj.getTileEntity(x, y, z) != this)
         {
             return false;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java
index cc9692308..cb993fea7 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java
@@ -157,7 +157,7 @@ public class TileEntityDispenser extends TileEntity
     @Override
 	public boolean stillValid(Player entityplayer)
     {
-        if(worldObj.getBlockEntity(x, y, z) != this)
+        if(worldObj == null || worldObj.getTileEntity(x, y, z) != this)
         {
             return false;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlag.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlag.java
index dc88c5ca3..e28a08896 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlag.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlag.java
@@ -10,7 +10,7 @@ import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.packet.Packet;
-import net.minecraft.core.net.packet.PacketBlockEntityData;
+import net.minecraft.core.net.packet.PacketTileEntityData;
 import net.minecraft.core.player.inventory.container.Container;
 import net.minecraft.core.util.helper.UUIDHelper;
 import org.jetbrains.annotations.Nullable;
@@ -237,7 +237,7 @@ public class TileEntityFlag extends TileEntity
 
     @Override
     public Packet getDescriptionPacket() {
-        return new PacketBlockEntityData(this);
+        return new PacketTileEntityData(this);
     }
 
     @Override
@@ -275,7 +275,7 @@ public class TileEntityFlag extends TileEntity
     @Override
     public boolean stillValid(Player entityplayer)
     {
-        if(worldObj.getBlockEntity(x, y, z) != this)
+        if(worldObj == null || worldObj.getTileEntity(x, y, z) != this)
         {
             return false;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlowerJar.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlowerJar.java
index e1d943d51..6b1995c3a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlowerJar.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlowerJar.java
@@ -7,7 +7,7 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.packet.Packet;
-import net.minecraft.core.net.packet.PacketBlockEntityData;
+import net.minecraft.core.net.packet.PacketTileEntityData;
 import net.minecraft.core.world.World;
 
 public class TileEntityFlowerJar extends TileEntity {
@@ -48,7 +48,7 @@ public class TileEntityFlowerJar extends TileEntity {
 
     @Override
     public Packet getDescriptionPacket() {
-        return new PacketBlockEntityData(this);
+        return new PacketTileEntityData(this);
     }
 
 }
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java
index 4197fd6c3..154efaccd 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java
@@ -14,7 +14,7 @@ import net.minecraft.core.entity.EntityItem;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.net.packet.PacketBlockEntityData;
+import net.minecraft.core.net.packet.PacketTileEntityData;
 import net.minecraft.core.net.packet.Packet;
 import net.minecraft.core.player.inventory.container.Container;
 import net.minecraft.core.util.helper.Side;
@@ -322,7 +322,7 @@ public class TileEntityFurnace extends TileEntity
     @Override
 	public boolean stillValid(Player entityplayer)
     {
-        if(worldObj.getBlockEntity(x, y, z) != this)
+        if(worldObj == null || worldObj.getTileEntity(x, y, z) != this)
         {
             return false;
         }
@@ -371,7 +371,7 @@ public class TileEntityFurnace extends TileEntity
 
     @Override
     public Packet getDescriptionPacket() {
-        return new PacketBlockEntityData(this);
+        return new PacketTileEntityData(this);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMeshGold.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMeshGold.java
index bb153de03..9e1882d97 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMeshGold.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMeshGold.java
@@ -5,7 +5,7 @@ import net.minecraft.core.entity.EntityItem;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.packet.Packet;
-import net.minecraft.core.net.packet.PacketBlockEntityData;
+import net.minecraft.core.net.packet.PacketTileEntityData;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.Nullable;
 
@@ -79,6 +79,6 @@ public class TileEntityMeshGold extends TileEntity {
 
     @Override
     public Packet getDescriptionPacket() {
-        return new PacketBlockEntityData(this);
+        return new PacketTileEntityData(this);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java
index 868556838..d32e914b4 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java
@@ -5,7 +5,7 @@ import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumSignPicture;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.net.packet.Packet;
-import net.minecraft.core.net.packet.PacketBlockEntityData;
+import net.minecraft.core.net.packet.PacketTileEntityData;
 import net.minecraft.core.util.helper.UUIDHelper;
 import org.jetbrains.annotations.Nullable;
 
@@ -124,7 +124,7 @@ public class TileEntitySign extends TileEntity
     @Override
 	public Packet getDescriptionPacket()
     {
-        return new PacketBlockEntityData(this);
+        return new PacketTileEntityData(this);
     }
 
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityStatue.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityStatue.java
index 232058293..e933f3b10 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityStatue.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityStatue.java
@@ -5,20 +5,24 @@ import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.tags.ListTag;
 import com.mojang.nbt.tags.Tag;
 import net.minecraft.core.entity.IArmorWearing;
+import net.minecraft.core.entity.IItemHolding;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.packet.Packet;
-import net.minecraft.core.net.packet.PacketBlockEntityData;
+import net.minecraft.core.net.packet.PacketTileEntityData;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class TileEntityStatue extends TileEntity implements IArmorWearing<HumanArmorShape> {
+public class TileEntityStatue
+    extends TileEntity
+    implements IArmorWearing<HumanArmorShape>, IItemHolding {
+
     public enum Pose {
         DEFAULT(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f),
         LEFT_ARM_UP(-2.2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f),
         RIGHT_ARM_UP(0.0f, -2.2f, 0.0f, 0.0f, 0.0f, 0.0f),
         BOTH_ARMS_UP(-2.2f, -2.2f, 0.0f, 0.0f, 0.0f, 0.0f),
-        WALKING(0.75f, -0.75f, 0.5f, -0.5f, 0.0f, 0.0f),
+        WALKING(0.75f, -0.75f, -0.5f, 0.5f, 0.0f, 0.0f),
         LOOK_UP(0.0f, 0.0f, 0.0f, 0.0f, -0.3f, 0.0f),
         LOOK_DOWN(0.0f, 0.0f, 0.0f, 0.0f, 0.3f, 0.0f),
         LOOK_LEFT(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f),
@@ -43,12 +47,14 @@ public class TileEntityStatue extends TileEntity implements IArmorWearing<HumanA
     }
 
     private final @Nullable ItemStack @NotNull[] armorPieces = new ItemStack[HumanArmorShape.values().length];
+    private @Nullable ItemStack heldItem = null;
     private @NotNull Pose pose = Pose.DEFAULT;
 
     @Override
     public void writeToNBT(CompoundTag tag) {
         super.writeToNBT(tag);
 
+        // Write armor
         final @NotNull ListTag list = new ListTag();
         for (int i = 0; i < getNumArmorSlots(); i++) {
             final @Nullable HumanArmorShape slot = getArmorSlotByIndex(i);
@@ -63,13 +69,23 @@ public class TileEntityStatue extends TileEntity implements IArmorWearing<HumanA
             }
         }
         tag.putList("Armor", list);
+
+        // Write pose
         tag.putByte("Pose", (byte) this.pose.ordinal());
+
+        // Write held item
+        if (getHeldItem() != null) {
+            final @NotNull CompoundTag heldItemTag = new CompoundTag();
+            getHeldItem().writeToNBT(heldItemTag);
+            tag.putCompound("HeldItem", heldItemTag);
+        }
     }
 
     @Override
     public void readFromNBT(CompoundTag tag) {
         super.readFromNBT(tag);
 
+        // Read armor
         final @Nullable ListTag list = tag.getList("Armor");
         if (list != null) {
             for (Tag<?> t : list) {
@@ -89,11 +105,21 @@ public class TileEntityStatue extends TileEntity implements IArmorWearing<HumanA
             }
         }
 
+        // Read pose
         byte pose = tag.getByteOrDefault("Pose", (byte) Pose.DEFAULT.ordinal());
         if (pose < 0 || pose >= Pose.values().length) {
             pose = (byte) Pose.DEFAULT.ordinal();
         }
         this.pose = Pose.values()[pose];
+
+        // Read held item
+        final @Nullable CompoundTag heldItemTag = tag.getCompoundOrDefault("HeldItem", null);
+        if (heldItemTag != null) {
+            final @Nullable ItemStack heldItem = ItemStack.readItemStackFromNbt(heldItemTag);
+            if (heldItem != null) {
+                setHeldItem(heldItem);
+            }
+        }
     }
 
     public @NotNull Pose getPose() {
@@ -133,8 +159,23 @@ public class TileEntityStatue extends TileEntity implements IArmorWearing<HumanA
         return HumanArmorShape.values()[index];
     }
 
+    @Override
+    public @Nullable ItemStack getHeldItem() {
+        return this.heldItem;
+    }
+
+    @Override
+    public void setHeldItem(@Nullable ItemStack item) {
+        this.heldItem = item;
+    }
+
+    @Override
+    public boolean isLeftHanded() {
+        return false;
+    }
+
     @Override
     public Packet getDescriptionPacket() {
-        return new PacketBlockEntityData(this);
+        return new PacketTileEntityData(this);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java
index 0c87fde72..d2c26dfd3 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java
@@ -390,7 +390,7 @@ public class TileEntityTrommel extends TileEntity
     @Override
 	public boolean stillValid(Player entityplayer)
     {
-        if(worldObj.getBlockEntity(x, y, z) != this)
+        if(worldObj == null || worldObj.getTileEntity(x, y, z) != this)
         {
             return false;
         }
@@ -407,7 +407,7 @@ public class TileEntityTrommel extends TileEntity
         super.dropContents(world, x, y, z);
         if (!BlockLogicTrommel.keepTrommelInventory)
         {
-            if(world.getBlockEntity(x, y, z) != null)
+            if(world.getTileEntity(x, y, z) != null)
             {
                 label0:
                 for (int l = 0; l < getContainerSize(); l++)
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
index 357ff1c97..47cffcc7a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
@@ -72,7 +72,7 @@ public class BlockLogicPistonBase extends BlockLogic
     @Override
 	public void onBlockPlacedByWorld(World world, int x, int y, int z)
     {
-        if(!world.isClientSide && world.getBlockEntity(x, y, z) == null)
+        if(!world.isClientSide && world.getTileEntity(x, y, z) == null)
         {
             checkIfExtend(world, x, y, z);
         }
@@ -164,7 +164,7 @@ public class BlockLogicPistonBase extends BlockLogic
     }
 
     public void retractEvent(World world, int x, int y, int z, int data, Direction direction) {
-        TileEntity tileEntity = world.getBlockEntity(x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ());
+        TileEntity tileEntity = world.getTileEntity(x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ());
         if((tileEntity instanceof TileEntityMovingPistonBlock))
         {
             TileEntityMovingPistonBlock moving = ((TileEntityMovingPistonBlock) tileEntity);
@@ -318,7 +318,7 @@ public class BlockLogicPistonBase extends BlockLogic
                 return false;
             }
             if (Blocks.blocksList[blockId].getPistonPushReaction(world, xo, yo, zo) == Material.PISTON_DESTROY_ON_PUSH) {
-                Blocks.blocksList[blockId].dropBlockWithCause(world, EnumDropCause.WORLD, xo, yo, zo, world.getBlockMetadata(xo, yo, zo), world.getBlockEntity(xo, yo, zo), null);
+                Blocks.blocksList[blockId].dropBlockWithCause(world, EnumDropCause.WORLD, xo, yo, zo, world.getBlockMetadata(xo, yo, zo), world.getTileEntity(xo, yo, zo), null);
                 break;
             }
             if (blocks == maxPushedBlocks) {
@@ -335,7 +335,7 @@ public class BlockLogicPistonBase extends BlockLogic
             int pz = zo - direction.getOffsetZ();
             int pushId = world.getBlockId(px, py, pz);
             int pushMeta = world.getBlockMetadata(px, py, pz);
-            TileEntity pushEntity = world.getBlockEntity(px, py, pz);
+            TileEntity pushEntity = world.getTileEntity(px, py, pz);
             if (pushEntity instanceof TileEntityMovingPistonBlock && px == x && py == y && pz == z) {
                 break;
             }
@@ -344,7 +344,7 @@ public class BlockLogicPistonBase extends BlockLogic
                 createPistonHeadAt(world, xo, yo, zo, data, direction);
             } else if (pushId == Blocks.PISTON_MOVING.id())
             {
-                TileEntity old = world.getBlockEntity(px, py, pz);
+                TileEntity old = world.getTileEntity(px, py, pz);
                 if (old instanceof TileEntityMovingPistonBlock) {
                     TileEntityMovingPistonBlock moving = (TileEntityMovingPistonBlock) old;
                     if (!moving.isSourcePiston()) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSteel.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSteel.java
index dc3aaf49f..b24877e18 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSteel.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSteel.java
@@ -99,7 +99,7 @@ public class BlockLogicPistonBaseSteel extends BlockLogicPistonBase {
             Block<?> block = world.getBlock(xo, yo, zo);
             if (block == null) return true;
             int blockMeta = world.getBlockMetadata(xo, yo, zo);
-            TileEntity tileEntity = world.getBlockEntity(xo, yo, zo);
+            TileEntity tileEntity = world.getTileEntity(xo, yo, zo);
             world.removeBlockTileEntity(xo, yo, zo);
             world.setBlockWithNotify(xo, yo, zo, 0);
             if (!world.isClientSide) {
@@ -155,7 +155,7 @@ public class BlockLogicPistonBaseSteel extends BlockLogicPistonBase {
                     return false;
                 }
                 if (Blocks.blocksList[blockId].getPistonPushReaction(world, xo, yo, zo) == Material.PISTON_DESTROY_ON_PUSH) {
-                    Blocks.blocksList[blockId].dropBlockWithCause(world, EnumDropCause.WORLD, xo, yo, zo, world.getBlockMetadata(xo, yo, zo), world.getBlockEntity(xo, yo, zo), null);
+                    Blocks.blocksList[blockId].dropBlockWithCause(world, EnumDropCause.WORLD, xo, yo, zo, world.getBlockMetadata(xo, yo, zo), world.getTileEntity(xo, yo, zo), null);
                     break;
                 }
                 if (blocks == maxPushedBlocks) {
@@ -172,7 +172,7 @@ public class BlockLogicPistonBaseSteel extends BlockLogicPistonBase {
                     int py = yo - direction.getOffsetY();
                     int pz = zo - direction.getOffsetZ();
                     int pushId = world.getBlockId(px, py, pz);
-                    TileEntity pushEntity = world.getBlockEntity(px, py, pz);
+                    TileEntity pushEntity = world.getTileEntity(px, py, pz);
                     if (pushEntity instanceof TileEntityMovingPistonBlock && px == x && py == y && pz == z) {
                         break;
                     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSticky.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSticky.java
index d10a577f1..72ee874a6 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSticky.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSticky.java
@@ -15,7 +15,7 @@ public class BlockLogicPistonBaseSticky extends BlockLogicPistonBase {
 
     @Override
     public void retractEvent(World world, int x, int y, int z, int data, Direction direction) {
-        TileEntity tileEntity = world.getBlockEntity(x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ());
+        TileEntity tileEntity = world.getTileEntity(x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ());
         if((tileEntity instanceof TileEntityMovingPistonBlock))
         {
             TileEntityMovingPistonBlock moving = ((TileEntityMovingPistonBlock) tileEntity);
@@ -32,11 +32,11 @@ public class BlockLogicPistonBaseSticky extends BlockLogicPistonBase {
         int z1 = z + direction.getOffsetZ() * 2;
         int retractId = world.getBlockId(x1, y1, z1);
         int retactMeta = world.getBlockMetadata(x1, y1, z1);
-        TileEntity retractEntity = world.getBlockEntity(x1, y1, z1);
+        TileEntity retractEntity = world.getTileEntity(x1, y1, z1);
         boolean pulledMoving = false;
         if(retractId == Blocks.PISTON_MOVING.id())
         {
-            TileEntity tileEntity1 = world.getBlockEntity(x1, y1, z1);
+            TileEntity tileEntity1 = world.getTileEntity(x1, y1, z1);
             if((tileEntity1 instanceof TileEntityMovingPistonBlock))
             {
                 TileEntityMovingPistonBlock movingPistonBlock = (TileEntityMovingPistonBlock) tileEntity1;
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
index 8d51ad975..1bb4fb32a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
@@ -32,7 +32,7 @@ public class BlockLogicPistonMoving extends BlockLogic
     @Override
     public void onBlockRemoved(World world, int x, int y, int z, int data)
     {
-        TileEntity tileEntity = world.getBlockEntity(x, y, z);
+        TileEntity tileEntity = world.getTileEntity(x, y, z);
         if((tileEntity instanceof TileEntityMovingPistonBlock))
         {
             ((TileEntityMovingPistonBlock) tileEntity).finalTick();
@@ -69,10 +69,10 @@ public class BlockLogicPistonMoving extends BlockLogic
     @Override
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
     {
-        if(!world.isClientSide && world.getBlockEntity(x, y, z) == null)
+        if(!world.isClientSide && world.getTileEntity(x, y, z) == null)
         {
             int id = 0;
-            TileEntityMovingPistonBlock piston = getBlockEntity(world, x, y, z);
+            TileEntityMovingPistonBlock piston = getTileEntity(world, x, y, z);
             if (piston != null) id = piston.getMovedId();
             world.setBlockWithNotify(x, y, z, id);
             return true;
@@ -95,7 +95,7 @@ public class BlockLogicPistonMoving extends BlockLogic
         {
             return;
         }
-        TileEntityMovingPistonBlock piston = getBlockEntity(world, x, y, z);
+        TileEntityMovingPistonBlock piston = getTileEntity(world, x, y, z);
         if(piston != null)
         {
             Blocks.blocksList[piston.getMovedId()].dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, meta, null, null);
@@ -107,7 +107,7 @@ public class BlockLogicPistonMoving extends BlockLogic
     {
         if(!world.isClientSide)
         {
-            if(world.getBlockEntity(x, y, z) != null);
+            if(world.getTileEntity(x, y, z) != null);
         }
     }
 
@@ -120,7 +120,7 @@ public class BlockLogicPistonMoving extends BlockLogic
     @Override
 	public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
     {
-        TileEntityMovingPistonBlock tileEntity = getBlockEntity(world, x, y, z);
+        TileEntityMovingPistonBlock tileEntity = getTileEntity(world, x, y, z);
         if(tileEntity == null)
         {
             return null;
@@ -136,20 +136,20 @@ public class BlockLogicPistonMoving extends BlockLogic
     @Override
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z)
     {
-        TileEntityMovingPistonBlock pistonBlockEntity = getBlockEntity(world, x, y, z);
-        if(pistonBlockEntity != null)
+        TileEntityMovingPistonBlock pistonTileEntity = getTileEntity(world, x, y, z);
+        if(pistonTileEntity != null)
         {
-            Block<?> block = Blocks.blocksList[pistonBlockEntity.getMovedId()];
+            Block<?> block = Blocks.blocksList[pistonTileEntity.getMovedId()];
             if(block == null || block == this.block)
             {
                 return getBlockBoundsFromState(world, x, y, z);
             }
-            float f = pistonBlockEntity.getProgress(0.0F);
-            if(pistonBlockEntity.isExtending())
+            float f = pistonTileEntity.getProgress(0.0F);
+            if(pistonTileEntity.isExtending())
             {
                 f = 1.0F - f;
             }
-            Direction direction = pistonBlockEntity.getDirection();
+            Direction direction = pistonTileEntity.getDirection();
             AABB otherBounds = block.getBlockBoundsFromState(world, x, y, z);
             return AABB.getTemporaryBB(
             otherBounds.minX - direction.getOffsetX() * f,
@@ -184,9 +184,9 @@ public class BlockLogicPistonMoving extends BlockLogic
         }
     }
 
-    private TileEntityMovingPistonBlock getBlockEntity(WorldSource world, int x, int y, int z)
+    private TileEntityMovingPistonBlock getTileEntity(WorldSource world, int x, int y, int z)
     {
-        TileEntity tileEntity = world.getBlockEntity(x, y, z);
+        TileEntity tileEntity = world.getTileEntity(x, y, z);
         if(tileEntity instanceof TileEntityMovingPistonBlock)
         {
             return (TileEntityMovingPistonBlock) tileEntity;
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/TileEntityMovingPistonBlock.java b/game/core/src/main/java/net/minecraft/core/block/piston/TileEntityMovingPistonBlock.java
index e35cbd94d..1e44799d6 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/TileEntityMovingPistonBlock.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/TileEntityMovingPistonBlock.java
@@ -146,7 +146,7 @@ public class TileEntityMovingPistonBlock extends TileEntity
         if(worldObj.getBlockId(x, y, z) == Blocks.PISTON_MOVING.id()) {
             worldObj.setBlockAndMetadataRaw(x, y, z, movedId, movedData);
             if (movedEntity != null) {
-                TileEntity oldEnt = worldObj.getBlockEntity(x, y, z);
+                TileEntity oldEnt = worldObj.getTileEntity(x, y, z);
                 if (oldEnt != null) {
                     oldEnt.invalidate();
                 }
@@ -161,7 +161,7 @@ public class TileEntityMovingPistonBlock extends TileEntity
                 Blocks.blocksList[movedId].onBlockPlacedByWorld(worldObj, x, y, z);
                 Block.disableNormalEntityLogic = false;
             }
-            assert movedEntity == null || worldObj.getBlockEntity(x, y, z) == movedEntity : "Piston failed to actually move entity!";
+            assert movedEntity == null || worldObj.getTileEntity(x, y, z) == movedEntity : "Piston failed to actually move entity!";
             worldObj.notifyBlockChange(x, y, z, movedId);
         }
     }
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 920602191..a01d44a32 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
@@ -6,7 +6,6 @@ import java.util.Random;
 import net.minecraft.core.block.BlockLogicFluid;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.vehicle.EntityBoat;
-import net.minecraft.core.entity.vehicle.MobGhastVehicle;
 import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.world.Dimension;
@@ -1228,7 +1227,7 @@ public abstract class Entity
         if (vehicle == null) {
             return;
         }
-        if(vehicle.isRemoved() || (isSneaking() && !(vehicle instanceof MobGhastVehicle)))
+        if(vehicle.isRemoved() || isSneaking())
         {
             vehicle.ejectRider();
             return;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java b/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
index 7fb4b9ae6..5c6051b24 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
@@ -5,8 +5,7 @@ import net.minecraft.core.entity.animal.*;
 import net.minecraft.core.entity.monster.*;
 import net.minecraft.core.entity.projectile.*;
 import net.minecraft.core.entity.vehicle.EntityBoat;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
-import net.minecraft.core.entity.vehicle.MobGhastVehicle;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.world.World;
@@ -183,7 +182,7 @@ public final class EntityDispatcher
         addMapping(EntityPainting.class, new NamespaceID("minecraft", "painting"));
         addMapping(EntityLightning.class, new NamespaceID("minecraft", "lightning"));
         addMapping(EntityFallingBlock.class, new NamespaceID("minecraft", "falling_block"));
-        addMapping(MinecartEntity.class, new NamespaceID("minecraft", "minecart"));
+        addMapping(EntityMinecart.class, new NamespaceID("minecraft", "minecart"));
         addMapping(EntityBoat.class, new NamespaceID("minecraft", "boat"));
         addMapping(EntityPrimedTNT.class, new NamespaceID("minecraft", "primed_tnt"));
 
@@ -209,7 +208,6 @@ public final class EntityDispatcher
         addMapping(MobGiant.class, new NamespaceID("minecraft", "giant"));
         addMapping(MobSlime.class, new NamespaceID("minecraft", "slime"), "guidebook.section.mob.slime.name");
         addMapping(MobGhast.class, new NamespaceID("minecraft", "ghast"), "guidebook.section.mob.ghast.name");
-        addMapping(MobGhastVehicle.class, new NamespaceID("minecraft", "ghast_vehicle"), "guidebook.section.mob.ghast.name");
         addMapping(MobSnowman.class, new NamespaceID("minecraft", "snowman"), "guidebook.section.mob.snowman.name");
 
         // Passive
@@ -298,7 +296,7 @@ public final class EntityDispatcher
             addMapping(ProjectileFireball.class, "Fireball", 12);
             addMapping(EntityPrimedTNT.class, "PrimedTnt", 20);
             addMapping(EntityFallingBlock.class, "FallingSand", 21);
-            addMapping(MinecartEntity.class, "Minecart", 40);
+            addMapping(EntityMinecart.class, "Minecart", 40);
             addMapping(EntityBoat.class, "Boat", 41);
             addMapping(MobZombieArmored.class, "ArmouredZombie", 42);
             addMapping(ProjectileArrowGolden.class, "ArrowGolden", 43);
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 518d11a4d..25e249c0c 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
@@ -134,7 +134,7 @@ public class EntityFallingBlock extends Entity
                 } else if (!world.isClientSide) {
                     world.setBlockMetadata(x, y, z, carriedBlock.metadata);
                     if (carriedBlock.entity != null) {
-                        TileEntity oldEnt = world.getBlockEntity(x, y, z);
+                        TileEntity oldEnt = world.getTileEntity(x, y, z);
                         if (oldEnt != null) {
                             oldEnt.invalidate();
                         }
@@ -149,7 +149,7 @@ public class EntityFallingBlock extends Entity
                     world.notifyBlockChange(x, y, z, carriedBlock.blockId);
                 }
                 if (rider != null) {
-                    TileEntity te = world.getBlockEntity(x, y, z);
+                    TileEntity te = world.getTileEntity(x, y, z);
                     if (te instanceof IVehicle) rider.startRiding((IVehicle) te);
                 }
             } else if(fallTime > 600 && !world.isClientSide) {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/IItemHolding.java b/game/core/src/main/java/net/minecraft/core/entity/IItemHolding.java
new file mode 100644
index 000000000..cb6dc5d50
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/entity/IItemHolding.java
@@ -0,0 +1,12 @@
+package net.minecraft.core.entity;
+
+import net.minecraft.core.item.ItemStack;
+import org.jetbrains.annotations.Nullable;
+
+public interface IItemHolding {
+    @Nullable ItemStack getHeldItem();
+
+    void setHeldItem(final @Nullable ItemStack item);
+
+    boolean isLeftHanded();
+}
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Mob.java b/game/core/src/main/java/net/minecraft/core/entity/Mob.java
index 9abf2175b..364b45ff6 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Mob.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Mob.java
@@ -1283,11 +1283,6 @@ public abstract class Mob extends Entity
         return 4;
     }
 
-    public ItemStack getHeldItem()
-    {
-        return null;
-    }
-
     @Override
 	public void handleEntityEvent(byte byte0, float attackedAtYaw)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java
index 1bae21f1e..fd68f598f 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java
@@ -240,7 +240,7 @@ public class MobFireflyCluster extends MobFlying
             return false;
 
         int blockLight = world.getBlockLightValue(x, y, z);
-        if(world.getCurrentWeather() != null && world.getCurrentWeather().doMobsSpawnInDaylight)
+        if(world.getCurrentWeather() != null && world.getCurrentWeather().isMobDaylightSpawnAllowed())
             blockLight = blockLight/2;
 
         return  blockLight <= 4 && (Blocks.blocksList[id] != null && Blocks.blocksList[id].hasTag(BlockTags.FIREFLIES_CAN_SPAWN)) && world.checkIfAABBIsClear(bb.grow(-2f, 0f, -2f));
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
index fbf3fcfde..938d8d96e 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
@@ -2,6 +2,7 @@ package net.minecraft.core.entity.animal;
 
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityItem;
+import net.minecraft.core.entity.IItemHolding;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.projectile.ProjectileArrow;
@@ -20,10 +21,11 @@ import net.minecraft.core.world.World;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.util.helper.DamageType;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
 
-public class MobWolf extends MobAnimal
+public class MobWolf extends MobAnimal implements IItemHolding
 {
     public static final Map<ArmorMaterial, IArmorItem> ARMOR_MATERIALS = new HashMap<>();
     static {
@@ -79,11 +81,11 @@ public class MobWolf extends MobAnimal
     @Override
     public void spawnInit() {
         if(random.nextInt(25 /*Used to be 100, but I think having it that high would make it excessively rare*/) == 0){
-            setWolfHeldItem(new ItemStack(Items.RECORD_DOG, 1));
+            setHeldItem(new ItemStack(Items.RECORD_DOG, 1));
         }
     }
 
-    public ArmorMaterial getArmorMaterial() {
+    public @Nullable ArmorMaterial getArmorMaterial() {
         ArmorMaterial material = null;
         String name = entityData.getString(DATA_ARMOR_MATERIAL);
         for (ArmorMaterial mat : ArmorMaterial.getArmorMaterials()) {
@@ -168,9 +170,9 @@ public class MobWolf extends MobAnimal
         tag.putBoolean("Angry", isWolfAngry());
         tag.putBoolean("Sitting", isWolfSitting());
 
-        if(getWolfHeldItem() != null) {
+        if(getHeldItem() != null) {
             CompoundTag heldItemNBT = new CompoundTag();
-            getWolfHeldItem().writeToNBT(heldItemNBT);
+            getHeldItem().writeToNBT(heldItemNBT);
 
             tag.putCompound("HeldItem", heldItemNBT);
         }
@@ -195,7 +197,7 @@ public class MobWolf extends MobAnimal
             ItemStack stack = ItemStack.readItemStackFromNbt(heldItemStack);
             if (stack != null)
             {
-                setWolfHeldItem(stack);
+                setHeldItem(stack);
             }
         }
 
@@ -285,7 +287,7 @@ public class MobWolf extends MobAnimal
     {
         if(getHeldItem() != null && getHeldItem().stackSize > 0) {
         	dropItem(getHeldItem(), 0.0f);
-            setWolfHeldItem(null);
+            setHeldItem(null);
         }
         if (armor != null && armor.stackSize > 0){
             dropItem(armor, 0);
@@ -307,6 +309,10 @@ public class MobWolf extends MobAnimal
             }
         }
 
+        if (isWolfSitting()) {
+            setTarget(null);
+        }
+
         if(!hasAttacked && !hasPath() && isWolfTamed() && vehicle == null)
         {
             Player entityplayer = world.getPlayerEntityByUUID(getWolfOwner());
@@ -332,7 +338,7 @@ public class MobWolf extends MobAnimal
                 }
             }
         }
-        ItemStack heldItemSlot = getWolfHeldItem();
+        ItemStack heldItemSlot = getHeldItem();
         if((heldItemSlot == null || heldItemSlot.itemID <= 0)) {
             List<EntityItem> triedItems = new ArrayList<>();
             List<EntityItem> nearbyItems = world.getEntitiesWithinAABB(EntityItem.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
@@ -397,12 +403,6 @@ public class MobWolf extends MobAnimal
         }
     }
 
-    @Override
-    public ItemStack getHeldItem()
-    {
-        return getWolfHeldItem();
-    }
-
     @Override
 	public void tick()
     {
@@ -412,11 +412,11 @@ public class MobWolf extends MobAnimal
         if(entitiesNearWolf != null && !entitiesNearWolf.isEmpty() && isAlive())
         {
             for (Entity entity : entitiesNearWolf) {
-                if(entity instanceof EntityItem && (this.getWolfHeldItem() == null || this.getWolfHeldItem().getItem() == null)){
+                if(entity instanceof EntityItem && (this.getHeldItem() == null || this.getHeldItem().getItem() == null)){
                     EntityItem entityItem = (EntityItem) entity;
 
                     if (entityItem.item != null && entityItem.item.stackSize > 0) {
-                        setWolfHeldItem(entityItem.item.copy());
+                        setHeldItem(entityItem.item.copy());
                         entityItem.item.stackSize = 0;
                         entity.outOfWorld();
 
@@ -677,7 +677,11 @@ public class MobWolf extends MobAnimal
     {
         if(!fireImmune)
         {
-            float protection = 1.0f - getArmorMaterial().getProtection(DamageType.FIRE);
+            float protection = 0;
+            ArmorMaterial material;
+            if ((material = getArmorMaterial()) != null) {
+                protection = 1.0f - material.getProtection(DamageType.FIRE);
+            }
             protection = Math.max(protection, 0.01f);
             hurt(null, 4, DamageType.FIRE);
             remainingFireTicks = (int) (80 + 520 * protection);
@@ -689,7 +693,11 @@ public class MobWolf extends MobAnimal
     {
         if(!fireImmune)
         {
-            float protection = 1.0f - getArmorMaterial().getProtection(DamageType.FIRE);
+            float protection = 0;
+            ArmorMaterial material;
+            if ((material = getArmorMaterial()) != null) {
+                protection = 1.0f - material.getProtection(DamageType.FIRE);
+            }
             protection = Math.max(protection, 0.01f);
             hurt(null, 1, DamageType.FIRE);
             remainingFireTicks = (int) (40 + 260 * protection);
@@ -745,7 +753,7 @@ public class MobWolf extends MobAnimal
                 			player.inventory.setItem(player.inventory.getCurrentItemIndex(), null);
                 		}                		
                 	}
-                    heal(((ItemFood)Items.FOOD_PORKCHOP_RAW).getHealAmount());
+                    heal(itemfood.getHealAmount());
                     return true;
                 }
             }
@@ -770,11 +778,11 @@ public class MobWolf extends MobAnimal
             {
                 if(!world.isClientSide)
                 {
-                    ItemStack heldItemSlot = getWolfHeldItem();
+                    ItemStack heldItemSlot = getHeldItem();
                     if(isWolfSitting() && heldItemSlot != null && heldItemSlot.getItem() != null && heldItemSlot.itemID > 0 && !player.isSneaking()) {
                     	player.inventory.insertItem(heldItemSlot, true);
                     	if(heldItemSlot.stackSize <= 0) {
-                    		setWolfHeldItem(null);
+                    		setHeldItem(null);
                     	}
                     }else {
                         setWolfSitting(!isWolfSitting());
@@ -878,14 +886,6 @@ public class MobWolf extends MobAnimal
         }
     }
 
-    public ItemStack getWolfHeldItem(){
-        return entityData.getItemStack(DATA_HELD_ITEM);
-    }
-
-    public void setWolfHeldItem(ItemStack itemStack){
-        entityData.set(DATA_HELD_ITEM, itemStack);
-    }
-
     public boolean isWolfTamed()
     {
         return (entityData.getByte(DATA_GENERIC_FLAGS) & MASK_TAMED) != 0;
@@ -902,4 +902,19 @@ public class MobWolf extends MobAnimal
             entityData.set(DATA_GENERIC_FLAGS, (byte) (data & ~MASK_TAMED));
         }
     }
+
+    @Override
+    public @Nullable ItemStack getHeldItem() {
+        return this.entityData.getItemStack(DATA_HELD_ITEM);
+    }
+
+    @Override
+    public void setHeldItem(@Nullable ItemStack item) {
+        this.entityData.set(DATA_HELD_ITEM, item);
+    }
+
+    @Override
+    public boolean isLeftHanded() {
+        return false;
+    }
 }
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 cfc4e51e6..5bec715fd 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
@@ -4,7 +4,6 @@ import net.minecraft.core.WeightedRandomLootObject;
 import net.minecraft.core.entity.MobFlying;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.projectile.ProjectileFireball;
-import net.minecraft.core.entity.vehicle.MobGhastVehicle;
 import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.entity.Entity;
@@ -150,9 +149,6 @@ public class MobGhast extends MobFlying
             {
             	targetedEntity = null;
             }
-            if (targetedEntity != null && targetedEntity.vehicle instanceof MobGhastVehicle) {
-                targetedEntity = null;
-            }
             if(targetedEntity != null)
             {
                 aggroCooldown = 20;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonster.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonster.java
index 3240cecb2..f9e78d9d0 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonster.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonster.java
@@ -153,7 +153,7 @@ public abstract class MobMonster extends MobPathfinder
             return false;
 
         int blockLight = world.getBlockLightValue(blockX, blockY, blockZ);
-        if(world.getCurrentWeather() != null && world.getCurrentWeather().doMobsSpawnInDaylight)
+        if(world.getCurrentWeather() != null && world.getCurrentWeather().isMobDaylightSpawnAllowed())
             blockLight = blockLight/2;
 
         return blockLight <= 4 && super.canSpawnHere();
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonsterArmored.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonsterArmored.java
index e73ef804b..ad76c65fa 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonsterArmored.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonsterArmored.java
@@ -5,6 +5,7 @@ import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.tags.ListTag;
 import com.mojang.nbt.tags.Tag;
 import net.minecraft.core.entity.IArmorWearing;
+import net.minecraft.core.entity.IItemHolding;
 import net.minecraft.core.enums.IArmorShape;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.DamageType;
@@ -12,21 +13,17 @@ import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public abstract class MobMonsterArmored<T extends IArmorShape> extends MobMonster implements IArmorWearing<T> {
-    private static final int DATA_ARMOR_START = 24;
+public abstract class MobMonsterArmored<T extends IArmorShape>
+    extends MobMonster
+    implements IArmorWearing<T>, IItemHolding {
+
+    private static final int DATA_ITEM_HELD = 24;
+    private static final int DATA_ARMOR_START = 25;
 
     public MobMonsterArmored(final @Nullable World world) {
         super(world);
     }
 
-    @Override
-    protected void defineSynchedData() {
-        super.defineSynchedData();
-        for (int i = 0; i < getNumArmorSlots(); i++) {
-            this.entityData.define(DATA_ARMOR_START + i, null, ItemStack.class);
-        }
-    }
-
     @Override
     public @Nullable ItemStack getItemInArmorSlot(final @NotNull T slot) {
         return this.entityData.getItemStack(DATA_ARMOR_START + slot.getSlotIndex());
@@ -37,6 +34,30 @@ public abstract class MobMonsterArmored<T extends IArmorShape> extends MobMonste
         this.entityData.set(DATA_ARMOR_START + slot.getSlotIndex(), item);
     }
 
+    @Override
+    public @Nullable ItemStack getHeldItem() {
+        return this.entityData.getItemStack(DATA_ITEM_HELD);
+    }
+
+    @Override
+    public void setHeldItem(@Nullable ItemStack item) {
+        this.entityData.set(DATA_ITEM_HELD, item);
+    }
+
+    @Override
+    public boolean isLeftHanded() {
+        return false;
+    }
+
+    @Override
+    protected void defineSynchedData() {
+        super.defineSynchedData();
+        this.entityData.define(DATA_ITEM_HELD, null, ItemStack.class);
+        for (int i = 0; i < getNumArmorSlots(); i++) {
+            this.entityData.define(DATA_ARMOR_START + i, null, ItemStack.class);
+        }
+    }
+
     @Override
     public void addAdditionalSaveData(@NotNull CompoundTag tag) {
         super.addAdditionalSaveData(tag);
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobSkeleton.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobSkeleton.java
index b9b827d80..14b1ec861 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobSkeleton.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobSkeleton.java
@@ -4,25 +4,24 @@ import net.minecraft.core.WeightedRandomLootObject;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.projectile.ProjectileArrow;
 import net.minecraft.core.enums.HumanArmorShape;
-import net.minecraft.core.item.Item;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.util.helper.MathHelper;
-import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.Weathers;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
 public class MobSkeleton extends MobMonsterArmored<HumanArmorShape>
 {
+    private static final ItemStack DEFAULT_HELD_ITEM;
+
+    static {
+        DEFAULT_HELD_ITEM = new ItemStack(Items.TOOL_BOW, 1);
+    }
+
     public static final int DATA_ATTACK_TIME = 15;
 
     public MobSkeleton(World world) {
@@ -31,56 +30,6 @@ public class MobSkeleton extends MobMonsterArmored<HumanArmorShape>
         scoreValue = 500;
         mobDrops.add(new WeightedRandomLootObject(Items.AMMO_ARROW.getDefaultStack(), 0, 2));
         mobDrops.add(new WeightedRandomLootObject(Items.BONE.getDefaultStack(), 0, 2));
-
-        Map<ArmorMaterial, Map<HumanArmorShape, Item>> itemsMapMap = new HashMap<>();
-
-        Map<HumanArmorShape, Item> itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_LEATHER);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_LEATHER);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_LEATHER);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_LEATHER);
-        itemsMapMap.put(ArmorMaterial.LEATHER, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_IRON);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_IRON);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_IRON);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_IRON);
-        itemsMapMap.put(ArmorMaterial.IRON, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_GOLD);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_GOLD);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_GOLD);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_GOLD);
-        itemsMapMap.put(ArmorMaterial.GOLD, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_CHAINMAIL);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_CHAINMAIL);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_CHAINMAIL);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_CHAINMAIL);
-        itemsMapMap.put(ArmorMaterial.CHAINMAIL, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_DIAMOND);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_DIAMOND);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_DIAMOND);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_DIAMOND);
-        itemsMapMap.put(ArmorMaterial.DIAMOND, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_STEEL);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_STEEL);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_STEEL);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_STEEL);
-        itemsMapMap.put(ArmorMaterial.STEEL, itemsMap);
-
-        Random rand = new Random();
-        for (HumanArmorShape shape : HumanArmorShape.values()) {
-            ArmorMaterial mat = ArmorMaterial.getArmorMaterials().get(rand.nextInt(ArmorMaterial.getArmorMaterials().size()));
-            setItemInArmorSlot(shape, new ItemStack(itemsMapMap.get(mat).get(shape)));
-        }
     }
 
     @Override
@@ -107,6 +56,13 @@ public class MobSkeleton extends MobMonsterArmored<HumanArmorShape>
         entityData.define(DATA_ATTACK_TIME, attackTime, Integer.class);
     }
 
+    @Override
+    public void spawnInit() {
+        super.spawnInit();
+
+        setHeldItem(DEFAULT_HELD_ITEM.copy());
+    }
+
     @Override
 	public void onLivingUpdate()
     {
@@ -120,7 +76,7 @@ public class MobSkeleton extends MobMonsterArmored<HumanArmorShape>
             float f = getBrightness(1.0F);
             Weather weather;
             if(f > 0.5F && world.canBlockSeeTheSky(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z)) && random.nextFloat() * 30F < (f - 0.4F) * 2.0F
-                && (weather = world.getCurrentWeather()) != null &&  !weather.isDamp && (weather != Weathers.OVERWORLD_FOG || world.weatherManager.getWeatherPower() < 0.75F))
+                && (weather = world.getCurrentWeather()) != null &&  !weather.isDamp() && (weather != Weathers.OVERWORLD_FOG || world.weatherManager.getWeatherPower() < 0.75F))
             {
                 remainingFireTicks = 300;
             }
@@ -153,12 +109,6 @@ public class MobSkeleton extends MobMonsterArmored<HumanArmorShape>
         }
     }
 
-    @Override
-	public ItemStack getHeldItem()
-    {
-        return defaultHeldItem;
-    }
-
     @Override
     public int getNumArmorSlots() {
         return HumanArmorShape.values().length;
@@ -172,11 +122,4 @@ public class MobSkeleton extends MobMonsterArmored<HumanArmorShape>
 
         return HumanArmorShape.values()[index];
     }
-
-    private static final ItemStack defaultHeldItem;
-
-    static
-    {
-        defaultHeldItem = new ItemStack(Items.TOOL_BOW, 1);
-    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobSnowman.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobSnowman.java
index c3d8a3283..5b01ff77d 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobSnowman.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobSnowman.java
@@ -57,7 +57,6 @@ public class MobSnowman extends MobMonster
                     {
                         projectileSnowball.damage = 1;
                     }
-                    projectileSnowball.y += 1.4D;
                     double d2 = (entity.y + (double) entity.getHeadHeight()) - 0.2D - projectileSnowball.y;
                     float f1 = MathHelper.sqrt(dX * dX + dZ * dZ) * 0.2F;
                     world.playSoundAtEntity(null, this, "random.bow", 0.5F, 0.4F / (random.nextFloat() * 0.4F + 0.8F));
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombie.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombie.java
index cd9d8345e..22d3f052b 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombie.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombie.java
@@ -29,56 +29,6 @@ public class MobZombie extends MobMonsterArmored<HumanArmorShape>
         attackStrength = 5;
         scoreValue = 300;
         mobDrops.add(new WeightedRandomLootObject(Items.CLOTH.getDefaultStack(), 0, 2));
-
-        Map<ArmorMaterial, Map<HumanArmorShape, Item>> itemsMapMap = new HashMap<>();
-
-        Map<HumanArmorShape, Item> itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_LEATHER);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_LEATHER);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_LEATHER);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_LEATHER);
-        itemsMapMap.put(ArmorMaterial.LEATHER, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_IRON);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_IRON);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_IRON);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_IRON);
-        itemsMapMap.put(ArmorMaterial.IRON, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_GOLD);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_GOLD);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_GOLD);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_GOLD);
-        itemsMapMap.put(ArmorMaterial.GOLD, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_CHAINMAIL);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_CHAINMAIL);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_CHAINMAIL);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_CHAINMAIL);
-        itemsMapMap.put(ArmorMaterial.CHAINMAIL, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_DIAMOND);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_DIAMOND);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_DIAMOND);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_DIAMOND);
-        itemsMapMap.put(ArmorMaterial.DIAMOND, itemsMap);
-
-        itemsMap = new HashMap<>();
-        itemsMap.put(HumanArmorShape.BOOTS, Items.ARMOR_BOOTS_STEEL);
-        itemsMap.put(HumanArmorShape.LEGS, Items.ARMOR_LEGGINGS_STEEL);
-        itemsMap.put(HumanArmorShape.CHEST, Items.ARMOR_CHESTPLATE_STEEL);
-        itemsMap.put(HumanArmorShape.HEAD, Items.ARMOR_CHESTPLATE_STEEL);
-        itemsMapMap.put(ArmorMaterial.STEEL, itemsMap);
-
-        Random rand = new Random();
-        for (HumanArmorShape shape : HumanArmorShape.values()) {
-            ArmorMaterial mat = ArmorMaterial.getArmorMaterials().get(rand.nextInt(ArmorMaterial.getArmorMaterials().size()));
-            setItemInArmorSlot(shape, new ItemStack(itemsMapMap.get(mat).get(shape)));
-        }
     }
 
     @Override
@@ -89,7 +39,7 @@ public class MobZombie extends MobMonsterArmored<HumanArmorShape>
             float f = getBrightness(1.0F);
             Weather weather = world.getCurrentWeather();
             if(f > 0.5F && world.canBlockSeeTheSky(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z)) && random.nextFloat() * 30F < (f - 0.4F) * 2.0F
-                && weather != null && !weather.isDamp && (world.getCurrentWeather() != Weathers.OVERWORLD_FOG || world.weatherManager.getWeatherPower() < 0.75F))
+                && weather != null && !weather.isDamp() && (world.getCurrentWeather() != Weathers.OVERWORLD_FOG || world.weatherManager.getWeatherPower() < 0.75F))
             {
                 remainingFireTicks = 300;
             }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombieArmored.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombieArmored.java
index 035051a6f..a161e2c91 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombieArmored.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombieArmored.java
@@ -3,23 +3,32 @@ package net.minecraft.core.entity.monster;
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityItem;
+import net.minecraft.core.entity.IItemHolding;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.collection.NamespaceID;
 import net.minecraft.core.util.helper.DamageType;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
 
-public class MobZombieArmored extends MobZombie
+public class MobZombieArmored extends MobZombie implements IItemHolding
 {
     public static final int DATA_BREAK_POINTS = 6;
     public static final int DATA_BREAK_ORDER = 7;
     public static final int DATA_GENERIC_FLAGS = 8;
     public static final int MASK_FLAG_SWORD = 0b0000_0001;
+
+    private static final ItemStack DEFAULT_HELD_ITEM;
+
+    static {
+        DEFAULT_HELD_ITEM = new ItemStack(Items.TOOL_SWORD_IRON, 1);
+    }
+
     public MobZombieArmored(World world)
     {
         super(world);
@@ -54,21 +63,24 @@ public class MobZombieArmored extends MobZombie
     }
 
     @Override
-    public void defineSynchedData(){
+    public void defineSynchedData() {
         super.defineSynchedData();
         entityData.define(DATA_BREAK_POINTS, 0, Integer.class);
         entityData.define(DATA_BREAK_ORDER, (short) 0, Short.class);
         entityData.define(DATA_GENERIC_FLAGS, (byte) 0, Byte.class);
     }
+
     @Override
     public int getMaxHealth(){
         return 40;
     }
+
     @Override
 	public void onLivingUpdate()
     {
         super.onLivingUpdate();
     }
+
     @Override
     public boolean hurt(Entity attacker, int i, DamageType type)
     {
@@ -94,6 +106,7 @@ public class MobZombieArmored extends MobZombie
 
         return result;
     }
+
     public void setArmorBreakPoints(int[] breakPoints){
         int value = breakPoints[0];
         value |=  breakPoints[1] << 6;
@@ -101,10 +114,12 @@ public class MobZombieArmored extends MobZombie
         value |= breakPoints[3] << 18;
         entityData.set(6, value);
     }
+
     public int[] getArmorBreakPoints(){
         int value = entityData.getInt(6);
         return new int[]{value & 0x3F, (value & 0xFC0) >> 6, (value & 0x3_F000) >> 12, (value & 0xFC_0000) >> 18};
     }
+
     public void setArmorBreakOrder(int[] breakPoints){
         short value = (short) breakPoints[0];
         value |= (short) (breakPoints[1] << 2);
@@ -116,6 +131,7 @@ public class MobZombieArmored extends MobZombie
         short value = entityData.getShort(7);
         return new int[]{value & 0x3, (value & 0xC) >> 2, (value & 0x30) >> 4, (value & 0xC0) >> 6};
     }
+
     public void setHoldingSword(boolean flag){
         if (flag) {
             entityData.set(DATA_GENERIC_FLAGS, (byte)(entityData.getByte(DATA_GENERIC_FLAGS) | MASK_FLAG_SWORD));
@@ -157,13 +173,13 @@ public class MobZombieArmored extends MobZombie
 	public ItemStack getHeldItem()
     {
         if(this.isHoldingSword())
-            return defaultHeldItem;
+            return DEFAULT_HELD_ITEM;
         return null;
     }
-    private static final ItemStack defaultHeldItem;
 
-    static
-    {
-        defaultHeldItem = new ItemStack(Items.TOOL_SWORD_IRON, 1);
+    @Override
+    public void setHeldItem(@Nullable ItemStack item) {
+        return;
     }
+
 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombiePig.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombiePig.java
index f07d24e89..1fa3117c4 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombiePig.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobZombiePig.java
@@ -21,6 +21,15 @@ import java.util.List;
 
 public class MobZombiePig extends MobZombie
 {
+    private static final ItemStack DEFAULT_HELD_ITEM;
+
+    static
+    {
+        DEFAULT_HELD_ITEM = new ItemStack(Items.TOOL_SWORD_GOLD, 1);
+    }
+
+    private int angerLevel;
+    private int randomSoundDelay;
 
     public MobZombiePig(World world)
     {
@@ -34,6 +43,13 @@ public class MobZombiePig extends MobZombie
         scoreValue = 500;
     }
 
+    @Override
+    public void spawnInit() {
+        super.spawnInit();
+
+        setHeldItem(DEFAULT_HELD_ITEM.copy());
+    }
+
     @Override
 	public void tick()
     {
@@ -168,19 +184,4 @@ public class MobZombiePig extends MobZombie
 
         return drops;
     }
-
-    @Override
-	public ItemStack getHeldItem()
-    {
-        return defaultHeldItem;
-    }
-
-    private int angerLevel;
-    private int randomSoundDelay;
-    private static final ItemStack defaultHeldItem;
-
-    static 
-    {
-        defaultHeldItem = new ItemStack(Items.TOOL_SWORD_GOLD, 1);
-    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
index 920ca6120..8a7d9fa9f 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -36,7 +36,11 @@ import net.minecraft.core.entity.projectile.ProjectileCannonball;
 import net.minecraft.core.entity.projectile.ProjectileFireball;
 import net.minecraft.core.entity.projectile.ProjectileArrowGolden;
 import net.minecraft.core.entity.vehicle.EntityBoat;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
+import net.minecraft.core.enums.ArtType;
+import net.minecraft.core.enums.EnumDropCause;
+import net.minecraft.core.enums.EnumSleepStatus;
+import net.minecraft.core.item.IArmorItem;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
@@ -67,7 +71,9 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.UUID;
 
-public abstract class Player extends Mob implements IArmorWearing<HumanArmorShape>
+public abstract class Player
+    extends Mob
+    implements IArmorWearing<HumanArmorShape>, IItemHolding
 {
     public static final int DATA_UNKNOWN = 16; // I have no idea wtf this id is for
     public static final int DATA_SELECTED_ART = 17;
@@ -119,6 +125,8 @@ public abstract class Player extends Mob implements IArmorWearing<HumanArmorShap
     public int lastRenderTick = 0;
     public float wobbleTimer = 0;
 
+    public final PlayerConfig playerConfig = new PlayerConfig();
+
     public Player(World world)
     {
         super(world);
@@ -986,27 +994,27 @@ public abstract class Player extends Mob implements IArmorWearing<HumanArmorShap
         }
     }
     
-    public void displayFurnaceScreen(TileEntityFurnace blockEntity)
+    public void displayFurnaceScreen(TileEntityFurnace tileEntity)
     {
     }
 
-    public void displayTrommelScreen(TileEntityTrommel blockEntity)
+    public void displayTrommelScreen(TileEntityTrommel tileEntity)
     {
     }
 
-    public void displayDispenserScreen(TileEntityDispenser blockEntity)
+    public void displayDispenserScreen(TileEntityDispenser tileEntity)
     {
     }
 
-    public void displayActivatorScreen(TileEntityActivator blockEntity)
+    public void displayActivatorScreen(TileEntityActivator tileEntity)
     {
     }
 
-    public void displaySignEditorScreen(TileEntitySign blockEntity)
+    public void displaySignEditorScreen(TileEntitySign tileEntity)
     {
     }
 
-    public void displayFlagEditorScreen(TileEntityFlag blockEntity)
+    public void displayFlagEditorScreen(TileEntityFlag tileEntity)
     {
     }
 
@@ -1326,7 +1334,17 @@ public abstract class Player extends Mob implements IArmorWearing<HumanArmorShap
     {
         return inventory.getCurrentItem();
     }
-    
+
+    @Override
+    public boolean isLeftHanded() {
+        return playerConfig.isLeftHand();
+    }
+
+    @Override
+    public void setHeldItem(@Nullable ItemStack item) {
+        inventory.setCurrentItem(item, true);
+    }
+
     public void updateCreativeInventory(int page, String searchText)
     {
     }
@@ -1434,7 +1452,7 @@ public abstract class Player extends Mob implements IArmorWearing<HumanArmorShap
             int i = java.lang.Math.round(MathHelper.sqrt(d * d + d1 * d1 + d2 * d2) * 100F);
             if(i > 0)
             {
-                if(vehicle instanceof MinecartEntity)
+                if(vehicle instanceof EntityMinecart)
                 {
                     addStat(StatList.distanceByMinecartStat, i);
                     if(startMinecartRidingCoordinate == null)
@@ -1553,7 +1571,7 @@ public abstract class Player extends Mob implements IArmorWearing<HumanArmorShap
     		return;
     	}
     	
-    	TileEntity tileEntity = world.getBlockEntity(x, y, z);
+    	TileEntity tileEntity = world.getTileEntity(x, y, z);
     	ItemStack[] result = block.getBreakResult(world, EnumDropCause.PICK_BLOCK, x, y, z, meta, tileEntity);
     	ItemStack selectItem = result != null ? result[0] : null;
     	
@@ -1693,4 +1711,32 @@ public abstract class Player extends Mob implements IArmorWearing<HumanArmorShap
             return o1.username.compareTo(o2.username);
         }
     }
+
+    public static class PlayerConfig {
+        public static final int MASK_LEFT_HAND = 0b0000_0001;
+
+        public PlayerConfigListener listener;
+        public byte config = 0;
+
+        public void assignListener(PlayerConfigListener listener) {
+            this.listener = listener;
+        }
+
+        public boolean isLeftHand() {
+            return (config & MASK_LEFT_HAND) != 0;
+        }
+
+        public void setLeftHand(boolean leftHand) {
+            if (leftHand) {
+                config |= MASK_LEFT_HAND;
+            } else {
+                config &= ~MASK_LEFT_HAND;
+            }
+            if (listener != null) listener.onValueChange();
+        }
+
+        public interface PlayerConfigListener {
+            void onValueChange();
+        }
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/MinecartEntity.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
similarity index 90%
rename from game/core/src/main/java/net/minecraft/core/entity/vehicle/MinecartEntity.java
rename to game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
index 1efb9fef0..ed17b7bc4 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/MinecartEntity.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
@@ -27,13 +27,18 @@ import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
 
-public class MinecartEntity extends Entity implements Container {
-    public static final int PASSENGER_CART = 0;
-    public static final int CHEST_CART = 1;
-    public static final int FURNACE_CART = 2;
+public class EntityMinecart extends Entity implements Container {
+    public static final byte PASSENGER_CART = 0;
+    public static final byte CHEST_CART = 1;
+    public static final byte FURNACE_CART = 2;
 
     public static final int TYPE_MASK_COLOR = 0b1111_0000;
     public static final int TYPE_MASK_PAINTED_CHEST = 0b0000_0001;
+
+    public static final int FLAG_TYPE = 10;
+    public static final int FLAG_META = 11;
+    public static final int FLAG_FUEL = 12;
+
     // 10 x 2 x 3 table of something
     private static final int[][][] EXITS = {
         {
@@ -82,9 +87,6 @@ public class MinecartEntity extends Entity implements Container {
     public int timeSinceHit;
     public int hurtDirection;
     public boolean flipped;
-    public int type;
-    public int typeMeta; // Just used for chest color *for now*
-    public int fuel;
     public double xPush;
     public double zPush;
     private int lerpTicks;
@@ -98,7 +100,7 @@ public class MinecartEntity extends Entity implements Container {
     private double lerpZD;
 
 
-    public MinecartEntity(World world) {
+    public EntityMinecart(World world) {
         super(world);
         items = new ItemStack[36];
         currentDamage = 0;
@@ -109,7 +111,7 @@ public class MinecartEntity extends Entity implements Container {
         setSize(0.98F, 0.7F);
         heightOffset = bbHeight / 2.0F;
     }
-    public MinecartEntity(World world, double x, double y, double z, int type) {
+    public EntityMinecart(World world, double x, double y, double z, int type) {
         this(world);
         setPos(x, y + (double) heightOffset, z);
         xd = 0.0D;
@@ -118,7 +120,7 @@ public class MinecartEntity extends Entity implements Container {
         xo = x;
         yo = y;
         zo = z;
-        this.type = type;
+        setType((byte) type);
     }
     @Override
     public float getShadowHeightOffs() {
@@ -130,7 +132,21 @@ public class MinecartEntity extends Entity implements Container {
     }
     @Override
 	protected void defineSynchedData() {
+        entityData.define(FLAG_TYPE, (byte)0, Byte.class);
+        entityData.define(FLAG_META, 0, Integer.class);
+        entityData.define(FLAG_FUEL, (short)0, Short.class);
     }
+
+    public void setType(byte type) {entityData.set(FLAG_TYPE, type);}
+    public byte getType() {return entityData.getByte(FLAG_TYPE);}
+
+    public void setMeta(int meta) {entityData.set(FLAG_META, meta);}
+    public int getMeta() {return entityData.getInt(FLAG_META);}
+
+    public void setFuel(int fuel) {entityData.set(FLAG_FUEL, fuel);}
+    public short getFuel() {return entityData.getShort(FLAG_FUEL);}
+
+
     @Override
 	public boolean isPushable() {
         return true;
@@ -196,10 +212,10 @@ public class MinecartEntity extends Entity implements Container {
             }
             if (!world.isClientSide){
                 dropItem(Items.MINECART.id, 1, 0.0F);
-                switch (this.type){
+                switch (getType()){
                     case CHEST_CART:
-                        if ((typeMeta & TYPE_MASK_PAINTED_CHEST) != 0) {
-                            dropItem(new ItemStack(Blocks.CHEST_PLANKS_OAK_PAINTED, 1, typeMeta & TYPE_MASK_COLOR), 0.0F);
+                        if ((getMeta() & TYPE_MASK_PAINTED_CHEST) != 0) {
+                            dropItem(new ItemStack(Blocks.CHEST_PLANKS_OAK_PAINTED, 1, getMeta() & TYPE_MASK_COLOR), 0.0F);
                         } else {
                             dropItem(Blocks.CHEST_PLANKS_OAK.id(), 1, 0.0F);
                         }
@@ -393,7 +409,7 @@ public class MinecartEntity extends Entity implements Container {
                 yd *= 0.0D;
                 zd *= 0.997D;
             } else {
-                if(type == FURNACE_CART) {
+                if(getType() == FURNACE_CART) {
                     vel = Math.hypot(xPush, zPush);
                     if(vel > 0.01D) {
                         didFurnacePush = true;
@@ -432,7 +448,7 @@ public class MinecartEntity extends Entity implements Container {
                 xd = vel * (double)(newBlockX - blockX);
                 zd = vel * (double)(newBlockZ - blockZ);
             }
-            if(type == FURNACE_CART) {
+            if(getType() == FURNACE_CART) {
                 double pushMagnitude = Math.hypot(xPush, zPush);
                 if(pushMagnitude > 0.01D && Math.hypot(xd, zd) > 0.001D) {
                     xPush = xd;
@@ -497,7 +513,7 @@ public class MinecartEntity extends Entity implements Container {
         List<Entity> list = world.getEntitiesWithinAABBExcludingEntity(this, bb.expand(0.2D, 0.0D, 0.2));
         if(list != null && !list.isEmpty()) {
             for (Entity entity : list) {
-                if ((entity instanceof MinecartEntity) && entity != passenger && entity.isPushable()) {
+                if ((entity instanceof EntityMinecart) && entity != passenger && entity.isPushable()) {
                     entity.push(this);
                 }
             }
@@ -506,8 +522,8 @@ public class MinecartEntity extends Entity implements Container {
             passenger = null;
         }
         if(didFurnacePush && random.nextInt(4) == 0) {
-            fuel--;
-            if(fuel < 0) {
+            setFuel(getFuel() - 1);
+            if(getFuel() < 0) {
                 xPush = 0.0D;
                 zPush = 0.0D;
             }
@@ -636,7 +652,7 @@ public class MinecartEntity extends Entity implements Container {
         if(!entity.isPushable()) {
         	return;
         }
-        if(type == PASSENGER_CART && (entity instanceof Mob) && !(entity instanceof Player) && xd * xd + zd * zd > 0.01D && passenger == null && entity.vehicle == null) {
+        if(getType() == PASSENGER_CART && (entity instanceof Mob) && !(entity instanceof Player) && xd * xd + zd * zd > 0.01D && passenger == null && entity.vehicle == null) {
             entity.startRiding(this);
         }
         final double diffX = entity.x - this.x;
@@ -658,15 +674,17 @@ public class MinecartEntity extends Entity implements Container {
             final double n13 = n11 * (1.0f - this.pushthrough);
             final double xForce = n12 * 0.5;
             final double zForce = n13 * 0.5;
-            if (entity instanceof MinecartEntity) {
-                if (((MinecartEntity)entity).type == FURNACE_CART && this.type != FURNACE_CART) {
+            if (entity instanceof EntityMinecart) {
+                int thisType = getType();
+                int otherType = ((EntityMinecart) entity).getType();
+                if (otherType == FURNACE_CART && thisType != FURNACE_CART) {
                     this.xd *= 0.2;
                     this.zd *= 0.2;
                     this.push(entity.xd - xForce, 0.0, entity.zd - zForce);
                     entity.xd *= 0.7;
                     entity.zd *= 0.7;
                 }
-                else if (((MinecartEntity)entity).type != FURNACE_CART && this.type == FURNACE_CART) {
+                else if (otherType != FURNACE_CART && thisType == FURNACE_CART) {
                     entity.xd *= 0.2;
                     entity.zd *= 0.2;
                     entity.push(this.xd + xForce, 0.0, this.zd + zForce);
@@ -701,17 +719,17 @@ public class MinecartEntity extends Entity implements Container {
 
     @Override
 	public boolean interact(@NotNull Player player) {
-        switch (type){
+        switch (getType()){
             case PASSENGER_CART:
                 if (!world.isClientSide && passenger == null && player.isSneaking() && player.getHeldObject() instanceof CarriedBlock) {
                     CarriedBlock carriedBlock = (CarriedBlock) player.getHeldObject();
                     if (carriedBlock.entity instanceof TileEntityChest) {
                         TileEntityChest chest = (TileEntityChest) carriedBlock.entity;
-                        this.type = CHEST_CART;
+                        setType(CHEST_CART);
                         if (carriedBlock.blockId == Blocks.CHEST_PLANKS_OAK_PAINTED.id()) {
-                            this.typeMeta = carriedBlock.metadata & TYPE_MASK_COLOR | TYPE_MASK_PAINTED_CHEST;
+                            setMeta(carriedBlock.metadata & TYPE_MASK_COLOR | TYPE_MASK_PAINTED_CHEST);
                         } else {
-                            this.typeMeta = carriedBlock.metadata & TYPE_MASK_COLOR;
+                            setMeta(carriedBlock.metadata & TYPE_MASK_COLOR);
                         }
                         for (int i = 0; i < this.getContainerSize(); i++) {
                             this.setItem(i, chest.getItem(i));
@@ -731,22 +749,22 @@ public class MinecartEntity extends Entity implements Container {
             case CHEST_CART:
                 if(!world.isClientSide) {
                     if (player.isSneaking() && player.inventory.getCurrentItem() == null && player.getHeldObject() == null) {
-                        TileEntityChest blockEntity = new TileEntityChest();
+                        TileEntityChest tileEntityChest = new TileEntityChest();
                         for (int i = 0; i < this.getContainerSize(); i++) {
-                            blockEntity.setItem(i, this.getItem(i));
+                            tileEntityChest.setItem(i, this.getItem(i));
                             this.setItem(i, null);
                         }
-                        blockEntity.worldObj = null;
+                        tileEntityChest.worldObj = null;
                         Block<?> block;
-                        if ((typeMeta & TYPE_MASK_PAINTED_CHEST) != 0) {
+                        if ((getMeta() & TYPE_MASK_PAINTED_CHEST) != 0) {
                             block = Blocks.CHEST_PLANKS_OAK_PAINTED;
                         } else {
                             block = Blocks.CHEST_PLANKS_OAK;
                         }
-                        blockEntity.carriedBlock = blockEntity.getCarriedEntry(world, player, block, typeMeta & TYPE_MASK_COLOR);
-                        player.setHeldObject(blockEntity.carriedBlock);
-                        this.type = PASSENGER_CART;
-                        this.typeMeta = 0;
+                        tileEntityChest.carriedBlock = tileEntityChest.getCarriedEntry(world, player, block, getMeta() & TYPE_MASK_COLOR);
+                        player.setHeldObject(tileEntityChest.carriedBlock);
+                        setType(PASSENGER_CART);
+                        setMeta(0);
                     } else {
                         player.displayContainerScreen(this);
                     }
@@ -759,7 +777,7 @@ public class MinecartEntity extends Entity implements Container {
                     {
                         player.inventory.setItem(player.inventory.getCurrentItemIndex(), null);
                     }
-                    fuel += (int) ((LookupFuelFurnace.instance.getFuelYield(itemstack.itemID)/1600F) * 1200);
+                    setFuel(getFuel() + (int) ((LookupFuelFurnace.instance.getFuelYield(itemstack.itemID)/1600F) * 1200));
                 }
                 xPush = x - player.x;
                 zPush = z - player.z;
@@ -770,9 +788,9 @@ public class MinecartEntity extends Entity implements Container {
 
     @Override
     public void addAdditionalSaveData(@NotNull CompoundTag tag) {
-        tag.putInt("Type", type);
-        tag.putInt("TypeMeta", typeMeta);
-        switch (type){
+        tag.putInt("Type", getType());
+        tag.putInt("TypeMeta", getMeta());
+        switch (getType()){
             case CHEST_CART:
                 ListTag nbttaglist = new ListTag();
                 for(int i = 0; i < items.length; i++) {
@@ -788,16 +806,16 @@ public class MinecartEntity extends Entity implements Container {
             case FURNACE_CART:
                 tag.putDouble("PushX", xPush);
                 tag.putDouble("PushZ", zPush);
-                tag.putShort("Fuel", (short)fuel);
+                tag.putShort("Fuel", (short)getFuel());
                 break;
         }
     }
 
     @Override
     public void readAdditionalSaveData(@NotNull CompoundTag tag) {
-        type = tag.getInteger("Type");
-        typeMeta = tag.getInteger("TypeMeta");
-        switch (type){
+        setType((byte) tag.getInteger("Type"));
+        setMeta(tag.getInteger("TypeMeta"));
+        switch (getType()){
             case CHEST_CART:
                 ListTag nbttaglist = tag.getList("Items");
                 items = new ItemStack[getContainerSize()];
@@ -812,7 +830,7 @@ public class MinecartEntity extends Entity implements Container {
             case FURNACE_CART:
                 xPush = tag.getDouble("PushX");
                 zPush = tag.getDouble("PushZ");
-                fuel = tag.getShort("Fuel");
+                setFuel(tag.getShort("Fuel"));
                 break;
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/MobGhastVehicle.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/MobGhastVehicle.java
deleted file mode 100644
index 8f88ac0fe..000000000
--- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/MobGhastVehicle.java
+++ /dev/null
@@ -1,444 +0,0 @@
-package net.minecraft.core.entity.vehicle;
-
-import net.minecraft.core.block.Block;
-import net.minecraft.core.block.Blocks;
-import net.minecraft.core.block.entity.TileEntityFlag;
-import net.minecraft.core.block.material.Material;
-import net.minecraft.core.block.tag.BlockTags;
-import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.monster.MobGhast;
-import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.item.Items;
-import net.minecraft.core.player.gamemode.Gamemode;
-import net.minecraft.core.util.collection.NamespaceID;
-import net.minecraft.core.util.helper.BlockParticleHelper;
-import net.minecraft.core.util.helper.DamageType;
-import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.util.helper.Side;
-import net.minecraft.core.util.phys.AABB;
-import net.minecraft.core.world.World;
-
-import java.util.List;
-
-public class MobGhastVehicle extends MobGhast
-{
-    private static final double MAX_BOAT_SPEED = 1.2D;
-    private static final double ACCELERATION = 0.03D;
-    private static final float MAX_ROTATION_SPEED = 5f;
-    private static final float MIN_ROTATION_SPEED = 3f;
-    private static final double MAX_PACKET_SPEED_CHANGE = ACCELERATION * 8;
-    private static final double MAX_PACKET_ROTATION_CHANGE = MAX_ROTATION_SPEED * 4;
-    public int boatCurrentDamage;
-    public int boatTimeSinceHit;
-    public int boatRockDirection;
-    private int lerpTicks;
-    private double lerpX;
-    private double lerpY;
-    private double lerpZ;
-    private float lerpYRot;
-    private float boatPitch;
-    private double velocityX;
-    private double velocityY;
-    private double velocityZ;
-    private float pendingYRot;
-    private double pendingXDChange;
-    private double pendingYDChange;
-    private double pendingZDChange;
-
-
-    public MobGhastVehicle(World world)
-    {
-        super(world);
-        boatCurrentDamage = 0;
-        boatTimeSinceHit = 0;
-        boatRockDirection = 1;
-        blocksBuilding = true;
-        sendAdditionalData = true;
-        textureIdentifier = new NamespaceID("minecraft", "ghast_vehicle");
-    }
-
-    @Override
-    public void lookAt(Entity entity, float yRot, float xRot) {
-        return;
-    }
-
-    @Override
-    protected void updateAI() {
-        return;
-    }
-
-    @Override
-    public void onLivingUpdate() {
-        return;
-    }
-
-    @Override
-	protected boolean makeStepSound()
-    {
-        return false;
-    }
-
-    @Override
-	public AABB getBb()
-    {
-        return bb;
-    }
-
-    @Override
-	public boolean isPushable()
-    {
-        return true;
-    }
-
-    public MobGhastVehicle(World world, double d, double d1, double d2)
-    {
-        this(world);
-        setPos(d, d1 + (double) heightOffset, d2);
-        xd = 0.0D;
-        yd = 0.0D;
-        zd = 0.0D;
-        xo = d;
-        yo = d1;
-        zo = d2;
-    }
-
-    @Override
-	public double getRideHeight()
-    {
-        return (double) bbHeight - 0.3D;
-    }
-    @Override
-    public boolean hurt(Entity entity, int i, DamageType type)
-    {
-        int numParticles = random.nextInt(8) + 1;
-        for (int q = 0; q < numParticles; q++)
-        {
-            world.spawnParticle("block", x, y, z, xd, yd, zd, BlockParticleHelper.encodeBlockData(Blocks.PLANKS_OAK.id(), 0, Side.BOTTOM));
-        }
-        if(world.isClientSide || removed)
-        {
-            return true;
-        }
-        boatRockDirection = -boatRockDirection;
-        boatTimeSinceHit = 10;
-        boatCurrentDamage += i * 10;
-        markHurt();
-        if(boatCurrentDamage > 40)
-        {
-            if(passenger != null)
-            {
-                passenger.startRiding(this);
-            }
-            if(entity instanceof Player){
-                dropItem(Items.BOAT.id, 1, 0.0F);
-            }else {
-                for (int j = 0; j < 3; j++) {
-                    dropItem(Blocks.PLANKS_OAK.id(), 1, 0.0F);
-                }
-
-                for (int k = 0; k < 2; k++) {
-                    dropItem(Items.STICK.id, 1, 0.0F);
-                }
-            }
-
-            remove();
-        }
-        return true;
-    }
-
-    @Override
-    public void remove(){
-        Entity entity = passenger;
-
-        if (entity != null){
-            double bbCenterX = (bb.minX + bb.maxX)/2;
-            double bbCenterZ = (bb.minZ + bb.maxZ)/2;
-
-            this.passenger = null;
-            entity.vehicle = null;
-            entity.moveTo(bbCenterX, this.bb.maxY + 0.1, bbCenterZ, entity.yRot, entity.xRot);
-        }
-
-        super.remove();
-    }
-
-    @Override
-	public void animateHurt()
-    {
-        boatRockDirection = -boatRockDirection;
-        boatTimeSinceHit = 10;
-        boatCurrentDamage += boatCurrentDamage * 10;
-    }
-
-    @Override
-	public boolean isPickable()
-    {
-        return !removed;
-    }
-
-    @Override
-	public void lerpTo(double x, double y, double z, float yRot,
-                       float xRot, int i)
-    {
-        lerpX = x;
-        lerpY = y;
-        lerpZ = z;
-        boatPitch = xRot;
-        lerpTicks = i;
-        // Don't interpolate velocity from server when controlling the boat
-        if (passenger != null && !passenger.lerpVehicleMotion()) return;
-        lerpYRot = yRot;
-        xd = velocityX;
-        yd = velocityY;
-        zd = velocityZ;
-    }
-
-    @Override
-	public void lerpMotion(double xd, double yd, double zd)
-    {
-        // Don't interpolate velocity from server when controlling the boat
-        if (passenger != null && !passenger.lerpVehicleMotion()) return;
-        velocityX = this.xd = xd;
-        velocityY = this.yd = yd;
-        velocityZ = this.zd = zd;
-    }
-    @Override
-	public void tick()
-    {
-        setRot(yRot, xRot);
-        super.tick();
-        if(boatTimeSinceHit > 0)
-        {
-            boatTimeSinceHit--;
-        }
-        if(boatCurrentDamage > 0)
-        {
-            boatCurrentDamage--;
-        }
-        xo = x;
-        yo = y;
-        zo = z;
-        if(world.isClientSide)
-        {
-            if(lerpTicks > 0)
-            {
-                double lerpX = x + (this.lerpX - x) / (double) lerpTicks;
-                double lerpY = y + (this.lerpY - y) / (double) lerpTicks;
-                double lerpZ = z + (this.lerpZ - z) / (double) lerpTicks;
-                xRot += (boatPitch - xRot) / lerpTicks;
-                if (passenger == null || passenger.lerpVehicleMotion()){
-                    float lerpYRot;
-                    lerpYRot = MathHelper.normalizeRotation(this.lerpYRot - yRot);
-                    yRot += lerpYRot / lerpTicks;
-                }
-                lerpTicks--;
-                setPos(lerpX, lerpY, lerpZ);
-            }
-            boatMovement();
-            move(xd , yd, zd);
-            setRot(yRot, xRot);
-            xd *= 0.99D;
-            yd *= 0.99D;
-            zd *= 0.99D;
-            return;
-        }
-
-        boatMovement();
-
-        if (passenger == null){
-            float nextYRot = yRot;
-            if(Math.hypot(xd, zd) > 0.001D)
-            {
-                nextYRot = (float)Math.toDegrees(Math.atan2(zd, xd)) + 180;
-            }
-            float changeInYRot;
-            changeInYRot = MathHelper.normalizeRotation(nextYRot - yRot);
-            changeInYRot = MathHelper.clamp(changeInYRot, -20F, 20F);
-            yRot = MathHelper.normalizeRotation(yRot + changeInYRot);
-            setRot(yRot, xRot);
-        }
-
-        move(xd, yd, zd);
-
-        if (passenger == null || !passenger.deferVehicleBehavior()){
-            xd *= 0.99D;
-            yd *= 0.99D;
-            zd *= 0.99D;
-        }
-
-        xRot = 0.0F;
-
-        // Push entities in bounding box
-        List<Entity> list = world.getEntitiesWithinAABBExcludingEntity(this, bb.grow(0.2D, 0.0D, 0.2D));
-        if(list != null && !list.isEmpty())
-        {
-            for (Entity entity : list) {
-                if (entity != passenger && entity.isPushable() && (entity instanceof MobGhastVehicle)) {
-                    entity.push(this);
-                }
-            }
-        }
-
-        // Remove passenger is passenger removal is queued
-        if(passenger != null && passenger.removed)
-        {
-            passenger = null;
-        }
-
-        yBodyRot = yRot + 90;
-    }
-    public void boatMovement(){
-        double boatRad = Math.toRadians(yRot + 90);
-        double vectorRad = Math.atan2(xd, zd);
-        double currentBoatSpeed;
-        if (passenger != null){
-            boolean isBackwards = Math.cos(-boatRad - vectorRad) < 0;
-            double ang = vectorRad + boatRad + (isBackwards ? Math.PI : 0);
-
-            double _xd = xd;
-            xd = _xd * Math.cos(ang) - zd * Math.sin(ang);
-            zd = _xd * Math.sin(ang) + zd * Math.cos(ang);
-        }
-
-        double xdOff;
-        double ydOff;
-        double zdOff;
-        currentBoatSpeed = Math.hypot(xd, zd);
-        if(passenger != null) {
-            passenger.handleSpecialVehicleControl();
-        }
-        yRot += pendingYRot;
-        pendingYRot = 0;
-        xdOff = pendingXDChange;
-        ydOff = pendingYDChange;
-        zdOff = pendingZDChange;
-        pendingXDChange = 0;
-        pendingYDChange = 0;
-        pendingZDChange = 0;
-
-        double offsetMagnitude = Math.hypot(xdOff, zdOff);
-        double vecAngle = Math.acos((xd * xdOff + zd * zdOff)/ ((currentBoatSpeed + 0.00000000001D) * (offsetMagnitude + 0.00000000001D)));
-        double multiplier = (1 + (vecAngle/Math.PI)); // Increase acceleration if it runs opposite to the current motion vector
-        xdOff *= multiplier;
-        ydOff *= multiplier;
-        zdOff *= multiplier;
-
-//        System.out.printf("%f %f\n", xdOff, zdOff);
-
-        xd += xdOff;
-        yd += ydOff;
-        zd += zdOff;
-
-        if(passenger != null) {
-            passenger.sendSpecialVehiclePacket();
-        }
-
-        // Cap max speed properly
-        currentBoatSpeed = Math.hypot(xd, zd);
-        if (currentBoatSpeed > MAX_BOAT_SPEED){
-            xd = xd/currentBoatSpeed * MAX_BOAT_SPEED;
-            yd = yd/currentBoatSpeed * MAX_BOAT_SPEED;
-            zd = zd/currentBoatSpeed * MAX_BOAT_SPEED;
-        }
-
-        if(onGround)
-        {
-            xd *= 0.5D;
-            yd *= 0.5D;
-            zd *= 0.5D;
-        }
-    }
-
-    public void controlVehicle(float forward, float strafe, boolean jump, boolean sneak){
-        double currentBoatSpeed = Math.hypot(xd, zd);
-        pendingYRot = (float) (strafe * (MIN_ROTATION_SPEED + (MAX_ROTATION_SPEED - MIN_ROTATION_SPEED) * Math.max(((MAX_BOAT_SPEED - (currentBoatSpeed * 1.5))/ MAX_BOAT_SPEED), 0))); // I love interpolation
-        float velOff = (float) (forward * ACCELERATION);
-        pendingXDChange = Math.cos(Math.toRadians(yRot)) * velOff;
-        pendingZDChange = Math.sin(Math.toRadians(yRot)) * velOff;
-
-        if (jump && !sneak) {
-            pendingYDChange = ACCELERATION;
-        }
-        if (sneak && !jump) {
-            pendingYDChange = -ACCELERATION;
-        }
-    }
-
-    public void handleControlDirect(float xd, float zd, float yRot){
-        this.yRot = (float) MathHelper.clamp(yRot, this.yRot - MAX_PACKET_ROTATION_CHANGE, this.yRot + MAX_PACKET_ROTATION_CHANGE);
-        this.xd = MathHelper.clamp(xd, this.xd - MAX_PACKET_SPEED_CHANGE, this.xd + MAX_PACKET_SPEED_CHANGE);
-        this.zd = MathHelper.clamp(zd, this.zd - MAX_PACKET_SPEED_CHANGE, this.zd + MAX_PACKET_SPEED_CHANGE);
-    }
-
-    @Override
-	public void positionRider()
-    {
-        if (passenger != null) {
-            double d = Math.cos(((double) yRot * Math.PI) / 180D) * 0.4D;
-            double d1 = Math.sin(((double) yRot * Math.PI) / 180D) * 0.4D;
-            passenger.setPos(x + d, y + getRideHeight() + passenger.getRidingHeight(), z + d1);
-        }
-    }
-
-    @Override
-    public void waterHurt() {
-        return;
-    }
-
-    @Override
-	public float getShadowHeightOffs()
-    {
-        return 0.0F;
-    }
-
-    @Override
-	public boolean interact(Player entityplayer)
-    {
-        if(passenger != null && (passenger instanceof Player) && passenger != entityplayer)
-        {
-            return true;
-        }
-        if (passenger == entityplayer) {
-            ejectRider();
-            return true;
-        }
-        if(!world.isClientSide)
-        {
-            entityplayer.startRiding(this);
-        }
-        return true;
-    }
-    @Override
-    public Entity ejectRider() {
-        Entity entity = passenger;
-        if(entity == null) return null;
-
-        this.passenger = null;
-        entity.vehicle = null;
-
-        double bbCenterX = (bb.minX + bb.maxX)/2;
-        double bbCenterY = (bb.minY + bb.maxY)/2;
-        double bbCenterZ = (bb.minZ + bb.maxZ)/2;
-
-        boolean flag = false;
-        for (int i = 0; i < 4; i++) {
-            final double length = 1.75D;
-            double angle = Math.toRadians(yRot - 90) + (Math.PI/2) * i;
-            double checkX = bbCenterX + Math.cos(angle) * length;
-            double checkZ = bbCenterZ + Math.sin(angle) * length;
-            entity.moveTo(checkX, this.bb.maxY + 0.1, checkZ, entity.yRot, entity.xRot);
-            if (/*world.checkIfAABBIsClear(entity.bb) && */world.getCubes(entity, entity.bb).isEmpty()){
-                flag = true;
-                break;
-            }
-        }
-        if (!flag){
-            entity.moveTo(bbCenterX, this.bb.maxY + 0.1, bbCenterZ, entity.yRot, entity.xRot);
-        }
-        return entity;
-    }
-
-    @Override
-    protected void causeFallDamage(float distance){}
-}
diff --git a/game/core/src/main/java/net/minecraft/core/item/Item.java b/game/core/src/main/java/net/minecraft/core/item/Item.java
index 94f88a14f..8983d06d8 100644
--- a/game/core/src/main/java/net/minecraft/core/item/Item.java
+++ b/game/core/src/main/java/net/minecraft/core/item/Item.java
@@ -297,7 +297,7 @@ public class Item implements ITaggable<Item>, IItemConvertible
 
     public String getStatName()
     {
-        return I18n.getInstance().translateNameKey(getKey());
+        return I18n.getInstance().translateKey(getKey() + ".name");
     }
 
     public void inventoryTick(ItemStack itemstack, World world, Entity entity, int i, boolean flag)
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemDye.java b/game/core/src/main/java/net/minecraft/core/item/ItemDye.java
index 175a52360..f28d368c0 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemDye.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemDye.java
@@ -42,7 +42,7 @@ public class ItemDye extends Item
     {
         if (world.getBlockId(blockX, blockY, blockZ) == Blocks.SIGN_POST_PLANKS_OAK.id() || world.getBlockId(blockX, blockY, blockZ) == Blocks.SIGN_WALL_PLANKS_OAK.id())
         {
-            TileEntitySign sign = (TileEntitySign) world.getBlockEntity(blockX, blockY, blockZ);
+            TileEntitySign sign = (TileEntitySign) world.getTileEntity(blockX, blockY, blockZ);
             if ((DyeColor.WHITE.itemMeta - itemstack.getMetadata()) != sign.getColor().id)
             {
                 sign.setColor(TextFormatting.get(DyeColor.WHITE.itemMeta - itemstack.getMetadata()));
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java b/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java
index 325383700..7be3d76fe 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java
@@ -33,7 +33,7 @@ public class ItemFlag extends Item
     {
         // copy flag data to empty flag
 		if (world.getBlockId(blockX, blockY, blockZ) == Blocks.FLAG.id() && !entityplayer.isSneaking()) {
-			TileEntityFlag flag = (TileEntityFlag) world.getBlockEntity(blockX, blockY, blockZ);
+			TileEntityFlag flag = (TileEntityFlag) world.getTileEntity(blockX, blockY, blockZ);
 			if (flag != null) {
 				CompoundTag flagData = stack.getData().getCompoundOrDefault("FlagData", new CompoundTag());
 				if (hasFlagBeenDrawnOn(stack) && doesFlagContainDyes(stack)) {
@@ -74,7 +74,7 @@ public class ItemFlag extends Item
         world.setBlockAndMetadataWithNotify(blockX, blockY, blockZ, Blocks.FLAG.id(), 0);
         
         stack.consumeItem(entityplayer);
-        TileEntityFlag tileEntityFlag = (TileEntityFlag) world.getBlockEntity(blockX, blockY, blockZ);
+        TileEntityFlag tileEntityFlag = (TileEntityFlag) world.getTileEntity(blockX, blockY, blockZ);
         if(tileEntityFlag != null)
         {
             CompoundTag flagData = stack.getData().getCompoundOrDefault("FlagData", null);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemMap.java b/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
index c9ccc12be..5a78c5cc2 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
@@ -123,7 +123,7 @@ public class ItemMap extends Item implements IComplexItem
 		if (world.getBlockId(blockX, blockY, blockZ) == Blocks.FLAG.id()) {
 			ItemMapSavedData mapData = getOrCreateSavedData(itemstack, world);
 			if (mapData != null){
-				TileEntityFlag flag = (TileEntityFlag) world.getBlockEntity(blockX, blockY, blockZ);
+				TileEntityFlag flag = (TileEntityFlag) world.getTileEntity(blockX, blockY, blockZ);
 				boolean canCreateMap = mapData.createNewWaypoint(flag);
 				if(!canCreateMap)
 					player.sendTranslatedChatMessage("flag.full");
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemMinecart.java b/game/core/src/main/java/net/minecraft/core/item/ItemMinecart.java
index 83e29e168..48656bc64 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemMinecart.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemMinecart.java
@@ -6,7 +6,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicRail;
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.entity.player.Player;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
@@ -28,7 +28,7 @@ public class ItemMinecart extends Item {
         if (!Block.hasLogicClass(block, BlockLogicRail.class)) { return false; }
 
         if(!world.isClientSide) {
-            world.entityJoinedWorld(new MinecartEntity(world, (float) blockX + 0.5F, (float) blockY + 0.5F, (float) blockZ + 0.5F, minecartType));
+            world.entityJoinedWorld(new EntityMinecart(world, (float) blockX + 0.5F, (float) blockY + 0.5F, (float) blockZ + 0.5F, minecartType));
         }
         if (player == null || player.getGamemode().consumeBlocks()) {
             itemstack.stackSize--;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSign.java b/game/core/src/main/java/net/minecraft/core/item/ItemSign.java
index d092dd03b..d8b017b82 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemSign.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemSign.java
@@ -52,7 +52,7 @@ public class ItemSign extends Item
             world.setBlockAndMetadataWithNotify(blockX, blockY, blockZ, Blocks.SIGN_WALL_PLANKS_OAK.id(), sideHit);
         }
         itemstack.consumeItem(entityplayer);
-        TileEntitySign tileentitysign = (TileEntitySign)world.getBlockEntity(blockX, blockY, blockZ);
+        TileEntitySign tileentitysign = (TileEntitySign)world.getTileEntity(blockX, blockY, blockZ);
         if(tileentitysign != null)
         {
             tileentitysign.setOwner(entityplayer);
diff --git a/game/core/src/main/java/net/minecraft/core/item/Items.java b/game/core/src/main/java/net/minecraft/core/item/Items.java
index 4160f000e..291861c4a 100644
--- a/game/core/src/main/java/net/minecraft/core/item/Items.java
+++ b/game/core/src/main/java/net/minecraft/core/item/Items.java
@@ -3,7 +3,7 @@ package net.minecraft.core.item;
 import net.minecraft.core.achievement.stat.Stat;
 import net.minecraft.core.achievement.stat.StatList;
 import net.minecraft.core.block.Blocks;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.item.material.ToolMaterial;
@@ -195,7 +195,12 @@ public final class Items {
     public static Item JAR_BUTTERFLY_PINK;
     public static Item JAR_BUTTERFLY_SILVER;
     public static Item STATUE_STONE;
-    
+    public static Item STATUE_BASALT;
+    public static Item STATUE_LIMESTONE;
+    public static Item STATUE_GRANITE;
+    public static Item STATUE_MARBLE;
+    public static Item STATUE_PIGMAN;
+
     private static boolean hasInit = false;
     public static void init(){
         if (hasInit) return;
@@ -308,7 +313,7 @@ public final class Items {
         BUCKET = (new ItemBucketEmpty("bucket", "minecraft:item/bucket", 16453));
         BUCKET_WATER = (new ItemBucket("bucket.water", "minecraft:item/bucket_water", 16454, Blocks.FLUID_WATER_FLOWING)).setContainerItem(BUCKET);
         BUCKET_LAVA = (new ItemBucket("bucket.lava", "minecraft:item/bucket_lava", 16455, Blocks.FLUID_LAVA_FLOWING)).setContainerItem(BUCKET);
-        MINECART = (new ItemMinecart("minecart", "minecraft:item/minecart", 16456, MinecartEntity.PASSENGER_CART));
+        MINECART = (new ItemMinecart("minecart", "minecraft:item/minecart", 16456, EntityMinecart.PASSENGER_CART));
         SADDLE = (new ItemSaddle("saddle", "minecraft:item/saddle", 16457));
         DOOR_IRON = (new ItemDoor("door.iron", "minecraft:item/door_iron", 16458, Blocks.DOOR_IRON_BOTTOM, Blocks.DOOR_IRON_TOP));
         DUST_REDSTONE = (new ItemPlaceable("dust.redstone", "minecraft:item/dust_redstone", 16459, Blocks.WIRE_REDSTONE));
@@ -322,8 +327,8 @@ public final class Items {
         PAPER = (new Item("paper", "minecraft:item/paper", 16467));
         BOOK = (new Item("book", "minecraft:item/book", 16468));
         SLIMEBALL = (new Item("slimeball", "minecraft:item/slimeball", 16469));
-        MINECART_CHEST = (new ItemMinecart("minecart.chest", "minecraft:item/minecart_chest", 16470, MinecartEntity.CHEST_CART));
-        MINECART_FURNACE = (new ItemMinecart("minecart.furnace", "minecraft:item/minecart_furnace", 16471, MinecartEntity.FURNACE_CART));
+        MINECART_CHEST = (new ItemMinecart("minecart.chest", "minecraft:item/minecart_chest", 16470, EntityMinecart.CHEST_CART));
+        MINECART_FURNACE = (new ItemMinecart("minecart.furnace", "minecraft:item/minecart_furnace", 16471, EntityMinecart.FURNACE_CART));
         EGG_CHICKEN = (new ItemEgg("egg.chicken", "minecraft:item/egg_chicken", 16472));
         TOOL_COMPASS = (new Item("tool.compass", "minecraft:item/tool_compass", 16473));
         TOOL_FISHINGROD = (new ItemFishingRod("tool.fishingrod", "minecraft:item/tool_fishingrod", 16474));
@@ -410,5 +415,10 @@ public final class Items {
         JAR_BUTTERFLY_PINK = new ItemPlaceable("jar.butterfly.pink", "minecraft:item/jar_butterfly_pink", 16541, Blocks.JAR_BUTTERFLY_PINK);
         JAR_BUTTERFLY_SILVER = new ItemPlaceable("jar.butterfly.silver", "minecraft:item/jar_butterfly_silver", 16542, Blocks.JAR_BUTTERFLY_SILVER);
         STATUE_STONE = new ItemStatue("statue.stone", "minecraft:item/statue_stone", 16543, Blocks.STATUE_STONE_LOWER, Blocks.STATUE_STONE_UPPER);
+        STATUE_BASALT = new ItemStatue("statue.basalt", "minecraft:item/statue_basalt", 16544, Blocks.STATUE_BASALT_LOWER, Blocks.STATUE_BASALT_UPPER);
+        STATUE_LIMESTONE = new ItemStatue("statue.limestone", "minecraft:item/statue_limestone", 16545, Blocks.STATUE_LIMESTONE_LOWER, Blocks.STATUE_LIMESTONE_UPPER);
+        STATUE_GRANITE = new ItemStatue("statue.granite", "minecraft:item/statue_granite", 16546, Blocks.STATUE_GRANITE_LOWER, Blocks.STATUE_GRANITE_UPPER);
+        STATUE_MARBLE = new ItemStatue("statue.marble", "minecraft:item/statue_marble", 16547, Blocks.STATUE_MARBLE_LOWER, Blocks.STATUE_MARBLE_UPPER);
+        STATUE_PIGMAN = new ItemStatue("statue.pigman", "minecraft:item/statue_pigman", 16548, Blocks.STATUE_PIGMAN_LOWER, Blocks.STATUE_PIGMAN_UPPER);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/lang/I18n.java b/game/core/src/main/java/net/minecraft/core/lang/I18n.java
index b118a066d..1358620a9 100644
--- a/game/core/src/main/java/net/minecraft/core/lang/I18n.java
+++ b/game/core/src/main/java/net/minecraft/core/lang/I18n.java
@@ -1,138 +1,116 @@
 package net.minecraft.core.lang;
 
 import com.mojang.logging.LogUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
+import java.net.URL;
 import java.nio.file.*;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Stream;
 
 public class I18n {
-    private static final Logger LOGGER = LogUtils.getLogger();
-    private static I18n INSTANCE;
-    private Language currentLanguage;
+    private static final @NotNull Logger LOGGER = LogUtils.getLogger();
 
-    public static void initialize(String languageCode)
-    {
+    private static @Nullable I18n INSTANCE = null;
+    private @Nullable Language currentLanguage = null;
+
+    public static void initialize(final @NotNull String languageCode) {
         INSTANCE = new I18n(languageCode);
     }
 
-	private I18n(String languageCode) {
-        if (!LanguageSeeker.LANGUAGE_DIR.exists())
-        {
+    public static @Nullable I18n getInstance() {
+        return INSTANCE;
+    }
+
+    private I18n(final @NotNull String languageCode) {
+        if (!LanguageSeeker.LANGUAGE_DIR.exists()) {
             LanguageSeeker.LANGUAGE_DIR.mkdirs();
         }
-		reload(languageCode);
-	}
-
-    public void reload(String languageCode)
-    {
-        reload(languageCode, false);
+        reload(languageCode);
     }
 
-    public void reload(String languageCode, boolean save)
-    {
-        if (currentLanguage != null) {
-            currentLanguage.onReload();
+    public final void reload(final @NotNull String languageCode) {
+        if (this.currentLanguage != null) {
+            this.currentLanguage.onReload();
         }
         try {
-            currentLanguage = LanguageSeeker.seek(languageCode);
-            if (currentLanguage == null){
-                currentLanguage = Language.Default.INSTANCE;
+            this.currentLanguage = LanguageSeeker.seek(languageCode);
+            if (this.currentLanguage == null) {
+                this.currentLanguage = Language.Default.INSTANCE;
             }
-        } catch (IOException e) {
+        } catch (final @NotNull IOException e) {
             // Fallback to the default language if the specified language is not found
-            currentLanguage = Language.Default.INSTANCE;
+            this.currentLanguage = Language.Default.INSTANCE;
         }
 
-        LOGGER.info("{} Translation Keys", currentLanguage.keySize());
+        LOGGER.info("{} translation keys in {}", this.currentLanguage.keySize(), this.currentLanguage.getName());
     }
 
-    public static I18n getInstance()
-    {
-        return INSTANCE;
-    }
-
-    public String translateKey(String s)
-    {
-    	return currentLanguage.translateKey(s);
-    }
-
-    public String translateKeyAndFormat(String formatKey, Object... args)
-    {
-        return currentLanguage.translateKeyAndFormat(formatKey, args);
-    }
-
-    public String translateNameKey(String s)
-    {
-        return translateKey(s + ".name");
+    public @NotNull String translateKey(final @NotNull String key) {
+        if (this.currentLanguage == null) {
+            return key;
+        }
+        return this.currentLanguage.translateKey(key);
     }
 
-    public String translateDescKey(String s)
-    {
-        return translateKey(s + ".desc");
+    public @NotNull String translateKeyAndFormat(final @NotNull String key, final @Nullable Object @Nullable... args) {
+        if (this.currentLanguage == null) {
+            return key;
+        }
+        return this.currentLanguage.translateKeyAndFormat(key, args);
     }
 
-    public Language getCurrentLanguage() {
-        return currentLanguage;
+    public @Nullable Language getCurrentLanguage() {
+        return this.currentLanguage;
     }
 
-	public static InputStream getResourceAsStream(String path) {
+    public static @Nullable InputStream getResourceAsStream(final @NotNull String path) {
         return I18n.class.getResourceAsStream(path);
-	}
+    }
 
-    public static String[] getFilesInDirectory(String directory)
-    {
-        List<String> paths = new ArrayList<>();
+    public static @NotNull String @NotNull[] getFilesInDirectory(@NotNull String directory) {
+        final @NotNull List<@NotNull String> paths = new ArrayList<>();
 
         if (!directory.endsWith("/")) directory = directory + "/";
 
-        try
-        {
-            URI uri = I18n.class.getResource(directory).toURI();
-            Path myPath;
-            FileSystem fileSystem = null;
-            if (uri.getScheme().equals("jar"))
-            {
-                try
-                {
-                    fileSystem = FileSystems.getFileSystem(uri);
-                }
-                catch (Exception e)
-                {
-                    fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
-                }
-                myPath = fileSystem.getPath(directory);
-            }
-            else
-            {
-                myPath = Paths.get(uri);
+        try {
+            final @Nullable URL url = I18n.class.getResource(directory);
+            if (url == null) {
+                return new String[0];
             }
-            try (Stream<Path> walk = Files.walk(myPath, 1))
-            {
-                Iterator<Path> it = walk.iterator();
-                it.next();
-                while(it.hasNext())
-                {
-                    paths.add(directory + it.next().getFileName().toString());
+            final @NotNull URI uri = url.toURI();
+
+            if (uri.getScheme().equals("jar")) {
+                try (final @NotNull FileSystem files = FileSystems.getFileSystem(uri)) {
+                    walkFiles(directory, files.getPath(directory), paths);
+                } catch (final @NotNull Exception e) {
+                    try (final @NotNull FileSystem files = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
+                        walkFiles(directory, files.getPath(directory), paths);
+                    }
                 }
+            } else {
+                walkFiles(directory, Paths.get(uri), paths);
+
             }
-            if (fileSystem != null)
-            {
-                fileSystem.close();
-            }
-        }
-        catch (Exception e)
-        {
+        } catch (final Exception e) {
             LOGGER.error("Exception while loading all files in directory '{}' in translator!", directory, e);
         }
 
         return paths.toArray(new String[0]);
     }
+
+    private static void walkFiles(final @NotNull String directory, final @NotNull Path path, final @NotNull Collection<? super @NotNull String> paths) throws IOException {
+        try (final Stream<Path> walk = Files.walk(path, 1)) {
+            final Iterator<Path> it = walk.iterator();
+            it.next();
+            while (it.hasNext()) {
+                paths.add(directory + it.next().getFileName().toString());
+            }
+        }
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeWeather.java b/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeWeather.java
index 8d513a743..333f9401e 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeWeather.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeWeather.java
@@ -17,7 +17,7 @@ import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 
 public class ArgumentTypeWeather implements ArgumentType<Weather> {
-    private static final Collection<String> EXAMPLES = Arrays.asList(Weathers.OVERWORLD_CLEAR.languageKey, Weathers.OVERWORLD_FOG.languageKey);
+    private static final Collection<String> EXAMPLES = Arrays.asList(Weathers.OVERWORLD_CLEAR.getLanguageKey(), Weathers.OVERWORLD_FOG.getLanguageKey());
 
     public static ArgumentTypeWeather weather() {
         return new ArgumentTypeWeather();
@@ -29,7 +29,7 @@ public class ArgumentTypeWeather implements ArgumentType<Weather> {
 
         for (Weather weather : Weathers.WEATHERS) {
             if (weather == null) continue;
-            if (CommandHelper.matchesKeyString(weather.languageKey, string)) {
+            if (CommandHelper.matchesKeyString(weather.getLanguageKey(), string)) {
                 return weather;
             }
         }
@@ -41,7 +41,7 @@ public class ArgumentTypeWeather implements ArgumentType<Weather> {
         String remaining = builder.getRemainingLowerCase();
         for (Weather weather : Weathers.WEATHERS) {
             if (weather == null) continue;
-            Optional<String> optional = CommandHelper.getStringToSuggest(weather.languageKey, remaining);
+            Optional<String> optional = CommandHelper.getStringToSuggest(weather.getLanguageKey(), remaining);
             optional.ifPresent(builder::suggest);
         }
         return builder.buildFuture();
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandClone.java b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandClone.java
index b8c81d737..ffeb83a08 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandClone.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandClone.java
@@ -154,7 +154,7 @@ public class CommandClone implements CommandManager.CommandRegistry {
                         if (!destination.getWorld().isBlockLoaded(destinationX, destinationY, destinationZ)) throw NOWHERE_LOADED.create();
                         else throw SOURCE_NOT_LOADED.create();
                     }
-                    map.put(new IntegerCoordinates(new IntegerCoordinate(false, x - minX), new IntegerCoordinate(false, y - minY), new IntegerCoordinate(false, z - minZ)), new ClonedBlock(start.getWorld().getBlock(x, y, z), start.getWorld().getBlockMetadata(x, y, z), start.getWorld().getBlockEntity(x, y, z)));
+                    map.put(new IntegerCoordinates(new IntegerCoordinate(false, x - minX), new IntegerCoordinate(false, y - minY), new IntegerCoordinate(false, z - minZ)), new ClonedBlock(start.getWorld().getBlock(x, y, z), start.getWorld().getBlockMetadata(x, y, z), start.getWorld().getTileEntity(x, y, z)));
                     if (cloneMode == CloneMode.MOVE) {
                         start.getWorld().setBlockWithNotify(x, y, z, 0);
                     }
@@ -171,13 +171,13 @@ public class CommandClone implements CommandManager.CommandRegistry {
             int offsetDestinationY = destinationY + entry.getKey().getY(source, true);
             int offsetDestinationZ = destinationZ + entry.getKey().getZ(source);
             CompoundTag blockTag = new CompoundTag();
-            TileEntity tileEntity = destination.getWorld().getBlockEntity(offsetDestinationX, offsetDestinationY, offsetDestinationZ);
+            TileEntity tileEntity = destination.getWorld().getTileEntity(offsetDestinationX, offsetDestinationY, offsetDestinationZ);
             if (tileEntity != null) tileEntity.writeToNBT(blockTag);
             if (filter == null || (destination.getWorld().getBlockId(offsetDestinationX, offsetDestinationY, offsetDestinationZ) == filter.getBlockId() && destination.getWorld().getBlockMetadata(offsetDestinationX, offsetDestinationY, offsetDestinationZ) == filter.getMetadata() && (filter.getTag().getValues().isEmpty() || CommandHelper.blockEntitiesAreEqual(blockTag, filter.getTag())))) {
                 if (destination.getWorld().getBlockId(offsetDestinationX, offsetDestinationY, offsetDestinationZ) != entry.getValue().getBlockId() || destination.getWorld().getBlockMetadata(offsetDestinationX, offsetDestinationY, offsetDestinationZ) != entry.getValue().getMetadata()) ++clonedBlocks;
                 destination.getWorld().setBlockWithNotify(offsetDestinationX, offsetDestinationY, offsetDestinationZ, entry.getValue().getBlockId());
                 destination.getWorld().setBlockMetadataWithNotify(offsetDestinationX, offsetDestinationY, offsetDestinationZ, entry.getValue().getMetadata());
-                CommandHelper.setBlockEntity(destination.getWorld(), offsetDestinationX, offsetDestinationY, offsetDestinationZ, entry.getValue().getBlockEntity());
+                CommandHelper.setTileEntity(destination.getWorld(), offsetDestinationX, offsetDestinationY, offsetDestinationZ, entry.getValue().getTileEntity());
             }
         }
         destination.getWorld().noNeighborUpdate = false;
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandFill.java b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandFill.java
index c741b7708..071213d5d 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandFill.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandFill.java
@@ -126,17 +126,17 @@ public class CommandFill implements CommandManager.CommandRegistry {
             for (int y = minY; y <= maxY; y++) {
                 for (int z = minZ; z <= maxZ; z++) {
                     CompoundTag blockTag = new CompoundTag();
-                    TileEntity tileEntity = world.getBlockEntity(x, y, z);
+                    TileEntity tileEntity = world.getTileEntity(x, y, z);
                     if (tileEntity != null) tileEntity.writeToNBT(blockTag);
-                    if ((block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getBlockEntity(x, y, z)))) && (filter == null || (world.getBlockId(x, y, z) == filter.getBlockId() && world.getBlockMetadata(x, y, z) == filter.getMetadata() && (filter.getTag().getValues().isEmpty() || CommandHelper.blockEntitiesAreEqual(blockTag, filter.getTag()))))) {
+                    if ((block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getTileEntity(x, y, z)))) && (filter == null || (world.getBlockId(x, y, z) == filter.getBlockId() && world.getBlockMetadata(x, y, z) == filter.getMetadata() && (filter.getTag().getValues().isEmpty() || CommandHelper.blockEntitiesAreEqual(blockTag, filter.getTag()))))) {
                         ++blocksFilled;
                         if (destroy && world.getBlock(x, y, z) != null)
-                            world.getBlock(x, y, z).getBreakResult(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), world.getBlockEntity(x, y, z));
+                            world.getBlock(x, y, z).getBreakResult(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), world.getTileEntity(x, y, z));
                     }
-                    if (filter == null || (world.getBlockId(x, y, z) == filter.getBlockId() && world.getBlockMetadata(x, y, z) == filter.getMetadata() && (!filter.getTag().getValue().isEmpty() || CommandHelper.blockEntitiesAreEqual(CommandHelper.tagFrom(world.getBlockEntity(x, y, z)), filter.getTag())))) {
+                    if (filter == null || (world.getBlockId(x, y, z) == filter.getBlockId() && world.getBlockMetadata(x, y, z) == filter.getMetadata() && (!filter.getTag().getValue().isEmpty() || CommandHelper.blockEntitiesAreEqual(CommandHelper.tagFrom(world.getTileEntity(x, y, z)), filter.getTag())))) {
                         world.setBlockWithNotify(x, y, z, block.getBlockId());
                         world.setBlockMetadataWithNotify(x, y, z, block.getMetadata());
-                        CommandHelper.setBlockEntity(world, x, y, z, block.getTag());
+                        CommandHelper.setTileEntity(world, x, y, z, block.getTag());
                     }
                 }
             }
@@ -160,14 +160,14 @@ public class CommandFill implements CommandManager.CommandRegistry {
             for (int y = minY; y <= maxY; y++) {
                 for (int z = minZ; z <= maxZ; z++) {
                     boolean isOutline = x == minX || x == maxX || y == minY || y == maxY || z == minZ || z == maxZ;
-                    if ((isOutline && (block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getBlockEntity(x, y, z))))) || (!isOutline && world.getBlockId(x, y, z) != 0)) {
+                    if ((isOutline && (block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getTileEntity(x, y, z))))) || (!isOutline && world.getBlockId(x, y, z) != 0)) {
                         ++blocksFilled;
                         if (!isOutline && world.getBlock(x, y, z) != null)
-                            world.getBlock(x, y, z).getBreakResult(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), world.getBlockEntity(x, y, z));
+                            world.getBlock(x, y, z).getBreakResult(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), world.getTileEntity(x, y, z));
                     }
                     world.setBlockWithNotify(x, y, z, isOutline ? block.getBlockId() : 0);
                     world.setBlockMetadataWithNotify(x, y, z, isOutline ? block.getMetadata() : 0);
-                    CommandHelper.setBlockEntity(world, x, y, z, block.getTag());
+                    CommandHelper.setTileEntity(world, x, y, z, block.getTag());
                 }
             }
         }
@@ -190,12 +190,12 @@ public class CommandFill implements CommandManager.CommandRegistry {
             for (int y = minY; y <= maxY; y++) {
                 for (int z = minZ; z <= maxZ; z++) {
                     boolean isOutline = x == minX || x == maxX || y == minY || y == maxY || z == minZ || z == maxZ;
-                    if (isOutline && (block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getBlockEntity(x, y, z)))))
+                    if (isOutline && (block.getBlockId() != world.getBlockId(x, y, z) || block.getMetadata() != world.getBlockMetadata(x, y, z) || !CommandHelper.blockEntitiesAreEqual(block.getTag(), CommandHelper.tagFrom(world.getTileEntity(x, y, z)))))
                         ++blocksFilled;
                     if (isOutline) {
                         world.setBlockWithNotify(x, y, z, block.getBlockId());
                         world.setBlockMetadataWithNotify(x, y, z, block.getMetadata());
-                        CommandHelper.setBlockEntity(world, x, y, z, block.getTag());
+                        CommandHelper.setTileEntity(world, x, y, z, block.getTag());
                     }
                 }
             }
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandSetBlock.java b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandSetBlock.java
index 45323a052..4e360d59c 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandSetBlock.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandSetBlock.java
@@ -37,7 +37,7 @@ public class CommandSetBlock implements CommandManager.CommandRegistry {
                                     } else {
                                         world.setBlockWithNotify(x, y, z, blockInput.getBlockId());
                                         world.setBlockMetadataWithNotify(x, y, z, blockInput.getMetadata());
-                                        CommandHelper.setBlockEntity(world, x, y, z, blockInput.getTag());
+                                        CommandHelper.setTileEntity(world, x, y, z, blockInput.getTag());
                                         source.sendTranslatableMessage("command.commands.setblock.success", coordinates.getX(source), coordinates.getY(source, true), coordinates.getZ(source));
                                     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandTestFor.java b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandTestFor.java
index 9e5398f11..3da906f2f 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandTestFor.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandTestFor.java
@@ -36,7 +36,7 @@ public class CommandTestFor implements CommandManager.CommandRegistry {
                                             BlockInput block = c.getArgument("block", BlockInput.class);
                                             IntegerCoordinates secondPos = c.getArgument("second", IntegerCoordinates.class);
                                             CompoundTag blockInWorldCompoundTag = new CompoundTag();
-                                            TileEntity tileEntity = c.getSource().getWorld().getBlockEntity(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource()));
+                                            TileEntity tileEntity = c.getSource().getWorld().getTileEntity(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource()));
                                             if (tileEntity != null) tileEntity.writeToNBT(blockInWorldCompoundTag);
                                             if (c.getSource().getWorld().getBlock(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource())) == block.getBlock()
                                             && c.getSource().getWorld().getBlockMetadata(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource())) == block.getMetadata()
@@ -70,10 +70,10 @@ public class CommandTestFor implements CommandManager.CommandRegistry {
                                             }
 
                                             CompoundTag firstTag = new CompoundTag();
-                                            TileEntity firstTileEntity = c.getSource().getWorld().getBlockEntity(firstPos.getX(c.getSource()), firstPos.getY(c.getSource(), true), firstPos.getZ(c.getSource()));
+                                            TileEntity firstTileEntity = c.getSource().getWorld().getTileEntity(firstPos.getX(c.getSource()), firstPos.getY(c.getSource(), true), firstPos.getZ(c.getSource()));
                                             if (firstTileEntity != null) firstTileEntity.writeToNBT(firstTag);
                                             CompoundTag secondTag = new CompoundTag();
-                                            TileEntity secondTileEntity = c.getSource().getWorld().getBlockEntity(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource()));
+                                            TileEntity secondTileEntity = c.getSource().getWorld().getTileEntity(secondPos.getX(c.getSource()), secondPos.getY(c.getSource(), true), secondPos.getZ(c.getSource()));
                                             if (secondTileEntity != null) secondTileEntity.writeToNBT(secondTag);
 
                                             if (!CommandHelper.blockEntitiesAreEqual(firstTag, secondTag)) {
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandWeather.java b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandWeather.java
index 8cb4e8ce2..5e64fe611 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandWeather.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandWeather.java
@@ -25,7 +25,7 @@ public class CommandWeather implements CommandManager.CommandRegistry {
                         Weather weather = Weathers.OVERWORLD_CLEAR;
 
                         world.weatherManager.overrideWeather(weather);
-                        source.sendTranslatableMessage("command.commands.weather.success", weather.getTranslatedName());
+                        source.sendTranslatableMessage("command.commands.weather.success", weather.getNameLanguageKey());
                         return Command.SINGLE_SUCCESS;
                     }))
                 .then(RequiredArgumentBuilder.<CommandSource, Weather>argument("weather", ArgumentTypeWeather.weather())
@@ -35,7 +35,7 @@ public class CommandWeather implements CommandManager.CommandRegistry {
                             Weather weather = c.getArgument("weather", Weather.class);
 
                             world.weatherManager.overrideWeather(weather);
-                            source.sendTranslatableMessage("command.commands.weather.success", weather.getTranslatedName());
+                            source.sendTranslatableMessage("command.commands.weather.success", weather.getNameLanguageKey());
                             return Command.SINGLE_SUCCESS;
                         })
                         .then(RequiredArgumentBuilder.<CommandSource, Integer>argument("duration", ArgumentTypeTime.time())
@@ -45,7 +45,7 @@ public class CommandWeather implements CommandManager.CommandRegistry {
                                     Weather weather = c.getArgument("weather", Weather.class);
 
                                     world.weatherManager.overrideWeather(weather, c.getArgument("duration", Integer.class));
-                                    source.sendTranslatableMessage("command.commands.weather.success", weather.getTranslatedName());
+                                    source.sendTranslatableMessage("command.commands.weather.success", weather.getNameLanguageKey());
                                     return Command.SINGLE_SUCCESS;
                                 })
                                 .then(RequiredArgumentBuilder.<CommandSource, Float>argument("power", FloatArgumentType.floatArg())
@@ -55,7 +55,7 @@ public class CommandWeather implements CommandManager.CommandRegistry {
                                             Weather weather = c.getArgument("weather", Weather.class);
 
                                             world.weatherManager.overrideWeather(weather, c.getArgument("duration", Integer.class), c.getArgument("power", Float.class));
-                                            source.sendTranslatableMessage("command.commands.weather.success", weather.getTranslatedName());
+                                            source.sendTranslatableMessage("command.commands.weather.success", weather.getNameLanguageKey());
                                             return Command.SINGLE_SUCCESS;
                                         })))));
         dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("w")
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/helpers/ClonedBlock.java b/game/core/src/main/java/net/minecraft/core/net/command/helpers/ClonedBlock.java
index cddff7fb4..d179514ea 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/helpers/ClonedBlock.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/helpers/ClonedBlock.java
@@ -29,7 +29,7 @@ public class ClonedBlock {
         return this.metadata;
     }
 
-    public TileEntity getBlockEntity() {
+    public TileEntity getTileEntity() {
         return this.tileEntity;
     }
 }
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java b/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java
index 1c8a08542..5443f05d9 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java
@@ -127,16 +127,16 @@ public class CommandHelper {
         return true;
     }
 
-    public static void setBlockEntity(WorldSource world, int x, int y, int z, CompoundTag tag) {
-        if (tag == null || world.getBlockEntity(x, y, z) == null) return;
+    public static void setTileEntity(WorldSource world, int x, int y, int z, CompoundTag tag) {
+        if (tag == null || world.getTileEntity(x, y, z) == null) return;
         tag.putInt("x", x);
         tag.putInt("y", y);
         tag.putInt("z", z);
-        world.getBlockEntity(x, y, z).readFromNBT(tag);
+        world.getTileEntity(x, y, z).readFromNBT(tag);
     }
 
-    public static void setBlockEntity(WorldSource world, int x, int y, int z, TileEntity tileEntity) {
-        setBlockEntity(world, x, y, z, tagFrom(tileEntity));
+    public static void setTileEntity(WorldSource world, int x, int y, int z, TileEntity tileEntity) {
+        setTileEntity(world, x, y, z, tagFrom(tileEntity));
     }
 
     public static CompoundTag tagFrom(TileEntity tileEntity) {
diff --git a/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryMinecart.java b/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryMinecart.java
index 0493cf1ad..af61ec3ff 100644
--- a/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryMinecart.java
+++ b/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryMinecart.java
@@ -2,7 +2,7 @@ package net.minecraft.core.net.entity.entries;
 
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.entity.vehicle.MinecartEntity;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.net.entity.EntityTracker;
 import net.minecraft.core.net.entity.EntityTrackerEntry;
 import net.minecraft.core.net.entity.ITrackedEntry;
@@ -12,10 +12,10 @@ import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class NetEntryMinecart implements IVehicleEntry<MinecartEntity>, ITrackedEntry<MinecartEntity> {
+public class NetEntryMinecart implements IVehicleEntry<EntityMinecart>, ITrackedEntry<EntityMinecart> {
     @Override
-    public @NotNull Class<MinecartEntity> getAppliedClass() {
-        return MinecartEntity.class;
+    public @NotNull Class<EntityMinecart> getAppliedClass() {
+        return EntityMinecart.class;
     }
 
     @Override
@@ -34,17 +34,23 @@ public class NetEntryMinecart implements IVehicleEntry<MinecartEntity>, ITracked
     }
 
     @Override
-    public void onEntityTracked(EntityTracker tracker, EntityTrackerEntry trackerEntry, MinecartEntity trackedObject) {
+    public void onEntityTracked(EntityTracker tracker, EntityTrackerEntry trackerEntry, EntityMinecart trackedObject) {
 
     }
 
     @Override
     public Entity getEntity(World world, double x, double y, double z, int metadata, boolean hasVelocity, double xd, double yd, double zd, Entity owner, @Nullable CompoundTag tag) {
-        return new MinecartEntity(world, x, y, z, metadata);
+        EntityMinecart minecartEntity = new EntityMinecart(world, x, y, z, metadata);
+        minecartEntity.setMeta(tag.getInteger("meta"));
+        minecartEntity.setFuel(tag.getShort("fuel"));
+        return minecartEntity;
     }
 
     @Override
-    public PacketAddEntity getSpawnPacket(EntityTrackerEntry tracker, MinecartEntity trackedObject) {
-        return new PacketAddEntity(trackedObject, trackedObject.type);
+    public PacketAddEntity getSpawnPacket(EntityTrackerEntry tracker, EntityMinecart trackedObject) {
+        CompoundTag extrasTag = new CompoundTag();
+        extrasTag.putInt("meta", trackedObject.getMeta());
+        extrasTag.putShort("fuel", trackedObject.getFuel());
+        return new PacketAddEntity(trackedObject, trackedObject.getType(), -1, null, null, null, extrasTag);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java b/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
index 8573791af..4ee257f4c 100644
--- a/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
+++ b/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
@@ -33,6 +33,11 @@ public abstract class PacketHandler
         handleInvalidPacket(loginPacket);
     }
 
+    public void handlePlayerConfig(PacketPlayerConfig packetPlayerConfig)
+    {
+        handleInvalidPacket(packetPlayerConfig);
+    }
+
     public void handleFlying(PacketMovePlayer movePlayerPacket)
     {
         handleInvalidPacket(movePlayerPacket);
@@ -208,9 +213,9 @@ public abstract class PacketHandler
         handleInvalidPacket(containerClickPacket);
     }
 
-    public void handleTileEntityData(PacketBlockEntityData blockEntityDataPacket)
+    public void handleTileEntityData(PacketTileEntityData packetTileEntityData)
     {
-        handleInvalidPacket(blockEntityDataPacket);
+        handleInvalidPacket(packetTileEntityData);
     }
 
     public void handleSetSlot(PacketContainerSetSlot containerSetslotPacket)
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java b/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java
index 5fd4d72c0..f72654a17 100644
--- a/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java
+++ b/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java
@@ -285,6 +285,7 @@ public abstract class Packet
         addMapping(33, true, false, PacketMoveEntity.PosRot.class);
         addMapping(34, true, false, PacketTeleportEntity.class);
         addMapping(35, true, true, PacketEntityNickname.class);
+        addMapping(36, true, true, PacketPlayerConfig.class);
         addMapping(38, true, false, PacketEntityEvent.class);
         addMapping(39, true, false, PacketSetRiding.class);
         addMapping(40, true, false, PacketSetEntityData.class);
@@ -324,7 +325,7 @@ public abstract class Packet
         addMapping(137, false, true, PacketSetItemName.class);
         addMapping(138, true, false, PacketPlayerList.class);
         addMapping(139, false, true, PacketSetPaintingArt.class);
-        addMapping(140, true, false, PacketBlockEntityData.class);
+        addMapping(140, true, false, PacketTileEntityData.class);
         addMapping(142, true, false, PacketFlagOpen.class);
         addMapping(143, true, false, PacketPhotoMode.class);
         addMapping(200, true, false, PacketStatistic.class);
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketAddPlayer.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketAddPlayer.java
index 600b8f0be..e1d2d31d4 100644
--- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketAddPlayer.java
+++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketAddPlayer.java
@@ -31,6 +31,7 @@ public class PacketAddPlayer extends Packet
         currentItem = itemstack != null ? itemstack.itemID : 0;
         nickname = entityplayer.getDisplayName();
         chatColor = entityplayer.chatColor;
+        playerConfig = entityplayer.playerConfig.config;
         if (entityplayer.getHeldObject() == null) {
             heldObjectTag = null;
         } else {
@@ -55,6 +56,7 @@ public class PacketAddPlayer extends Packet
         currentItem = dis.readShort();
         nickname = readString(dis, MAX_NICKNAME_SIZE);
         chatColor = dis.readByte();
+        playerConfig = dis.readByte();
 
         if (dis.readByte() == 1) {
             heldObjectTag = readCompressedCompoundTag(dis);
@@ -78,6 +80,7 @@ public class PacketAddPlayer extends Packet
         dos.writeShort(currentItem);
         writeString(nickname, dos);
         dos.writeByte(chatColor);
+        dos.writeByte(playerConfig);
 
         if (heldObjectTag != null) {
             dos.writeByte(1);
@@ -111,4 +114,5 @@ public class PacketAddPlayer extends Packet
     public @Nullable CompoundTag heldObjectTag;
     public String nickname;
     public byte chatColor;
+    public byte playerConfig;
 }
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketPlayerConfig.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketPlayerConfig.java
new file mode 100644
index 000000000..bd5ea3cc2
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketPlayerConfig.java
@@ -0,0 +1,43 @@
+package net.minecraft.core.net.packet;
+
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.net.handler.PacketHandler;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class PacketPlayerConfig extends Packet {
+    public int entityId;
+    public byte config;
+    public PacketPlayerConfig() {}
+    public PacketPlayerConfig(Player.PlayerConfig config) {
+        this.entityId = -1;
+        this.config = config.config;
+    }
+    public PacketPlayerConfig(int entityId, Player.PlayerConfig config) {
+        this.entityId = entityId;
+        this.config = config.config;
+    }
+    @Override
+    public void read(DataInputStream dis) throws IOException {
+        entityId = dis.readInt();
+        config = dis.readByte();
+    }
+
+    @Override
+    public void write(DataOutputStream dos) throws IOException {
+        dos.writeInt(entityId);
+        dos.writeByte(config);
+    }
+
+    @Override
+    public void handlePacket(PacketHandler packetHandler) {
+        packetHandler.handlePlayerConfig(this);
+    }
+
+    @Override
+    public int getEstimatedSize() {
+        return 5;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketBlockEntityData.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketTileEntityData.java
similarity index 84%
rename from game/core/src/main/java/net/minecraft/core/net/packet/PacketBlockEntityData.java
rename to game/core/src/main/java/net/minecraft/core/net/packet/PacketTileEntityData.java
index 2c388caa0..1338b2d9d 100644
--- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketBlockEntityData.java
+++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketTileEntityData.java
@@ -6,17 +6,17 @@ import net.minecraft.core.net.handler.PacketHandler;
 
 import java.io.*;
 
-public class PacketBlockEntityData
+public class PacketTileEntityData
     extends Packet
 {
     public CompoundTag tag;
 
-    public PacketBlockEntityData()
+    public PacketTileEntityData()
     {
         isChunkDataPacket = true;
     }
 
-    public PacketBlockEntityData(TileEntity tileEntity)
+    public PacketTileEntityData(TileEntity tileEntity)
     {
         this();
 
@@ -24,7 +24,7 @@ public class PacketBlockEntityData
         tileEntity.writeToNBT(tag);
     }
 
-    public PacketBlockEntityData(CompoundTag tag) {
+    public PacketTileEntityData(CompoundTag tag) {
         this.tag = tag;
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuFurnace.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuFurnace.java
index f665658e9..c31ffea49 100644
--- a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuFurnace.java
+++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuFurnace.java
@@ -22,15 +22,15 @@ public class MenuFurnace extends MenuAbstract {
 	private int itemBurnTime;
 	private int itemCookTime;
 
-	public MenuFurnace(ContainerInventory inventory, TileEntityFurnace blockEntity) {
+	public MenuFurnace(ContainerInventory inventory, TileEntityFurnace tileEntity) {
 		currentCookTime = 0;
 		currentBurnTime = 0;
 		itemCookTime = 0;
 		itemBurnTime = 0;
-		furnace = blockEntity;
-		addSlot(new Slot(blockEntity, 0, 56, 17));
-		addSlot(new Slot(blockEntity, 1, 56, 53));
-		addSlot(new SlotFurnace(inventory.player, blockEntity, 2, 116, 35));
+		furnace = tileEntity;
+		addSlot(new Slot(tileEntity, 0, 56, 17));
+		addSlot(new Slot(tileEntity, 1, 56, 53));
+		addSlot(new SlotFurnace(inventory.player, tileEntity, 2, 116, 35));
 		for (int i = 0; i < 3; i++) {
 			for (int k = 0; k < 9; k++) {
 				addSlot(new Slot(inventory, k + i * 9 + 9, 8 + k * 18, 84 + i * 18));
diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java
index aaf3943fa..0ac46ab45 100644
--- a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java
+++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java
@@ -83,7 +83,7 @@ public class MenuInventoryCreative extends MenuInventory
 		
 		for (int i = 0; i < creativeItemsCount; i++)
 		{
-			if (t.translateNameKey(creativeItems.get(i).getItemKey()).toLowerCase().contains(search.toLowerCase()))
+			if (t.translateKey(creativeItems.get(i).getItemKey() + ".name").toLowerCase().contains(search.toLowerCase()))
 			{
 				searchedItems.add(creativeItems.get(i));
 			}
diff --git a/game/core/src/main/java/net/minecraft/core/util/collection/NamespaceID.java b/game/core/src/main/java/net/minecraft/core/util/collection/NamespaceID.java
index 5bd5de90d..89af7b7d0 100644
--- a/game/core/src/main/java/net/minecraft/core/util/collection/NamespaceID.java
+++ b/game/core/src/main/java/net/minecraft/core/util/collection/NamespaceID.java
@@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull;
 import java.util.Comparator;
 
 public final class NamespaceID implements Comparator<NamespaceID>, Comparable<NamespaceID> {
+    public static final String DEFAULT_NAMESPACE = "minecraft";
     public final String namespace;
     public final String value;
     public NamespaceID(String namespace, String value) throws IllegalArgumentException {
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 f1df137a7..fb71c4755 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
@@ -60,12 +60,12 @@ public class BlocksContainer implements WorldSource {
     }
 
     @Override
-    public TileEntity getBlockEntity(int x, int y, int z) {
+    public TileEntity getTileEntity(int x, int y, int z) {
         ChunkCoordinates c = new ChunkCoordinates(x, y, z);
         if (blockEntryMap.containsKey(c)){
             return blockEntryMap.get(c).tileEntity;
         }
-        return world.getBlockEntity(x, y, z);
+        return world.getTileEntity(x, y, z);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/Dimension.java b/game/core/src/main/java/net/minecraft/core/world/Dimension.java
index c74e693f4..22450e328 100644
--- a/game/core/src/main/java/net/minecraft/core/world/Dimension.java
+++ b/game/core/src/main/java/net/minecraft/core/world/Dimension.java
@@ -67,7 +67,7 @@ public class Dimension
 	
 	public String getTranslatedName()
 	{
-		return I18n.getInstance().translateNameKey("dimension." + languageKey);
+		return I18n.getInstance().translateKey("dimension." + languageKey + ".name");
 	}
 	
 	@Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/Explosion.java b/game/core/src/main/java/net/minecraft/core/world/Explosion.java
index efc1b3041..ebafd28f2 100644
--- a/game/core/src/main/java/net/minecraft/core/world/Explosion.java
+++ b/game/core/src/main/java/net/minecraft/core/world/Explosion.java
@@ -65,7 +65,7 @@ public class Explosion {
             int z = chunkposition.z;
             
             int id = worldObj.getBlockId(x, y, z);
-            TileEntity tileEntity = worldObj.getBlockEntity(x, y, z);
+            TileEntity tileEntity = worldObj.getTileEntity(x, y, z);
             if(particles) {
                 double xPos = (double) x + worldObj.rand.nextFloat();
                 double yPos = (double) y + worldObj.rand.nextFloat();
diff --git a/game/core/src/main/java/net/minecraft/core/world/ExplosionCannonball.java b/game/core/src/main/java/net/minecraft/core/world/ExplosionCannonball.java
index 4f9258d3f..d6982dd7b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/ExplosionCannonball.java
+++ b/game/core/src/main/java/net/minecraft/core/world/ExplosionCannonball.java
@@ -144,7 +144,7 @@ public class ExplosionCannonball extends Explosion{
             int y = chunkposition.y;
             int z = chunkposition.z;
             Block<?> block = worldObj.getBlock(x, y, z);
-            TileEntity tileEntity = worldObj.getBlockEntity(x, y, z);
+            TileEntity tileEntity = worldObj.getTileEntity(x, y, z);
             if(flag)
             {
                 double d = (double)x + worldObj.rand.nextFloat();
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 4f0b272f8..0f3e03456 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
@@ -63,6 +63,7 @@ import net.minecraft.core.world.saveddata.SavedData;
 import net.minecraft.core.world.saveddata.SavedDataStorage;
 import net.minecraft.core.world.season.SeasonManager;
 import net.minecraft.core.world.type.WorldType;
+import net.minecraft.core.world.weather.IPrecipitation;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.WeatherManager;
 import net.minecraft.core.world.weather.Weathers;
@@ -206,7 +207,6 @@ public class World implements WorldSource {
                 dimensionData.getCurrentWeather(),
                 dimensionData.getNextWeather(),
                 dimensionData.getWeatherDuration(),
-                dimensionData.getWeatherIntensity(),
                 dimensionData.getWeatherPower()
             );
         }
@@ -250,7 +250,6 @@ public class World implements WorldSource {
                 dimensionData.getCurrentWeather(),
                 dimensionData.getNextWeather(),
                 dimensionData.getWeatherDuration(),
-                dimensionData.getWeatherIntensity(),
                 dimensionData.getWeatherPower()
             );
         }
@@ -1769,7 +1768,7 @@ public class World implements WorldSource {
                 loadedTileEntityList.remove(i);
                 Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(tileEntity.x, Chunk.CHUNK_SIZE_X), Math.floorDiv(tileEntity.z, Chunk.CHUNK_SIZE_Z));
                 if (chunk != null) {
-                    chunk.removeBlockEntity(tileEntity);
+                    chunk.removeTileEntity(tileEntity);
                 }
             }
         }
@@ -2136,26 +2135,26 @@ public class World implements WorldSource {
     }
 
     @Override
-    public TileEntity getBlockEntity(int x, int y, int z)
+    public TileEntity getTileEntity(int x, int y, int z)
     {
         Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
         if(chunk != null)
         {
-            return chunk.getBlockEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
+            return chunk.getTileEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
         } else
         {
             return null;
         }
     }
 
-    public void setBlockTileEntity(int x, int y, int z, TileEntity tileEntity)
+    public void setTileEntity(int x, int y, int z, TileEntity tileEntity)
     {
         if(!tileEntity.isInvalid())
         {
             Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
             if(chunk != null)
             {
-                if (chunk.setBlockEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), tileEntity) && !loadedTileEntityList.contains(tileEntity)) {
+                if (chunk.setTileEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), tileEntity) && !loadedTileEntityList.contains(tileEntity)) {
                     loadedTileEntityList.add(tileEntity);
                 }
             }
@@ -2164,7 +2163,7 @@ public class World implements WorldSource {
 
     public void removeBlockTileEntity(int x, int y, int z)
     {
-        TileEntity tileEntity = getBlockEntity(x, y, z);
+        TileEntity tileEntity = getTileEntity(x, y, z);
 
         if(tileEntity != null && updatingBlockEntities)
         {
@@ -2178,14 +2177,14 @@ public class World implements WorldSource {
             Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
             if(chunk != null)
             {
-                chunk.removeBlockEntity(tileEntity);
+                chunk.removeTileEntity(tileEntity);
             }
         }
     }
 
     public void replaceBlockTileEntity(int x, int y, int z, TileEntity tileEntity) {
         removeBlockTileEntity(x, y, z);
-        setBlockTileEntity(x, y, z, tileEntity);
+        setTileEntity(x, y, z, tileEntity);
     }
 
     @Override
@@ -2603,7 +2602,7 @@ public class World implements WorldSource {
         return loadedEntityList;
     }
 
-    public List<TileEntity> getLoadedBlockEntityList()
+    public List<TileEntity> getLoadedTileEntityList()
     {
         return loadedTileEntityList;
     }
@@ -3103,7 +3102,8 @@ public class World implements WorldSource {
                 entityplayer.wakeUpPlayer(false, false);
             }
         }
-        if (getCurrentWeather() != null && getCurrentWeather().spawnRainParticles)
+        final @Nullable Weather currentWeather = getCurrentWeather();
+        if (currentWeather instanceof IPrecipitation && ((IPrecipitation) currentWeather).spawnRainParticles())
         {
             weatherManager.overrideWeather(worldType.getDefaultWeather());
         }
@@ -3127,7 +3127,7 @@ public class World implements WorldSource {
         {
             return false;
         }
-        if (!getCurrentWeather().isPrecipitation)
+        if (!(getCurrentWeather() instanceof IPrecipitation))
         {
             return false;
         }
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 6c036563b..6c4507283 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
@@ -15,7 +15,7 @@ public interface WorldSource
 
     @Nullable Block<?> getBlock(int x, int y, int z);
 
-    TileEntity getBlockEntity(int x, int y, int z);
+    TileEntity getTileEntity(int x, int y, int z);
 
     float getBrightness(int x, int y, int z, int blockLightValue);
     
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 fcf6285b9..b0f0fa846 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
@@ -30,7 +30,7 @@ public class Chunk
     public int lowestY;
     public final int xPosition;
     public final int zPosition;
-    public Map<ChunkPosition, TileEntity> blockEntityMap;
+    public Map<ChunkPosition, TileEntity> tileEntityMap;
     public double[] temperature;
     public double[] humidity;
     public double[] variety;
@@ -44,7 +44,7 @@ public class Chunk
 
     public Chunk(World world, int x, int z)
     {
-        blockEntityMap = new HashMap<>();
+        tileEntityMap = new HashMap<>();
         isTerrainPopulated = false;
         isModified = false;
         hasEntities = false;
@@ -489,10 +489,10 @@ public class Chunk
         return y >= getHeightValue(x, z);
     }
 
-    public TileEntity getBlockEntity(int x, int y, int z)
+    public TileEntity getTileEntity(int x, int y, int z)
     {
         ChunkPosition pos = new ChunkPosition(x, y, z);
-        TileEntity tileEntity = blockEntityMap.get(pos);
+        TileEntity tileEntity = tileEntityMap.get(pos);
         if(tileEntity == null)
         {
             Block<?> block = Blocks.getBlock(getBlockID(x, y, z));
@@ -501,11 +501,11 @@ public class Chunk
                 return null;
             }
             block.onBlockPlacedByWorld(world, xPosition * CHUNK_SIZE_X + x, y, zPosition * CHUNK_SIZE_Z + z);
-            tileEntity = blockEntityMap.get(pos);
+            tileEntity = tileEntityMap.get(pos);
         }
         if(tileEntity != null && tileEntity.isInvalid())
         {
-            blockEntityMap.remove(pos);
+            tileEntityMap.remove(pos);
             return null;
         }
         else
@@ -514,12 +514,12 @@ public class Chunk
         }
     }
 
-    public void addBlockEntity(TileEntity tileEntity)
+    public void addTileEntity(TileEntity tileEntity)
     {
         int x = tileEntity.x - xPosition * CHUNK_SIZE_X;
         int y = tileEntity.y;
         int z = tileEntity.z - zPosition * CHUNK_SIZE_Z;
-        setBlockEntity(x, y, z, tileEntity);
+        setTileEntity(x, y, z, tileEntity);
         if(isLoaded)
         {
             world.loadedTileEntityList.add(tileEntity);
@@ -529,7 +529,7 @@ public class Chunk
     /**
      * @return True if the specified block entity was set
      */
-    public boolean setBlockEntity(int x, int y, int z, TileEntity tileEntity)
+    public boolean setTileEntity(int x, int y, int z, TileEntity tileEntity)
     {
         ChunkPosition chunkposition = new ChunkPosition(x, y, z);
         tileEntity.worldObj = world;
@@ -545,7 +545,7 @@ public class Chunk
         else
         {
             tileEntity.validate();
-            TileEntity previous = blockEntityMap.put(chunkposition, tileEntity);
+            TileEntity previous = tileEntityMap.put(chunkposition, tileEntity);
             if (previous != null) {
                 previous.invalidate();
             }
@@ -554,12 +554,12 @@ public class Chunk
         return false;
     }
 
-    public void removeBlockEntity(int x, int y, int z)
+    public void removeTileEntity(int x, int y, int z)
     {
         ChunkPosition pos = new ChunkPosition(x, y, z);
         if(isLoaded)
         {
-            TileEntity tileEntity = blockEntityMap.remove(pos);
+            TileEntity tileEntity = tileEntityMap.remove(pos);
             if(tileEntity != null)
             {
                 tileEntity.invalidate();
@@ -567,9 +567,9 @@ public class Chunk
         }
     }
 
-    public void removeBlockEntity(TileEntity tileEntity) {
-        if (isLoaded && tileEntity != null && blockEntityMap.containsValue(tileEntity)) {
-            blockEntityMap.remove(new ChunkPosition(tileEntity.x & (Chunk.CHUNK_SIZE_X - 1), tileEntity.y, tileEntity.z & (Chunk.CHUNK_SIZE_Z - 1)));
+    public void removeTileEntity(TileEntity tileEntity) {
+        if (isLoaded && tileEntity != null && tileEntityMap.containsValue(tileEntity)) {
+            tileEntityMap.remove(new ChunkPosition(tileEntity.x & (Chunk.CHUNK_SIZE_X - 1), tileEntity.y, tileEntity.z & (Chunk.CHUNK_SIZE_Z - 1)));
             tileEntity.invalidate();
         }
     }
@@ -577,7 +577,7 @@ public class Chunk
     public void onLoad()
     {
         isLoaded = true;
-        world.addAllBlockEntities(blockEntityMap.values());
+        world.addAllBlockEntities(tileEntityMap.values());
 
         for (ChunkSection section : sections) {
             section.onLoad(world);
@@ -588,7 +588,7 @@ public class Chunk
     {
         isLoaded = false;
         TileEntity tileentity;
-        for(Iterator<TileEntity> iterator = blockEntityMap.values().iterator(); iterator.hasNext(); tileentity.invalidate())
+        for(Iterator<TileEntity> iterator = tileEntityMap.values().iterator(); iterator.hasNext(); tileentity.invalidate())
         {
             tileentity = iterator.next();
         }
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 c2bc4d8d7..178a006c3 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
@@ -71,11 +71,11 @@ public class ChunkCache
     }
 
     @Override
-	public TileEntity getBlockEntity(int x, int y, int z)
+	public TileEntity getTileEntity(int x, int y, int z)
     {
         int l = Math.floorDiv(x, Chunk.CHUNK_SIZE_X) - chunkX;
         int i1 = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z) - chunkZ;
-        return chunkArray[l][i1].getBlockEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
+        return chunkArray[l][i1].getTileEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
     }
 
     public boolean getBlockLitInteriorSurface(int x, int y, int z)
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 8069fefad..e78616393 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
@@ -206,7 +206,7 @@ public class ChunkLoaderLegacy
         // Write tile entities
         ListTag tileEntityListTag = new ListTag();
         CompoundTag tileEntityTag;
-        for (TileEntity tileEntity : chunk.blockEntityMap.values())
+        for (TileEntity tileEntity : chunk.tileEntityMap.values())
         {
             tileEntityTag = new CompoundTag();
             tileEntity.writeToNBT(tileEntityTag);
@@ -307,7 +307,7 @@ public class ChunkLoaderLegacy
                     TileEntity tileEntity = TileEntityDispatcher.createAndLoadEntity(tileEntityTag);
                     if (tileEntity != null)
                     {
-                        chunk.addBlockEntity(tileEntity);
+                        chunk.addTileEntity(tileEntity);
                     }
                 }
             }
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 e0eea2729..977789001 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
@@ -36,7 +36,7 @@ public class DisplayChunk extends EmptyChunk{
         return 15;
     }
     @Override
-    public boolean setBlockEntity(int x, int y, int z, TileEntity tileEntity)
+    public boolean setTileEntity(int x, int y, int z, TileEntity tileEntity)
     {
         if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
             displayTileEntity = tileEntity;
@@ -49,14 +49,14 @@ public class DisplayChunk extends EmptyChunk{
     }
 
     @Override
-    public void removeBlockEntity(int x, int y, int z)
+    public void removeTileEntity(int x, int y, int z)
     {
         if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
             displayTileEntity = null;
         }
     }
     @Override
-    public TileEntity getBlockEntity(int x, int y, int z)
+    public TileEntity getTileEntity(int x, int y, int z)
     {
         if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
             return displayTileEntity;
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 1481d1491..c1aa0b772 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
@@ -116,24 +116,24 @@ public class EmptyChunk extends Chunk
     }
 
     @Override
-	public TileEntity getBlockEntity(int x, int y, int z)
+	public TileEntity getTileEntity(int x, int y, int z)
     {
         return null;
     }
 
     @Override
-	public void addBlockEntity(TileEntity tileEntity)
+	public void addTileEntity(TileEntity tileEntity)
     {
     }
 
     @Override
-	public boolean setBlockEntity(int x, int y, int z, TileEntity tileEntity)
+	public boolean setTileEntity(int x, int y, int z, TileEntity tileEntity)
     {
         return false;
     }
 
     @Override
-	public void removeBlockEntity(int x, int y, int z)
+	public void removeTileEntity(int x, int y, int z)
     {
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java
index 8ff58e0fb..28d803342 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java
@@ -21,7 +21,7 @@ public class ChunkDecoratorSkyblock
         }
         if (contains(chunk, 4, -3)) {
             chunk.setBlockIDWithMetadata(4 & (Chunk.CHUNK_SIZE_X - 1), 67, -3 & (Chunk.CHUNK_SIZE_Z - 1), Blocks.CHEST_PLANKS_OAK.id(), 3);
-            TileEntity tileEntity = chunk.getBlockEntity(4 & (Chunk.CHUNK_SIZE_X - 1), 67, -3 & (Chunk.CHUNK_SIZE_Z - 1));
+            TileEntity tileEntity = chunk.getTileEntity(4 & (Chunk.CHUNK_SIZE_X - 1), 67, -3 & (Chunk.CHUNK_SIZE_Z - 1));
             if (tileEntity instanceof TileEntityChest) {
                 TileEntityChest chestEntity = (TileEntityChest) tileEntity;
                 chestEntity.setItem(0, new ItemStack(Items.BUCKET_LAVA, 1));
@@ -32,7 +32,7 @@ public class ChunkDecoratorSkyblock
         // Desert island
         if (contains(chunk, -67, 0)) {
             chunk.setBlockIDWithMetadata(-67 & (Chunk.CHUNK_SIZE_X - 1), 67, 0 & (Chunk.CHUNK_SIZE_Z - 1), Blocks.CHEST_PLANKS_OAK.id(), 1);
-            TileEntity tileEntity = chunk.getBlockEntity(-67 & (Chunk.CHUNK_SIZE_X - 1), 67, 0 & (Chunk.CHUNK_SIZE_Z - 1));
+            TileEntity tileEntity = chunk.getTileEntity(-67 & (Chunk.CHUNK_SIZE_X - 1), 67, 0 & (Chunk.CHUNK_SIZE_Z - 1));
             if (tileEntity instanceof TileEntityChest) {
                 TileEntityChest chestEntity = (TileEntityChest) tileEntity;
                 chestEntity.setItem(0, new ItemStack(Blocks.OBSIDIAN, 14));
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblockNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblockNether.java
index a457e4a81..465c27272 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblockNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblockNether.java
@@ -24,7 +24,7 @@ public class ChunkDecoratorSkyblockNether
         // Chest
         if (contains(chunk, 1, -1)) {
             chunk.setBlockIDWithMetadata(1 & (Chunk.CHUNK_SIZE_X - 1), 66, -1 & (Chunk.CHUNK_SIZE_Z - 1), Blocks.CHEST_PLANKS_OAK.id(), 3);
-            TileEntity tileEntity = chunk.getBlockEntity(1 & (Chunk.CHUNK_SIZE_X - 1), 66, -1 & (Chunk.CHUNK_SIZE_Z - 1));
+            TileEntity tileEntity = chunk.getTileEntity(1 & (Chunk.CHUNK_SIZE_X - 1), 66, -1 & (Chunk.CHUNK_SIZE_Z - 1));
             if (tileEntity != null) {
                 TileEntityChest tileEntityChest = (TileEntityChest) tileEntity;
                 tileEntityChest.setItem(0, new ItemStack(Blocks.SAPLING_BIRCH, 1));
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureDungeon.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureDungeon.java
index 9f665a455..4c7dcd01f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureDungeon.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureDungeon.java
@@ -157,7 +157,7 @@ public class WorldFeatureDungeon extends WorldFeature
                 }
                 world.setBlockWithNotify(k3, l3, i4, Blocks.CHEST_PLANKS_OAK.id());
                 BlockLogicChest.setDefaultDirection(world, k3, l3, i4);
-                TileEntityChest tileentitychest = (TileEntityChest)world.getBlockEntity(k3, l3, i4);
+                TileEntityChest tileentitychest = (TileEntityChest)world.getTileEntity(k3, l3, i4);
                 int k4 = 0;
                 do
                 {
@@ -177,7 +177,7 @@ public class WorldFeatureDungeon extends WorldFeature
         }
 
         world.setBlockWithNotify(x, y, z, Blocks.MOBSPAWNER.id());
-        TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner)world.getBlockEntity(x, y, z);
+        TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner)world.getTileEntity(x, y, z);
         tileentitymobspawner.setMobId(pickMobSpawner(random));
         return true;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java
index 7fedd3a98..407b76883 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java
@@ -7,7 +7,10 @@ import net.minecraft.core.block.BlockLogicRotatable;
 import net.minecraft.core.block.entity.TileEntityChest;
 import net.minecraft.core.block.entity.TileEntityDispenser;
 import net.minecraft.core.block.entity.TileEntityMobSpawner;
+import net.minecraft.core.block.entity.TileEntityStatue;
 import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.enums.HumanArmorShape;
+import net.minecraft.core.item.IArmorItem;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
@@ -16,14 +19,12 @@ import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.world.biome.Biomes;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
 public class WorldFeatureLabyrinth extends WorldFeature
 {
-    public WorldFeatureLabyrinth()
-    {
-    }
     int dungeonSize = 0;
     int dungeonLimit;
     int dungeonCount = 0;
@@ -39,6 +40,14 @@ public class WorldFeatureLabyrinth extends WorldFeature
     public WeightedRandomBag<WeightedRandomLootObject> chestLoot;
     public WeightedRandomBag<WeightedRandomLootObject> dispenserLoot;
     public WeightedRandomBag<String> spawnerMonsters;
+
+    private int @Nullable[] platformPos = null;
+    private int @Nullable[] lastDungeon = null;
+
+    public WorldFeatureLabyrinth()
+    {
+    }
+
     @Override
     public boolean place(World world, Random random, int x, int y, int z)
     {
@@ -112,6 +121,12 @@ public class WorldFeatureLabyrinth extends WorldFeature
         if(canReplace(world, x, y, z)) {
             dungeonLimit = 1;
             generateBranch(world, random, x, y, z);
+            if (!treasureGenerated && lastDungeon != null) {
+                generateTrophyRoom(world, random, lastDungeon[1], lastDungeon[2], lastDungeon[3], lastDungeon[0]);
+            }
+            if (platformPos != null) {
+                generateStatue(world, platformPos[0], platformPos[1], platformPos[2], platformPos[3]);
+            }
             return true;
         }
         return false;
@@ -146,7 +161,7 @@ public class WorldFeatureLabyrinth extends WorldFeature
                                 BlockLogicRotatable.setDefaultDirection(world, x, y, z);
                                 world.setBlockWithNotify(x, y - 1, z, Blocks.DISPENSER_COBBLE_STONE.id());
                                 BlockLogicRotatable.setDefaultDirection(world, x, y - 1, z);
-                                TileEntityDispenser tileEntityDispenser = (TileEntityDispenser) world.getBlockEntity(x, blockY - 1, z);
+                                TileEntityDispenser tileEntityDispenser = (TileEntityDispenser) world.getTileEntity(x, blockY - 1, z);
                                 int k4 = 0;
                                 while (k4 < 3) {
                                     ItemStack itemstack = pickDispenserLootItem(random);
@@ -314,7 +329,7 @@ public class WorldFeatureLabyrinth extends WorldFeature
             else
                 generateDrop(world, random, blockX, blockY, blockZ);
         }
-        else if(random.nextInt(2) == 0 && corridorIteration > 1 && dungeonSize > 3 || (dungeonSize >= 10 && dungeonCount<dungeonLimit)) {
+        else if(random.nextInt(2) == 0 && corridorIteration > 1 && dungeonSize > 3 || (dungeonSize >= 10 && dungeonCount < dungeonLimit)) {
             createDungeon(world, random, blockX, blockY, blockZ, rot);
             dungeonCount++;
         }
@@ -375,7 +390,7 @@ public class WorldFeatureLabyrinth extends WorldFeature
         if(canReplace(world, chestX, blockY-2, chestZ)) {
             world.setBlockWithNotify(chestX, blockY - 1, chestZ, Blocks.CHEST_PLANKS_OAK.id());
             BlockLogicChest.setDefaultDirection(world, chestX, blockY - 1, chestZ);
-            TileEntityChest tileentitychest = (TileEntityChest) world.getBlockEntity(chestX, blockY - 1, chestZ);
+            TileEntityChest tileentitychest = (TileEntityChest) world.getTileEntity(chestX, blockY - 1, chestZ);
             int k4 = 0;
             while (k4 < 10) {
                 ItemStack itemstack = pickCheckLootItem(random);
@@ -388,7 +403,7 @@ public class WorldFeatureLabyrinth extends WorldFeature
         if (doSpawner)
         {
             world.setBlockWithNotify(blockX, blockY-1, blockZ, Blocks.MOBSPAWNER.id());
-            TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner)world.getBlockEntity(blockX, blockY-1, blockZ);
+            TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner)world.getTileEntity(blockX, blockY-1, blockZ);
             if(tileentitymobspawner != null)
                 tileentitymobspawner.setMobId(pickMobSpawner(random));
         }
@@ -465,6 +480,103 @@ public class WorldFeatureLabyrinth extends WorldFeature
 
     }
 
+    private void generateTrophyRoom(World world, Random random, int blockX, int blockY, int blockZ, int rot) {
+        int size = 8;
+//        int sideFacing = random.nextInt(2);
+        if (blockY < 10)
+            return;
+        for (int x = blockX - size; x <= blockX + size; x++) {
+            for (int y = blockY - 2; y <= blockY + 6; y++) {
+                for (int z = blockZ - size; z <= blockZ + size; z++) {
+                    int xRoom = x - blockX + size;
+                    int zRoom = z - blockZ + size;
+                    boolean xWallCheck = x == blockX - size || x == blockX + size;
+                    boolean zWallCheck = z == blockZ - size || z == blockZ + size;
+                    boolean yWallCheck = y == blockY - 2;
+                    if (canReplace(world, x, y, z)) {
+                        if (xWallCheck) {
+                            if (zRoom % 4 != 0) {
+                                world.setBlockWithNotify(x, y, z, wallBlockB);
+                            } else world.setBlockWithNotify(x, y, z, brickBlockA);
+                        }
+                        else if (zWallCheck) {
+                            if (xRoom % 4 != 0) {
+                                world.setBlockWithNotify(x, y, z, wallBlockB);
+                            } else world.setBlockWithNotify(x, y, z, brickBlockA);
+                        }
+                        else if (yWallCheck) {
+                            if ((x > blockX - 2 && x < blockX + 2) || (z > blockZ - 2 && z < blockZ + 2))
+                                if (x == blockX || z == blockZ) {
+                                    world.setBlockWithNotify(x, y, z, isCold ? Blocks.OBSIDIAN.id() : Blocks.FLUID_LAVA_FLOWING.id());
+                                } else {
+                                    world.setBlockWithNotify(x, y, z, isCold ? Blocks.PERMAFROST_POLISHED.id() : Blocks.STONE_POLISHED.id());
+                                }
+                            else if (random.nextInt(5) == 0)
+                                world.setBlockWithNotify(x, y, z, wallBlockB);
+                            else
+                                world.setBlockWithNotify(x, y, z, wallBlockA);
+                            if (x > blockX - 3 && x < blockX + 3 && z > blockZ - 3 && z < blockZ + 3)
+                                world.setBlockWithNotify(x, y, z, wallBlockB);
+                        } else if (y == blockY + 6) {
+                            if (random.nextInt(5) == 0)
+                                world.setBlockWithNotify(x, y, z, wallBlockB);
+                            else
+                                world.setBlockWithNotify(x, y, z, wallBlockA);
+                        } else if (x > blockX - size && x < blockX + size || z > blockZ - size && z < blockX + size) {
+                                world.setBlockWithNotify(x, y, z, 0);
+                        } else
+                            world.setBlockWithNotify(x, y, z, 0);
+                        if (zRoom % 2 == 0
+                            && (x == blockX - 2 || x == blockX + 2)
+                            && (z == blockZ - 2 || z == blockZ + 2)) {
+                            world.setBlockWithNotify(x, y, z, brickBlockA);
+                        }
+                    }
+                }
+            }
+        }
+
+        platformPos = new int[] { rot, blockX, blockY, blockZ };
+    }
+
+    private void generateStatue(World world, int rot, int blockX, int blockY, int blockZ) {
+        for (int x = blockX - 1; x <= blockX + 1; x++) {
+            for (int z = blockZ - 1; z <= blockZ + 1; z++) {
+                if (x == blockX && z == blockZ) {
+                    world.setBlockAndMetadataWithNotify(x, blockY - 1, z, isCold ? Blocks.SLAB_PERMAFROST_POLISHED.id() : Blocks.SLAB_STONE_POLISHED.id(), 1);
+                } else {
+                    world.setBlockWithNotify(x, blockY - 1, z, isCold ? Blocks.SLAB_PERMAFROST_POLISHED.id() : Blocks.SLAB_STONE_POLISHED.id());
+                }
+            }
+        }
+
+        int meta = 0;
+        switch (rot) {
+            case 0:
+                meta = 8;
+                break;
+            case 1:
+                meta = 12;
+                break;
+            case 2:
+                meta = 0;
+                break;
+            case 3:
+                meta = 4;
+                break;
+        }
+        world.setBlockAndMetadata(blockX, blockY, blockZ, Blocks.STATUE_PIGMAN_LOWER.id(), meta);
+        world.setBlockAndMetadata(blockX, blockY + 1, blockZ, Blocks.STATUE_PIGMAN_UPPER.id(), meta);
+        TileEntityStatue statue = (TileEntityStatue) world.getTileEntity(blockX, blockY, blockZ);
+        Item treasureItem = this.treasureItem.getItem();
+        if (treasureItem instanceof IArmorItem && ((IArmorItem<?>) treasureItem).getArmorShape() instanceof HumanArmorShape) {
+            statue.setItemInArmorSlot(((IArmorItem<HumanArmorShape>) treasureItem).getArmorShape(), this.treasureItem.copy());
+        } else {
+            statue.setHeldItem(this.treasureItem.copy());
+        }
+        statue.setPose(TileEntityStatue.Pose.LOOK_UP);
+    }
+
     private void createDungeon(World world, Random random, int blockX, int blockY, int blockZ, int rot)
     {
         int dx = 0, dz = 0;
@@ -487,7 +599,12 @@ public class WorldFeatureLabyrinth extends WorldFeature
 
         if (canReplace(world, blockX + dx * 5, blockY, blockZ + dz * 5))
         {
-            if (dungeonSize==10 && !libraryGenerated)
+            if (!treasureGenerated && dungeonSize == 10)
+            {
+                treasureGenerated = true;
+                generateTrophyRoom(world, random, blockX + dx * 4, blockY, blockZ + dz * 4, rot);
+            }
+            else if (!libraryGenerated && random.nextInt(3) == 0)
             {
                 libraryGenerated = true;
                 generateLibrary(world, random, blockX + dx * 4, blockY, blockZ + dz * 4);
@@ -495,6 +612,7 @@ public class WorldFeatureLabyrinth extends WorldFeature
             else
             {
                 generateDungeon(world, random, blockX + dx * 4, blockY, blockZ + dz * 4, true);
+                lastDungeon = new int[] { rot, blockX + dx * 4, blockY, blockZ + dx * 4 };
             }
         }
 
@@ -507,11 +625,6 @@ public class WorldFeatureLabyrinth extends WorldFeature
 
     private ItemStack pickCheckLootItem(Random random)
     {
-        if(!treasureGenerated && dungeonSize > 7)
-        {
-            treasureGenerated = true;
-            return treasureItem.copy();
-        }
         return chestLoot.getRandom(random).getItemStack(random);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/DimensionData.java b/game/core/src/main/java/net/minecraft/core/world/save/DimensionData.java
index 8bd87d572..9f2cd1e1d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/DimensionData.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/DimensionData.java
@@ -150,7 +150,7 @@ public class DimensionData
         if (weather == null) {
             this.weatherCurrentId = -1;
         } else {
-            this.weatherCurrentId = weather.weatherId;
+            this.weatherCurrentId = weather.getId();
         }
     }
 
@@ -168,7 +168,7 @@ public class DimensionData
         }
         else
         {
-            this.weatherNextId = weather.weatherId;
+            this.weatherNextId = weather.getId();
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/season/Season.java b/game/core/src/main/java/net/minecraft/core/world/season/Season.java
index a10430110..e05d357b8 100644
--- a/game/core/src/main/java/net/minecraft/core/world/season/Season.java
+++ b/game/core/src/main/java/net/minecraft/core/world/season/Season.java
@@ -43,7 +43,7 @@ public abstract class Season
 
 	public String getTranslatedName()
 	{
-		return I18n.getInstance().translateNameKey(languageKey);
+		return I18n.getInstance().translateKey(languageKey + ".name");
 	}
 	
 	public Season allowWeather(Weather weather, float probability)
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeEmpty.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeEmpty.java
index be6be9932..5636a9aae 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeEmpty.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeEmpty.java
@@ -68,7 +68,7 @@ public class WorldTypeEmpty
         float weatherOffset = 0;
         Weather currentWeather = world.getCurrentWeather();
         if (currentWeather != null)
-            weatherOffset = currentWeather.subtractLightLevel * world.weatherManager.getWeatherIntensity() * world.weatherManager.getWeatherPower();
+            weatherOffset = currentWeather.getLightLevelSubtracted() * world.weatherManager.getWeatherIntensity() * world.weatherManager.getWeatherPower();
         return (int) (f2 * (11F - weatherOffset) + weatherOffset);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
index 4d6fe1dc5..294fb8285 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
@@ -113,14 +113,14 @@ public abstract class WorldTypes {
                             .fillerBlock(Blocks.STONE)
                             .allowRespawn()
                             .bounds(0, 127, 64)
-                            .defaultWeather(Weathers.OVERWORLD_CLEAR_HELL)
+                            .defaultWeather(Weathers.OVERWORLD_HELL_CLEAR)
             )
     );
     public static final WorldType OVERWORLD_WOODS = register(
             "minecraft:overworld.woods",
             new WorldTypeOverworldWoods(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.woods")
-                            .defaultWeather(Weathers.OVERWORLD_CLEAR_WOODS)
+                            .defaultWeather(Weathers.OVERWORLD_WOODS_CLEAR)
             )
     );
     public static final WorldType OVERWORLD_PARADISE = register(
@@ -148,6 +148,7 @@ public abstract class WorldTypes {
                     WorldTypeOverworld.defaultProperties("worldType.overworld.classic")
                             .seasonConfig(null)
                             .bounds(0, 127, 64)
+                            .setRetro()
             )
     );
     public static final WorldType OVERWORLD_INDEV = register(
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
index 02e75163f..cb7050017 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
@@ -84,7 +84,7 @@ public class WorldTypeOverworld
         float weatherOffset = 0;
         Weather currentWeather = world.getCurrentWeather();
         if (currentWeather != null)
-            weatherOffset = currentWeather.subtractLightLevel * world.weatherManager.getWeatherIntensity() * world.weatherManager.getWeatherPower();
+            weatherOffset = currentWeather.getLightLevelSubtracted() * world.weatherManager.getWeatherIntensity() * world.weatherManager.getWeatherPower();
         return (int) (f2 * (11F - weatherOffset) + weatherOffset);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/paradise/WorldTypeParadise.java b/game/core/src/main/java/net/minecraft/core/world/type/paradise/WorldTypeParadise.java
index d966edec0..72c0684a7 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/paradise/WorldTypeParadise.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/paradise/WorldTypeParadise.java
@@ -87,7 +87,7 @@ public class WorldTypeParadise
         }
         float weatherOffset = 0;
         if (world.getCurrentWeather() != null)
-            weatherOffset = world.getCurrentWeather().subtractLightLevel * world.weatherManager.getWeatherIntensity() * world.weatherManager.getWeatherPower();
+            weatherOffset = world.getCurrentWeather().getLightLevelSubtracted() * world.weatherManager.getWeatherIntensity() * world.weatherManager.getWeatherPower();
         int subtracted = (int) (f2 * (11F - weatherOffset) + weatherOffset);
         if (subtracted > 8) subtracted = 8;
         return subtracted;
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/IPrecipitation.java b/game/core/src/main/java/net/minecraft/core/world/weather/IPrecipitation.java
new file mode 100644
index 000000000..b0da6c58d
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/IPrecipitation.java
@@ -0,0 +1,17 @@
+package net.minecraft.core.world.weather;
+
+import org.jetbrains.annotations.NotNull;
+
+public interface IPrecipitation {
+    enum Type {
+        RAIN_LIKE,
+        SNOW_LIKE,
+        INVERTED_RAIN_LIKE
+    }
+
+    @NotNull Type getPrecipitationType();
+
+    @NotNull String getPrecipitationTexturePath(final float power, final float intensity);
+
+    boolean spawnRainParticles();
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java b/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
index 97c6f6e9c..b35de9227 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
@@ -2,178 +2,122 @@ package net.minecraft.core.world.weather;
 
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
-import net.minecraft.core.lang.I18n;
 import net.minecraft.core.world.chunk.Chunk;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.PropertyKey;
 
 import java.util.Random;
 
-public abstract class Weather
-{
-	public int weatherId;
-	public String languageKey;
-	public boolean isPrecipitation = false;
-	private String texturePath = null;
-	public int subtractLightLevel = 0;
-	public int precipitationType = 0;
-	public boolean spawnRainParticles = false;
-	public boolean doMobsSpawnInDaylight = false;
-	public boolean isDamp = false;
-	public float fogDistance = 1.0f;
-	
-	public Weather(int id)
-	{
-		if(Weathers.WEATHERS[id] != null) throw new RuntimeException();
-		Weathers.WEATHERS[id] = this;
-		this.weatherId = id;
-	}
-	
-	public Weather setLanguageKey(String key)
-	{
-		languageKey = "weather." + key;
-		return this;
-	}
-	
-	public Weather setPrecipitation(String texturePath, int type)
-	{
-		this.isPrecipitation = true;
-		this.texturePath = texturePath;
-		this.precipitationType = type;
-		return this;
-	}
-	
-	public Weather setPrecipitationTexture(String texturePath)
-	{
-		this.texturePath = texturePath;
-		return this;
-	}
-
-	public String getPrecipitationTexture(World world)
-	{
-		return texturePath;
-	}
-	
-	public Weather setSubtractLightLevel(int subtractLightLevel)
-	{
-		this.subtractLightLevel = subtractLightLevel;
-		return this;
-	}
-	
-	public Weather setSpawnRainParticles(boolean spawnRainParticles)
-	{
-		this.spawnRainParticles = spawnRainParticles;
-		return this;
-	}
-	
-	public Weather setFogDistance(float f)
-	{
-		this.fogDistance = f;
-		return this;
-	}
-	
-	public Weather setMobsSpawnInDaylight()
-	{
-		doMobsSpawnInDaylight = true;
-		return this;
-	}
-
-	public Weather setDamp() {
-		isDamp = true;
-		return this;
-	}
-	
-	public String getTranslatedName()
-	{
-		return I18n.getInstance().translateKey(languageKey + ".name");
-	}
-	
-	public String getLanguageKey() {
-		return languageKey;
-	}
-	
-	public float[] modifyFogColor(float r, float g, float b, float intensity)
-	{
-		return new float[] { r, g, b };
-	}
-	
-	public void doEnvironmentUpdate(World world, Random rand, int x, int z)
-	{
-		if (world.getSeasonManager().getCurrentSeason() != null && !world.getSeasonManager().getCurrentSeason().letWeatherCleanUpSnow) return;
-
-		if (rand.nextInt(4) == 0)
-		{
-			int y = world.getHeightValue(x, z);
-
-			int blockId = world.getBlockId(x, y, z);
-			int blockIdBelow = world.getBlockId(x, y - 1, z);
-
-			if (world.getBlockBiome(x, y, z).hasSurfaceSnow())
-			{
-				if (blockId == Blocks.LAYER_SNOW.id())
-				{
-					int meta = world.getBlockMetadata(x, y, z);
-					if (meta != 0)
-					{
-						world.setBlockMetadata(x, y, z, meta - 1);
-						world.markBlockNeedsUpdate(x, y, z);
-					}
-				}
-			}
-			else
-			{
-				if (blockId == Blocks.LAYER_SNOW.id())
-				{
-					int meta = world.getBlockMetadata(x, y, z);
-					if (meta != 0)
-					{
-						world.setBlockMetadata(x, y, z, meta - 1);
-						world.markBlockNeedsUpdate(x, y, z);
-					}
-					else
-					{
-						world.setBlockWithNotify(x, y, z, 0);
-					}
-				}
-				else if (blockIdBelow == Blocks.ICE.id())
-				{
-					world.setBlockWithNotify(x, y - 1, z, Blocks.FLUID_WATER_STILL.id());
-				}
-			}
-		}
-	}
-
-	public void doChunkLoadEffect(World world, Chunk chunk)
-	{
-		if (world.getSeasonManager().getCurrentSeason() != null && !world.getSeasonManager().getCurrentSeason().letWeatherCleanUpSnow) return;
-
-		for (int x = 0; x < 16; x++)
-		{
-			for (int z = 0; z < 16; z++)
-			{
-				int y = chunk.getHeightValue(x, z);
-				if (y == 0) continue;
-
-				int blockId = chunk.getBlockID(x, y, z);
-				int blockIdBelow = chunk.getBlockID(x, y - 1, z);
-
-				if (world.getBlockBiome(chunk.xPosition * 16 + x, y, chunk.zPosition * 16 + z).hasSurfaceSnow())
-				{
-					if (blockId == Blocks.LAYER_SNOW.id())
-					{
-						chunk.setBlockMetadata(x, y, z, 0);
-					}
-				}
-				else
-				{
-					if (blockId == Blocks.LAYER_SNOW.id())
-					{
-						chunk.setBlockID(x, y, z, 0);
-					}
-					else if (blockIdBelow == Blocks.ICE.id())
-					{
-						chunk.setBlockID(x, y - 1, z, Blocks.FLUID_WATER_STILL.id());
-					}
-				}
-			}
-		}
-	}
+public abstract class Weather {
+    private final int id;
+    private final @NotNull String languageKey;
+    private final int lightLevelSubtracted;
+    private final boolean mobDaylightSpawnAllowed;
+    private final boolean isDamp;
+    private final float fogDistanceMultiplier;
+
+    public Weather(final int id, final @NotNull String languageKey, final @NotNull WeatherConfig weatherConfig) {
+        this.id = id;
+        this.languageKey = "weather." + languageKey;
+
+        this.lightLevelSubtracted = weatherConfig.getLightLevelSubtracted();
+        this.mobDaylightSpawnAllowed = weatherConfig.isMobDaylightSpawnAllowed();
+        this.isDamp = weatherConfig.isDamp();
+        this.fogDistanceMultiplier = weatherConfig.getFogDistanceMultiplier();
+
+        if (Weathers.WEATHERS[id] != null) throw new RuntimeException();
+        Weathers.WEATHERS[id] = this;
+    }
+
+    public final int getId() {
+        return this.id;
+    }
+
+    public final @NotNull String getLanguageKey() {
+        return this.languageKey;
+    }
+
+    public final @NotNull String getNameLanguageKey() {
+        return this.languageKey + ".name";
+    }
+
+    public final int getLightLevelSubtracted() {
+        return this.lightLevelSubtracted;
+    }
+
+    public final boolean isMobDaylightSpawnAllowed() {
+        return this.mobDaylightSpawnAllowed;
+    }
+
+    public final boolean isDamp() {
+        return this.isDamp;
+    }
+
+    public final float getFogDistanceMultiplier() {
+        return this.fogDistanceMultiplier;
+    }
+
+    public abstract float @NotNull [] modifyFogColor(final float r, final float g, final float b, final float intensity);
+
+    public void doEnvironmentUpdate(final @NotNull World world, final @NotNull Random rand, final int x, final int z) {
+        if (world.getSeasonManager().getCurrentSeason() != null && !world.getSeasonManager().getCurrentSeason().letWeatherCleanUpSnow)
+            return;
+
+        if (rand.nextInt(4) == 0) {
+            final int y = world.getHeightValue(x, z);
+
+            final int blockId = world.getBlockId(x, y, z);
+            final int blockIdBelow = world.getBlockId(x, y - 1, z);
+
+            if (world.getBlockBiome(x, y, z).hasSurfaceSnow()) {
+                if (blockId == Blocks.LAYER_SNOW.id()) {
+                    final int meta = world.getBlockMetadata(x, y, z);
+                    if (meta != 0) {
+                        world.setBlockMetadata(x, y, z, meta - 1);
+                        world.markBlockNeedsUpdate(x, y, z);
+                    }
+                }
+            } else {
+                if (blockId == Blocks.LAYER_SNOW.id()) {
+                    final int meta = world.getBlockMetadata(x, y, z);
+                    if (meta != 0) {
+                        world.setBlockMetadata(x, y, z, meta - 1);
+                        world.markBlockNeedsUpdate(x, y, z);
+                    } else {
+                        world.setBlockWithNotify(x, y, z, 0);
+                    }
+                } else if (blockIdBelow == Blocks.ICE.id()) {
+                    world.setBlockWithNotify(x, y - 1, z, Blocks.FLUID_WATER_STILL.id());
+                }
+            }
+        }
+    }
+
+    public void doChunkLoadEffect(final @NotNull World world, final @NotNull Chunk chunk) {
+        if (world.getSeasonManager().getCurrentSeason() != null && !world.getSeasonManager().getCurrentSeason().letWeatherCleanUpSnow) {
+            return;
+        }
+
+        for (int x = 0; x < 16; x++) {
+            for (int z = 0; z < 16; z++) {
+                int y = chunk.getHeightValue(x, z);
+                if (y == 0) continue;
+
+                int blockId = chunk.getBlockID(x, y, z);
+                int blockIdBelow = chunk.getBlockID(x, y - 1, z);
+
+                if (world.getBlockBiome(chunk.xPosition * 16 + x, y, chunk.zPosition * 16 + z).hasSurfaceSnow()) {
+                    if (blockId == Blocks.LAYER_SNOW.id()) {
+                        chunk.setBlockMetadata(x, y, z, 0);
+                    }
+                } else {
+                    if (blockId == Blocks.LAYER_SNOW.id()) {
+                        chunk.setBlockID(x, y, z, 0);
+                    } else if (blockIdBelow == Blocks.ICE.id()) {
+                        chunk.setBlockID(x, y - 1, z, Blocks.FLUID_WATER_STILL.id());
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherClear.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherClear.java
index 1c1ffa3b5..d755c465b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherClear.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherClear.java
@@ -1,10 +1,14 @@
 package net.minecraft.core.world.weather;
 
-public class WeatherClear extends Weather
-{
-	public WeatherClear(int id)
-	{
-		super(id);
-	}
+import org.jetbrains.annotations.NotNull;
 
+public class WeatherClear extends Weather {
+    public WeatherClear(final int id, final @NotNull String languageKey, final @NotNull WeatherConfig weatherConfig) {
+        super(id, languageKey, weatherConfig);
+    }
+
+    @Override
+    public float @NotNull [] modifyFogColor(final float r, final float g, final float b, final float intensity) {
+        return new float[]{r, g, b};
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherConfig.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherConfig.java
new file mode 100644
index 000000000..811ab0793
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherConfig.java
@@ -0,0 +1,54 @@
+package net.minecraft.core.world.weather;
+
+
+import org.jetbrains.annotations.NotNull;
+
+public class WeatherConfig {
+    private int lightLevelSubtracted = 0;
+    private boolean mobDaylightSpawnAllowed = false;
+    private boolean isDamp = false;
+    private float fogDistanceMultiplier = 1.0f;
+
+    public WeatherConfig() {
+    }
+
+    public @NotNull WeatherConfig setLightLevelSubtracted(final int lightLevelSubtracted) {
+        this.lightLevelSubtracted = lightLevelSubtracted;
+
+        return this;
+    }
+
+    public int getLightLevelSubtracted() {
+        return this.lightLevelSubtracted;
+    }
+
+    public @NotNull WeatherConfig setMobDaylightSpawnAllowed(final boolean mobDaylightSpawnAllowed) {
+        this.mobDaylightSpawnAllowed = mobDaylightSpawnAllowed;
+
+        return this;
+    }
+
+    public boolean isMobDaylightSpawnAllowed() {
+        return this.mobDaylightSpawnAllowed;
+    }
+
+    public @NotNull WeatherConfig setDamp(final boolean isDamp) {
+        this.isDamp = isDamp;
+
+        return this;
+    }
+
+    public boolean isDamp() {
+        return this.isDamp;
+    }
+
+    public @NotNull WeatherConfig setFogDistanceMultiplier(final float fogDistanceMultiplier) {
+        this.fogDistanceMultiplier = fogDistanceMultiplier;
+
+        return this;
+    }
+
+    public float getFogDistanceMultiplier() {
+        return this.fogDistanceMultiplier;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherManager.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherManager.java
index 0170e655e..ec6ac3dcc 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherManager.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherManager.java
@@ -5,22 +5,24 @@ import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.season.Season;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class WeatherManager {
-    private final World world;
+    private final @NotNull World world;
 
-    private Weather lastWeather = null;
-    private Weather currentWeather = null;
-    private Weather nextWeather = null;
+    private @Nullable Weather lastWeather = null;
+    private @Nullable Weather currentWeather = null;
+    private @Nullable Weather nextWeather = null;
     private long weatherDuration = Global.DAY_LENGTH_TICKS;
     private float weatherIntensity = 1.0f;
     private float weatherPower = 1.0f;
 
-    public WeatherManager(World world) {
+    public WeatherManager(final @NotNull World world) {
         this.world = world;
     }
 
-    public WeatherManager(World world, Weather currentWeather, Weather nextWeather, long weatherDuration, float weatherIntensity, float weatherPower) {
+    public WeatherManager(final World world, final @Nullable Weather currentWeather, final @Nullable Weather nextWeather, final long weatherDuration, final float weatherPower) {
         this(world);
         this.currentWeather = currentWeather;
         this.nextWeather = nextWeather;
@@ -34,29 +36,32 @@ public class WeatherManager {
             this.weatherIntensity = 1.0f;
         }
     }
-    public Weather getLastWeather() { return lastWeather; }
 
-    public Weather getCurrentWeather() {
-        return currentWeather;
+    public @Nullable Weather getLastWeather() {
+        return this.lastWeather;
     }
 
-    public Weather getNextWeather() {
-        return nextWeather;
+    public @Nullable Weather getCurrentWeather() {
+        return this.currentWeather;
+    }
+
+    public @Nullable Weather getNextWeather() {
+        return this.nextWeather;
     }
 
     public long getWeatherDuration() {
-        return weatherDuration;
+        return this.weatherDuration;
     }
 
     public float getWeatherIntensity() {
-        return weatherIntensity;
+        return this.weatherIntensity;
     }
 
     public float getWeatherPower() {
-        return weatherPower;
+        return this.weatherPower;
     }
 
-    public void overrideWeather(Weather currentWeather, Weather nextWeather, long weatherDuration, float weatherIntensity, float weatherPower) {
+    public void overrideWeather(final @Nullable Weather currentWeather, final @Nullable Weather nextWeather, final long weatherDuration, final float weatherIntensity, final float weatherPower) {
         this.lastWeather = this.currentWeather;
         this.currentWeather = currentWeather;
         this.nextWeather = nextWeather;
@@ -65,109 +70,111 @@ public class WeatherManager {
         this.weatherPower = weatherPower;
     }
 
-    public void overrideWeather(Weather weather, long duration, float power) {
-        lastWeather = currentWeather;
-        currentWeather = weather;
-        nextWeather = null;
-        weatherDuration = duration;
-        weatherIntensity = 1.0f;
-        weatherPower = MathHelper.clamp(power, 0.0f, 1.0f);
+    public void overrideWeather(final @Nullable Weather weather, final long duration, final float power) {
+        this.lastWeather = this.currentWeather;
+        this.currentWeather = weather;
+        this.nextWeather = null;
+        this.weatherDuration = duration;
+        this.weatherIntensity = 1.0f;
+        this.weatherPower = MathHelper.clamp(power, 0.0f, 1.0f);
     }
 
-    public void overrideWeather(Weather weather, long duration) {
+    public void overrideWeather(final @Nullable Weather weather, final long duration) {
         this.overrideWeather(weather, duration, getRandomWeatherPower());
     }
 
-    public void overrideWeather(Weather weather) {
+    public void overrideWeather(final @Nullable Weather weather) {
         this.overrideWeather(weather, getRandomWeatherDuration());
     }
 
     public void skip() {
-        weatherDuration = 0;
+        this.weatherDuration = 0;
     }
 
     public boolean tick() {
-        if(world.worldType.hasCeiling())
-        {
+        if (this.world.getWorldType().hasCeiling()) {
             return false;
         }
-        if (world.getSeasonManager().getCurrentSeason() == null)
+        if (this.world.getSeasonManager().getCurrentSeason() == null)
             return false;
 
-        if (currentWeather == null) {
-            lastWeather = null;
-            currentWeather = world.worldType.getDefaultWeather();
-            weatherDuration = getRandomWeatherDuration();
+        if (this.currentWeather == null) {
+            this.lastWeather = null;
+            this.currentWeather = this.world.getWorldType().getDefaultWeather();
+            this.weatherDuration = getRandomWeatherDuration();
         }
 
-        if (nextWeather == null && weatherIntensity <= 1.0f)
-        {
-            weatherIntensity += 0.002f;
-            if (weatherIntensity > 1.0f)
-                weatherIntensity = 1.0f;
-        }
-        else if (nextWeather != null && weatherIntensity >= 0.0f)
-        {
-            weatherIntensity -= 0.002f;
-            if (!world.isClientSide) {
-                if (world.dayCanHaveRainbow && world.rainbowTicks <= 0 && weatherIntensity < 0.5f && currentWeather.precipitationType == 0 && !nextWeather.isPrecipitation){ // On rain end
-                    int rainbowTicks = world.rand.nextInt(20 * 90) + 20 * 30;
-                    world.addRainbow(rainbowTicks);
+        if (this.nextWeather == null && this.weatherIntensity <= 1.0f) {
+            this.weatherIntensity += 0.002f;
+            if (this.weatherIntensity > 1.0f)
+                this.weatherIntensity = 1.0f;
+        } else if (this.nextWeather != null && this.weatherIntensity >= 0.0f) {
+            this.weatherIntensity -= 0.002f;
+            if (!this.world.isClientSide) {
+                if (this.currentWeather instanceof IPrecipitation) {
+                    final @NotNull IPrecipitation precipitation = (IPrecipitation) this.currentWeather;
+                    if (this.world.dayCanHaveRainbow &&
+                        this.world.rainbowTicks <= 0 &&
+                        this.weatherIntensity < 0.5f &&
+                        precipitation.getPrecipitationType() == IPrecipitation.Type.RAIN_LIKE &&
+                        !(this.nextWeather instanceof IPrecipitation)
+                    ) { // On rain end
+                        final int rainbowTicks = this.world.rand.nextInt(20 * 90) + 20 * 30;
+                        this.world.addRainbow(rainbowTicks);
+                    }
                 }
             }
-            if (weatherIntensity <= 0.0f) {
-                weatherIntensity = 0.0f;
-                lastWeather = currentWeather;
-                currentWeather = nextWeather;
-                weatherPower = getRandomWeatherPower();
-                nextWeather = null;
+            if (this.weatherIntensity <= 0.0f) {
+                this.weatherIntensity = 0.0f;
+                this.lastWeather = this.currentWeather;
+                this.currentWeather = this.nextWeather;
+                this.weatherPower = getRandomWeatherPower();
+                this.nextWeather = null;
             }
         }
 
-        if (world.getGameRuleValue(GameRules.DO_WEATHER_CYCLE)) {
-            weatherDuration--;
+        if (this.world.getGameRuleValue(GameRules.DO_WEATHER_CYCLE)) {
+            this.weatherDuration--;
         }
-        if (weatherDuration <= 0)
-        {
-            if (currentWeather != world.worldType.getDefaultWeather()) {
-                nextWeather = world.worldType.getDefaultWeather();
+        if (this.weatherDuration <= 0) {
+            if (this.currentWeather != this.world.getWorldType().getDefaultWeather()) {
+                this.nextWeather = this.world.getWorldType().getDefaultWeather();
             } else {
-                Season season = world.getSeasonManager().getCurrentSeason();
+                final @NotNull Season season = this.world.getSeasonManager().getCurrentSeason();
                 boolean foundWeather = false;
                 float acc = 0.0f;
-                float val = world.rand.nextFloat();
+                final float val = this.world.rand.nextFloat();
                 for (int i = 0; i < season.allowedWeathers.size(); i++) {
                     acc += season.weatherProbability.get(season.allowedWeathers.get(i));
                     if (val < acc) {
-                        nextWeather = season.allowedWeathers.get(i);
+                        this.nextWeather = season.allowedWeathers.get(i);
                         foundWeather = true;
                         break;
                     }
                 }
                 if (!foundWeather) {
-                    nextWeather = world.worldType.getDefaultWeather();
+                    this.nextWeather = this.world.getWorldType().getDefaultWeather();
                 }
 
             }
-            weatherDuration = getRandomWeatherDuration();
+            this.weatherDuration = getRandomWeatherDuration();
         }
 
-        world.dimensionData.setCurrentWeather(currentWeather);
-        world.dimensionData.setNextWeather(nextWeather);
+        this.world.dimensionData.setCurrentWeather(this.currentWeather);
+        this.world.dimensionData.setNextWeather(this.nextWeather);
 
-        world.dimensionData.setWeatherDuration(weatherDuration);
-        world.dimensionData.setWeatherIntensity(weatherIntensity);
-        world.dimensionData.setWeatherPower(weatherPower);
+        this.world.dimensionData.setWeatherDuration(this.weatherDuration);
+        this.world.dimensionData.setWeatherIntensity(this.weatherIntensity);
+        this.world.dimensionData.setWeatherPower(this.weatherPower);
 
         return true;
-
     }
 
     private long getRandomWeatherDuration() {
-        return (long)(world.rand.nextFloat() * (Global.DAY_LENGTH_TICKS * 1.5f) + (Global.DAY_LENGTH_TICKS * 0.25f));
+        return (long) (this.world.rand.nextFloat() * (Global.DAY_LENGTH_TICKS * 1.5f) + (Global.DAY_LENGTH_TICKS * 0.25f));
     }
 
     private float getRandomWeatherPower() {
-        return world.rand.nextFloat() * 0.5f + 0.5f;
+        return this.world.rand.nextFloat() * 0.5f + 0.5f;
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherRain.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherRain.java
index b130c85a7..f1d18e9fd 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherRain.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherRain.java
@@ -1,22 +1,34 @@
 package net.minecraft.core.world.weather;
 
-public class WeatherRain extends Weather
-{
+import org.jetbrains.annotations.NotNull;
 
-	public WeatherRain(int id)
-	{
-		super(id);
-	}
-	
-	@Override
-	public float[] modifyFogColor(float r, float g, float b, float intensity)
-	{
-		float f6 = 1.0F - intensity * 0.5F;
-        float f8 = 1.0F - intensity * 0.4F;
-        r *= f6;
-        g *= f6;
-        b *= f8;
-        
-        return new float[] { r, g, b };
-	}
+public class WeatherRain
+    extends Weather
+    implements IPrecipitation {
+    public WeatherRain(final int id, final @NotNull String languageKey, final @NotNull WeatherConfig weatherConfig) {
+        super(id, languageKey, weatherConfig);
+    }
+
+    @Override
+    public float @NotNull [] modifyFogColor(final float r, final float g, final float b, final float intensity) {
+        final float rgMod = 1.0F - intensity * 0.5F;
+        final float bMod = 1.0F - intensity * 0.4F;
+
+        return new float[]{r * rgMod, g * rgMod, b * bMod};
+    }
+
+    @Override
+    public @NotNull Type getPrecipitationType() {
+        return Type.RAIN_LIKE;
+    }
+
+    @Override
+    public @NotNull String getPrecipitationTexturePath(final float power, final float intensity) {
+        return "/assets/minecraft/textures/environment/rain.png";
+    }
+
+    @Override
+    public boolean spawnRainParticles() {
+        return true;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherRainBlood.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherRainBlood.java
new file mode 100644
index 000000000..23a65e693
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherRainBlood.java
@@ -0,0 +1,19 @@
+package net.minecraft.core.world.weather;
+
+import org.jetbrains.annotations.NotNull;
+
+public class WeatherRainBlood extends WeatherStorm {
+    public WeatherRainBlood(final int id, final @NotNull String languageKey, final @NotNull WeatherConfig weatherConfig) {
+        super(id, languageKey, weatherConfig);
+    }
+
+    @Override
+    public @NotNull Type getPrecipitationType() {
+        return Type.INVERTED_RAIN_LIKE;
+    }
+
+    @Override
+    public @NotNull String getPrecipitationTexturePath(final float power, final float intensity) {
+        return "/assets/minecraft/textures/environment/rain_blood.png";
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
index cee09c2c5..6db888133 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
@@ -10,119 +10,112 @@ import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.Biomes;
 import net.minecraft.core.world.chunk.Chunk;
+import org.jetbrains.annotations.NotNull;
 
-public class WeatherSnow extends Weather
-{
-
-	public WeatherSnow(int id)
-	{
-		super(id);
-	}
-
-	@Override
-	public String getPrecipitationTexture(World world)
-	{
-		if (world.weatherManager.getWeatherPower() <= 0.6f)
-		{
-			return "/assets/minecraft/textures/environment/snow_light.png";
-		}
-		else
-		{
-			return "/assets/minecraft/textures/environment/snow.png";
-		}
-	}
-
-	@Override
-	public void doChunkLoadEffect(World world, Chunk chunk)
-	{
-		if (world.weatherManager.getWeatherPower() <= 0.6f) return;
-		for (int x = 0; x < 16; x++)
-		{
-			int worldX = chunk.xPosition * 16 + x;
-zLoop:		for (int z = 0; z < 16; z++)
-			{
-				int worldZ = chunk.zPosition * 16 + z;
-				int y = world.findTopSolidBlock(worldX, worldZ);
-
-				Biome biome = world.getBlockBiome(worldX, y, worldZ);
-				for (int i = 0; i < biome.blockedWeathers.length; i++)
-				{
-					if (biome.blockedWeathers[i] == this) continue zLoop;
-				}
-
-				int blockId = chunk.getBlockID(x, y, z);
-				int blockIdBelow = chunk.getBlockID(x, y - 1, z);
-
-				if (y >= 0 && y < world.getHeightBlocks() && chunk.getBrightness(LightLayer.Block, x, y, z) < 10)
-				{
-					if (blockId == 0 && Blocks.LAYER_SNOW.canPlaceBlockAt(world, worldX, y, worldZ) && blockIdBelow != Blocks.ICE.id())
-					{
-						chunk.setBlockIDWithMetadataRaw(x, y, z, Blocks.LAYER_SNOW.id(), chunk.getBlockMetadata(x, y, z));
-					}
-					else if (blockIdBelow == Blocks.FLUID_WATER_STILL.id() && chunk.getBlockMetadata(x, y - 1, z) == 0) {
-						chunk.setBlockIDWithMetadataRaw(x, y - 1, z, Blocks.ICE.id(), chunk.getBlockMetadata(x, y - 1, z));
-						if (chunk.getBlockID(x, y - 2, z) == Blocks.FLUID_WATER_STILL.id()){
-							chunk.setBlockIDWithMetadataRaw(x, y - 2, z, Blocks.FLUID_WATER_FLOWING.id(), chunk.getBlockMetadata(x, y - 2, z));
-						}
-					}
-				}
-			}
-		}
-	}
-
-	@Override
-	public void doEnvironmentUpdate(World world, Random rand, int x, int z)
-	{
-		int probability = (int)(64 * (1 / world.weatherManager.getWeatherPower()));
-		if (world.getSeasonManager().getCurrentSeason() != null && world.getSeasonManager().getCurrentSeason().hasDeeperSnow)
-		{
-			probability /= 2;
-		}
-		
-		boolean snow = rand.nextInt(probability) == 0;
-		
-		int y = world.findTopSolidBlock(x, z);
-		
-		int blockId = world.getBlockId(x, y, z);
-		int blockIdBelow = world.getBlockId(x, y - 1, z);
-		
-		Biome biome = world.getBlockBiome(x, y, z);
-		for (int i = 0; i < biome.blockedWeathers.length; i++)
-		{
-			if (biome.blockedWeathers[i] == this) return;
-		}
-		
-		if (world.weatherManager.getWeatherPower() > 0.6f && y >= 0 && y < world.getHeightBlocks() && world.getSavedLightValue(LightLayer.Block, x, y, z) < 10)
-		{
-			if (blockId == 0 && blockIdBelow != 0 && Blocks.LAYER_SNOW.canPlaceBlockAt(world, x, y, z) && blockIdBelow != Blocks.ICE.id())
-			{
-				if(snow)
-				{
-					world.setBlockWithNotify(x, y, z, Blocks.LAYER_SNOW.id());
-				}
-			}
-			else if (world.weatherManager.getWeatherPower() > 0.5f && blockId == Blocks.LAYER_SNOW.id() && world.getSeasonManager().getCurrentSeason() != null && (world.getSeasonManager().getCurrentSeason().hasDeeperSnow || biome == Biomes.OVERWORLD_GLACIER))
-			{
-				if(snow) {
-					Blocks.LAYER_SNOW.getLogic().accumulate(world, x, y, z);
-				}
-			}
-			else if (blockIdBelow == Blocks.FLUID_WATER_STILL.id() && world.getBlockMetadata(x, y - 1, z) == 0)
-			{
-				if(rand.nextFloat() < world.weatherManager.getWeatherPower() * world.weatherManager.getWeatherIntensity())
-				{
-					for(int i=0; i < 4; i++)
-					{
-						Direction direction = Direction.horizontalDirections[i];
-						Block<?> block = world.getBlock(x + direction.getOffsetX(), y - 1, z + direction.getOffsetZ());
-						if(block == Blocks.ICE || block != null && block.isSolidRender())
-						{
-							world.setBlockWithNotify(x, y - 1, z, Blocks.ICE.id());
-							break;
-						}
-					}	
-				}
-			}
-		}
-	}
+public class WeatherSnow
+    extends Weather
+    implements IPrecipitation {
+
+    public WeatherSnow(final int id, final @NotNull String languageKey, final @NotNull WeatherConfig weatherConfig) {
+        super(id, languageKey, weatherConfig);
+    }
+
+    @Override
+    public @NotNull Type getPrecipitationType() {
+        return Type.SNOW_LIKE;
+    }
+
+    @Override
+    public @NotNull String getPrecipitationTexturePath(final float power, final float intensity) {
+        if (power <= 0.6f) {
+            return "/assets/minecraft/textures/environment/snow_light.png";
+        } else {
+            return "/assets/minecraft/textures/environment/snow.png";
+        }
+    }
+
+    @Override
+    public boolean spawnRainParticles() {
+        return false;
+    }
+
+    @Override
+    public void doChunkLoadEffect(@NotNull World world, @NotNull Chunk chunk) {
+        if (world.weatherManager.getWeatherPower() <= 0.6f) return;
+        for (int x = 0; x < 16; x++) {
+            int worldX = chunk.xPosition * 16 + x;
+            zLoop:
+            for (int z = 0; z < 16; z++) {
+                int worldZ = chunk.zPosition * 16 + z;
+                int y = world.findTopSolidBlock(worldX, worldZ);
+
+                Biome biome = world.getBlockBiome(worldX, y, worldZ);
+                for (int i = 0; i < biome.blockedWeathers.length; i++) {
+                    if (biome.blockedWeathers[i] == this) continue zLoop;
+                }
+
+                int blockId = chunk.getBlockID(x, y, z);
+                int blockIdBelow = chunk.getBlockID(x, y - 1, z);
+
+                if (y >= 0 && y < world.getHeightBlocks() && chunk.getBrightness(LightLayer.Block, x, y, z) < 10) {
+                    if (blockId == 0 && Blocks.LAYER_SNOW.canPlaceBlockAt(world, worldX, y, worldZ) && blockIdBelow != Blocks.ICE.id()) {
+                        chunk.setBlockIDWithMetadataRaw(x, y, z, Blocks.LAYER_SNOW.id(), chunk.getBlockMetadata(x, y, z));
+                    } else if (blockIdBelow == Blocks.FLUID_WATER_STILL.id() && chunk.getBlockMetadata(x, y - 1, z) == 0) {
+                        chunk.setBlockIDWithMetadataRaw(x, y - 1, z, Blocks.ICE.id(), chunk.getBlockMetadata(x, y - 1, z));
+                        if (chunk.getBlockID(x, y - 2, z) == Blocks.FLUID_WATER_STILL.id()) {
+                            chunk.setBlockIDWithMetadataRaw(x, y - 2, z, Blocks.FLUID_WATER_FLOWING.id(), chunk.getBlockMetadata(x, y - 2, z));
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public float @NotNull [] modifyFogColor(final float r, final float g, final float b, final float intensity) {
+        return new float[]{r, g, b};
+    }
+
+    @Override
+    public void doEnvironmentUpdate(@NotNull World world, @NotNull Random rand, int x, int z) {
+        int probability = (int) (64 * (1 / world.weatherManager.getWeatherPower()));
+        if (world.getSeasonManager().getCurrentSeason() != null && world.getSeasonManager().getCurrentSeason().hasDeeperSnow) {
+            probability /= 2;
+        }
+
+        boolean snow = rand.nextInt(probability) == 0;
+
+        int y = world.findTopSolidBlock(x, z);
+
+        int blockId = world.getBlockId(x, y, z);
+        int blockIdBelow = world.getBlockId(x, y - 1, z);
+
+        Biome biome = world.getBlockBiome(x, y, z);
+        for (int i = 0; i < biome.blockedWeathers.length; i++) {
+            if (biome.blockedWeathers[i] == this) return;
+        }
+
+        if (world.weatherManager.getWeatherPower() > 0.6f && y >= 0 && y < world.getHeightBlocks() && world.getSavedLightValue(LightLayer.Block, x, y, z) < 10) {
+            if (blockId == 0 && blockIdBelow != 0 && Blocks.LAYER_SNOW.canPlaceBlockAt(world, x, y, z) && blockIdBelow != Blocks.ICE.id()) {
+                if (snow) {
+                    world.setBlockWithNotify(x, y, z, Blocks.LAYER_SNOW.id());
+                }
+            } else if (world.weatherManager.getWeatherPower() > 0.5f && blockId == Blocks.LAYER_SNOW.id() && world.getSeasonManager().getCurrentSeason() != null && (world.getSeasonManager().getCurrentSeason().hasDeeperSnow || biome == Biomes.OVERWORLD_GLACIER)) {
+                if (snow) {
+                    Blocks.LAYER_SNOW.getLogic().accumulate(world, x, y, z);
+                }
+            } else if (blockIdBelow == Blocks.FLUID_WATER_STILL.id() && world.getBlockMetadata(x, y - 1, z) == 0) {
+                if (rand.nextFloat() < world.weatherManager.getWeatherPower() * world.weatherManager.getWeatherIntensity()) {
+                    for (int i = 0; i < 4; i++) {
+                        Direction direction = Direction.horizontalDirections[i];
+                        Block<?> block = world.getBlock(x + direction.getOffsetX(), y - 1, z + direction.getOffsetZ());
+                        if (block == Blocks.ICE || block != null && block.isSolidRender()) {
+                            world.setBlockWithNotify(x, y - 1, z, Blocks.ICE.id());
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherStorm.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherStorm.java
index f714ff933..6c8784f47 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherStorm.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherStorm.java
@@ -6,81 +6,78 @@ import net.minecraft.core.entity.Mob;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.List;
 import java.util.Random;
 
-public class WeatherStorm extends WeatherRain
-{
-	public WeatherStorm(int id)
-	{
-		super(id);
-	}
-	
-	@Override
-	public float[] modifyFogColor(float r, float g, float b, float intensity)
-	{
-		float[] out = super.modifyFogColor(r, g, b, intensity);
-        float f9 = 1.0F - intensity * 0.5F;
-        out[0] *= f9;
-        out[1] *= f9;
-        out[2] *= f9;
-        
+public class WeatherStorm extends WeatherRain {
+
+    public WeatherStorm(final int id, final @NotNull String languageKey, final @NotNull WeatherConfig weatherConfig) {
+        super(id, languageKey, weatherConfig);
+    }
+
+    @Override
+    public float @NotNull [] modifyFogColor(final float r, final float g, final float b, final float intensity) {
+        final float[] out = super.modifyFogColor(r, g, b, intensity);
+        final float mod = 1.0F - intensity * 0.5F;
+        out[0] *= mod;
+        out[1] *= mod;
+        out[2] *= mod;
+
         return out;
-	}
-	
-	@Override
-	public void doEnvironmentUpdate(World world, Random rand, int x, int z)
-	{
-		super.doEnvironmentUpdate(world, rand, x, z);
-		
-		if (rand.nextInt((int)(100000 * (1 / world.weatherManager.getWeatherPower()))) == 0)
-		{
-			final int searchRadius = 32;
+    }
+
+    @Override
+    public void doEnvironmentUpdate(final @NotNull World world, final @NotNull Random rand, final int x, final int z) {
+        super.doEnvironmentUpdate(world, rand, x, z);
+
+        if (rand.nextInt((int) (100000 * (1 / world.weatherManager.getWeatherPower()))) == 0) {
+            final int searchRadius = 32;
+
+            int maxWeight = Integer.MIN_VALUE;
+            int targetX = x;
+            int targetY = world.getHeightValue(x, z);
+            int targetZ = z;
+            for (int _x = -searchRadius; _x <= searchRadius; _x++) {
+                for (int _z = -searchRadius; _z < searchRadius; _z++) {
+                    final int checkX = x + _x;
+                    final int checkZ = z + _z;
+                    final int checkY = world.getHeightValue(checkX, checkZ);
+                    final int weight = evalStrikeWeight(world, rand, x, z, checkX, checkY, checkZ);
+                    if (weight > maxWeight) {
+                        maxWeight = weight;
+                        targetX = checkX;
+                        targetY = checkY;
+                        targetZ = checkZ;
+                    }
+                }
+            }
 
-			int maxWeight = Integer.MIN_VALUE;
-			int targetX = x;
-			int targetY = world.getHeightValue(x, z);
-			int targetZ = z;
-			for (int _x = -searchRadius; _x <= searchRadius; _x++) {
-				for (int _z = -searchRadius; _z < searchRadius; _z++) {
-					int checkX = x + _x;
-					int checkZ = z + _z;
-					int checkY = world.getHeightValue(checkX, checkZ);
-					int weight = evalStrikeWeight(world, rand, x, z, checkX, checkY, checkZ);
-					if (weight > maxWeight){
-						maxWeight = weight;
-						targetX = checkX;
-						targetY = checkY;
-						targetZ = checkZ;
-					}
-				}
-			}
+            if (world.canBlockBeRainedOn(targetX, targetY, targetZ)) {
+                world.addWeatherEffect(new EntityLightning(world, targetX, targetY, targetZ));
+            }
+        }
+    }
 
-			if (world.canBlockBeRainedOn(targetX, targetY, targetZ))
-			{
-				world.addWeatherEffect(new EntityLightning(world, targetX, targetY, targetZ));
-			}			
-		}
-	}
-	public int evalStrikeWeight(World world, Random random, int orgX, int orgZ, int checkX, int checkY, int checkZ){
-		Material material = world.getBlockMaterial(checkX, checkY - 1, checkZ);
-		int weight = random.nextInt(10);
-		weight += checkY;
-		weight += material.getConductivity();
+    private static int evalStrikeWeight(final @NotNull World world, final @NotNull Random random, final int orgX, final int orgZ, final int checkX, final int checkY, final int checkZ) {
+        final @NotNull Material material = world.getBlockMaterial(checkX, checkY - 1, checkZ);
+        int weight = random.nextInt(10);
+        weight += checkY;
+        weight += material.getConductivity();
 
-		List<Mob> entityList = world.getEntitiesWithinAABB(Mob.class, AABB.getTemporaryBB(checkX, checkY, checkZ, checkX + 1, checkY + 1, checkZ + 1));
-		if (!entityList.isEmpty()){
-			weight += 4; // :)
-		}
+        final @NotNull List<@NotNull Mob> entityList = world.getEntitiesWithinAABB(Mob.class, AABB.getTemporaryBB(checkX, checkY, checkZ, checkX + 1, checkY + 1, checkZ + 1));
+        if (!entityList.isEmpty()) {
+            weight += 4; // :)
+        }
 
-		final int distX =  (checkX - orgX);
-		final int distZ =  (checkZ - orgZ);
-		final double dist = Math.sqrt(distX * distX + distZ + distZ);
-		final int decayFactor = MathHelper.floor(Math.sqrt(dist) / 4);
-		weight -= decayFactor;
+        final int distX = (checkX - orgX);
+        final int distZ = (checkZ - orgZ);
+        final double dist = Math.sqrt(distX * distX + distZ + distZ);
+        final int decayFactor = MathHelper.floor(Math.sqrt(dist) / 4);
+        weight -= decayFactor;
 
-		return weight;
-	}
+        return weight;
+    }
 
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/Weathers.java b/game/core/src/main/java/net/minecraft/core/world/weather/Weathers.java
index 8bd03d6df..60777a8d1 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/Weathers.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/Weathers.java
@@ -1,61 +1,64 @@
 package net.minecraft.core.world.weather;
 
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
 public abstract class Weathers {
-    public static final Weather[] WEATHERS = new Weather[16];
-    public static final Weather OVERWORLD_CLEAR = new WeatherClear(0)
-        .setLanguageKey("overworld.clear");
-    public static final Weather OVERWORLD_RAIN = new WeatherRain(1)
-        .setLanguageKey("overworld.rain")
-        .setPrecipitation("/assets/minecraft/textures/environment/rain.png", 0)
-        .setSubtractLightLevel(3)
-        .setSpawnRainParticles(true)
-        .setFogDistance(0.5f)
-        .setDamp();
-    public static final Weather OVERWORLD_SNOW = new WeatherSnow(2)
-        .setLanguageKey("overworld.snow")
-        .setPrecipitation("/assets/minecraft/textures/environment/snow.png", 1)
-        .setSubtractLightLevel(1)
-        .setFogDistance(0.5f)
-        .setDamp();
-    public static final Weather OVERWORLD_STORM = new WeatherStorm(3)
-        .setLanguageKey("overworld.storm")
-        .setPrecipitation("/assets/minecraft/textures/environment/rain.png", 0)
-        .setSubtractLightLevel(5)
-        .setSpawnRainParticles(true)
-        .setMobsSpawnInDaylight()
-        .setFogDistance(0.4f)
-        .setDamp();
-    public static final Weather OVERWORLD_FOG = new WeatherClear(4)
-        .setLanguageKey("overworld.fog")
-        .setFogDistance(0.125f);
-    public static final Weather OVERWORLD_CLEAR_HELL = new WeatherClear(5)
-        .setLanguageKey("overworld.clear.hell")
-        .setSubtractLightLevel(7);
-    public static final Weather OVERWORLD_CLEAR_WOODS = new WeatherClear(6)
-        .setLanguageKey("overworld.clear.woods")
-        .setSubtractLightLevel(2);
-    public static final Weather OVERWORLD_WINTER_SNOW = new WeatherSnow(7)
-        .setLanguageKey("overworld.winter.snow")
-        .setPrecipitation("/assets/minecraft/textures/environment/snow.png", 1)
-        .setDamp();
-    public static final Weather OVERWORLD_RAIN_BLOOD = new WeatherStorm(8)
-        .setLanguageKey("overworld.rain.blood")
-        .setPrecipitation("/assets/minecraft/textures/environment/rain_blood.png", 2)
-        .setSubtractLightLevel(5)
-        .setMobsSpawnInDaylight()
-        .setFogDistance(0.4f)
-        .setDamp();
+    public static final @Nullable Weather @NotNull[] WEATHERS = new Weather[16];
+    public static final @NotNull Weather OVERWORLD_CLEAR = new WeatherClear(0, "overworld.clear", new WeatherConfig());
+    public static final @NotNull Weather OVERWORLD_RAIN = new WeatherRain(1, "overworld.rain",
+        new WeatherConfig()
+            .setLightLevelSubtracted(3)
+            .setFogDistanceMultiplier(0.5f)
+            .setDamp(true)
+    );
+    public static final @NotNull Weather OVERWORLD_SNOW = new WeatherSnow(2, "overworld.snow",
+        new WeatherConfig()
+            .setLightLevelSubtracted(1)
+            .setFogDistanceMultiplier(0.5f)
+            .setDamp(true)
+    );
+    public static final @NotNull Weather OVERWORLD_STORM = new WeatherStorm(3, "overworld.storm",
+        new WeatherConfig()
+            .setLightLevelSubtracted(5)
+            .setMobDaylightSpawnAllowed(true)
+            .setFogDistanceMultiplier(0.4f)
+            .setDamp(true)
+    );
+    public static final @NotNull Weather OVERWORLD_FOG = new WeatherClear(4, "overworld.fog",
+        new WeatherConfig()
+            .setFogDistanceMultiplier(0.125f)
+    );
+    public static final @NotNull Weather OVERWORLD_HELL_CLEAR = new WeatherClear(5, "overworld.hell.clear",
+        new WeatherConfig()
+            .setLightLevelSubtracted(7)
+    );
+    public static final @NotNull Weather OVERWORLD_WOODS_CLEAR = new WeatherClear(6, "overworld.woods.clear",
+        new WeatherConfig()
+            .setLightLevelSubtracted(2)
+    );
+    public static final @NotNull Weather OVERWORLD_WINTER_SNOW = new WeatherSnow(7, "overworld.winter.snow",
+        new WeatherConfig()
+            .setDamp(true)
+    );
+    public static final @NotNull Weather OVERWORLD_RAIN_BLOOD = new WeatherRainBlood(8, "overworld.rain.blood",
+        new WeatherConfig()
+            .setLightLevelSubtracted(5)
+            .setMobDaylightSpawnAllowed(true)
+            .setFogDistanceMultiplier(0.4f)
+            .setDamp(true)
+    );
 
-    public static Weather getWeatherByLanguageKey(String string) {
-        for(Weather weather : WEATHERS) {
-            if(weather != null && weather.languageKey.substring(8).equalsIgnoreCase(string)) {
+    public static @Nullable Weather getWeatherByLanguageKey(final @NotNull String languageKey) {
+        for(final @Nullable Weather weather : WEATHERS) {
+            if(weather != null && weather.getLanguageKey().substring(8).equalsIgnoreCase(languageKey)) {
                 return weather;
             }
         }
         return null;
     }
 
-    public static Weather getWeather(int i) {
+    public static @Nullable Weather getWeather(final int i) {
         return WEATHERS[i];
     }
 
diff --git a/game/core/src/main/resources/lang/en_US/item.lang b/game/core/src/main/resources/lang/en_US/item.lang
index f48e92eb3..b22bf191c 100644
--- a/game/core/src/main/resources/lang/en_US/item.lang
+++ b/game/core/src/main/resources/lang/en_US/item.lang
@@ -435,3 +435,13 @@ item.jar.butterfly.silver.desc=A glass jar containing a silver butterfly.
 
 item.statue.stone.name=Stone Statue
 item.statue.stone.desc=A decorative stone statue for you to hang your armor.
+item.statue.basalt.name=Basalt Statue
+item.statue.basalt.desc=A decorative basalt statue for you to hang your armor.
+item.statue.limestone.name=Limestone Statue
+item.statue.limestone.desc=A decorative limestone statue for you to hang your armor.
+item.statue.granite.name=Granite Statue
+item.statue.granite.desc=A decorative granite statue for you to hang your armor.
+item.statue.marble.name=Marble Statue
+item.statue.marble.desc=A decorative marble statue for you to hang your armor.
+item.statue.marble.name=Pigman Statue
+item.statue.marble.desc=An ancient stone statue found in a long-forgotten place.
diff --git a/game/core/src/main/resources/lang/en_US/options.lang b/game/core/src/main/resources/lang/en_US/options.lang
index 644440c4b..3d4a4d255 100644
--- a/game/core/src/main/resources/lang/en_US/options.lang
+++ b/game/core/src/main/resources/lang/en_US/options.lang
@@ -173,6 +173,7 @@ options.chatVisibility.never_show=Never Show
 options.developerMode=Developer Mode
 options.forceOnscreenKeyboard=Force On Screen Keyboard
 options.enableHolidayTextures=Enable Holiday Textures
+options.dynamicCursor=Dynamic Cursor
 
 options.tooltipStyle.default=Default
 options.tooltipStyle.modern=Modern
@@ -191,6 +192,8 @@ options.tooltipStyle.redstone_goggles=Redstone Goggles
 options.tooltipStyle.creep-o-vision=Creep-o-Vision
 options.tooltipStyle.steve=Steve
 
+options.playerLeftHanded=Left Handed
+
 key.attack=Attack
 key.interact=Interact
 key.pickBlock=Pick Block
diff --git a/game/core/src/main/resources/lang/en_US/strings.lang b/game/core/src/main/resources/lang/en_US/strings.lang
index b5e85bc80..d283dfed0 100644
--- a/game/core/src/main/resources/lang/en_US/strings.lang
+++ b/game/core/src/main/resources/lang/en_US/strings.lang
@@ -13,8 +13,8 @@ season.paradise.silver.name=Silver
 season.null.name=No Season
 
 weather.overworld.clear.name=Clear
-weather.overworld.clear.hell.name=Clear
-weather.overworld.clear.woods.name=Clear
+weather.overworld.hell.clear.name=Clear
+weather.overworld.woods.clear.name=Clear
 weather.overworld.rain.name=Raining
 weather.overworld.snow.name=Snowing
 weather.overworld.winter.snow.name=Snowing
diff --git a/game/core/src/main/resources/lang/en_US/tile.lang b/game/core/src/main/resources/lang/en_US/tile.lang
index f637a568d..0d792530c 100644
--- a/game/core/src/main/resources/lang/en_US/tile.lang
+++ b/game/core/src/main/resources/lang/en_US/tile.lang
@@ -1235,4 +1235,24 @@ tile.jar.butterfly.silver.desc=A glass jar containing a silver butterfly.
 tile.statue.stone.lower.name=Stone Statue (Lower)
 tile.statue.stone.lower.desc=
 tile.statue.stone.upper.name=Stone Statue (Upper)
-tile.statue.stone.upper.desc=
\ No newline at end of file
+tile.statue.stone.upper.desc=
+tile.statue.basalt.lower.name=Basalt Statue (Lower)
+tile.statue.basalt.lower.desc=
+tile.statue.basalt.upper.name=Basalt Statue (Upper)
+tile.statue.basalt.upper.desc=
+tile.statue.limestone.lower.name=Limestone Statue (Lower)
+tile.statue.limestone.lower.desc=
+tile.statue.limestone.upper.name=Limestone Statue (Upper)
+tile.statue.limestone.upper.desc=
+tile.statue.granite.lower.name=Granite Statue (Lower)
+tile.statue.granite.lower.desc=
+tile.statue.granite.upper.name=Granite Statue (Upper)
+tile.statue.granite.upper.desc=
+tile.statue.marble.lower.name=Marble Statue (Lower)
+tile.statue.marble.lower.desc=
+tile.statue.marble.upper.name=Marble Statue (Upper)
+tile.statue.marble.upper.desc=
+tile.statue.pigman.lower.name=Pigman Statue (Lower)
+tile.statue.pigman.lower.desc=
+tile.statue.pigman.upper.name=Pigman Statue (Upper)
+tile.statue.pigman.upper.desc=
\ No newline at end of file
diff --git a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
index ae9dc15a5..f2d9785f7 100644
--- a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
+++ b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
@@ -535,64 +535,64 @@ public class PlayerServer extends Player implements ContainerListener {
     }
 
     @Override
-	public void displayFurnaceScreen(TileEntityFurnace blockEntity)
+	public void displayFurnaceScreen(TileEntityFurnace tileEntity)
     {
         getNextWindowId();
-        if (blockEntity instanceof TileEntityFurnaceBlast)
+        if (tileEntity instanceof TileEntityFurnaceBlast)
         {
-            playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_BLAST_FURNACE, blockEntity.getNameTranslationKey(), blockEntity.getContainerSize()));
+            playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_BLAST_FURNACE, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
         }
         else
         {
-            playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_FURNACE, blockEntity.getNameTranslationKey(), blockEntity.getContainerSize()));
+            playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_FURNACE, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
         }
         craftingInventory.onCraftGuiClosed(this);
-        craftingInventory = new MenuFurnace(inventory, blockEntity);
+        craftingInventory = new MenuFurnace(inventory, tileEntity);
         craftingInventory.containerId = currentWindowId;
         craftingInventory.addSlotListener(this);
     }
 
     @Override
-	public void displayDispenserScreen(TileEntityDispenser blockEntity)
+	public void displayDispenserScreen(TileEntityDispenser tileEntity)
     {
         getNextWindowId();
-        playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_DISPENSER, blockEntity.getNameTranslationKey(), blockEntity.getContainerSize()));
+        playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_DISPENSER, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
         craftingInventory.onCraftGuiClosed(this);
-        craftingInventory = new MenuTrap(inventory, blockEntity);
+        craftingInventory = new MenuTrap(inventory, tileEntity);
         craftingInventory.containerId = currentWindowId;
         craftingInventory.addSlotListener(this);
     }
 
     @Override
-    public void displayActivatorScreen(TileEntityActivator blockEntity)
+    public void displayActivatorScreen(TileEntityActivator tileEntity)
     {
         getNextWindowId();
-        playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_ACTIVATOR, blockEntity.getNameTranslationKey(), blockEntity.getContainerSize()));
+        playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_ACTIVATOR, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
         craftingInventory.onCraftGuiClosed(this);
-        craftingInventory = new MenuActivator(inventory, blockEntity);
+        craftingInventory = new MenuActivator(inventory, tileEntity);
         craftingInventory.containerId = currentWindowId;
         craftingInventory.addSlotListener(this);
     }
 
 
     @Override
-	public void displayTrommelScreen(TileEntityTrommel blockEntity)
+	public void displayTrommelScreen(TileEntityTrommel tileEntity)
     {
         getNextWindowId();
-        playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_TROMMEL, blockEntity.getNameTranslationKey(), blockEntity.getContainerSize()));
+        playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_TROMMEL, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
         craftingInventory.onCraftGuiClosed(this);
-        craftingInventory = new MenuTrommel(inventory, blockEntity);
+        craftingInventory = new MenuTrommel(inventory, tileEntity);
         craftingInventory.containerId = currentWindowId;
         craftingInventory.addSlotListener(this);
     }
 
     @Override
-    public void displayFlagEditorScreen(TileEntityFlag blockEntity)
+    public void displayFlagEditorScreen(TileEntityFlag tileEntity)
     {
         getNextWindowId();
-        playerNetServerHandler.sendPacket(new PacketFlagOpen(currentWindowId, blockEntity.x, blockEntity.y, blockEntity.z));
+        playerNetServerHandler.sendPacket(new PacketFlagOpen(currentWindowId, tileEntity.x, tileEntity.y, tileEntity.z));
         craftingInventory.onCraftGuiClosed(this);
-        craftingInventory = new MenuFlag(inventory, blockEntity);
+        craftingInventory = new MenuFlag(inventory, tileEntity);
         craftingInventory.containerId = currentWindowId;
         craftingInventory.addSlotListener(this);
     }
@@ -747,7 +747,9 @@ public class PlayerServer extends Player implements ContainerListener {
     @Override
     public void setHeldObject(@Nullable ICarriable heldObject) {
         super.setHeldObject(heldObject);
-        mcServer.getEntityTracker(dimension).sendPacketToTrackedPlayers(this, new PacketSetHeldObject(id, heldObject));
+        PacketSetHeldObject object = new PacketSetHeldObject(id, heldObject);
+        playerNetServerHandler.sendPacket(object);
+        mcServer.getEntityTracker(dimension).sendPacketToTrackedPlayers(this, object);
 
         // Ensure slot is definitely synced
         playerNetServerHandler.sendPacket(new PacketSetHotbarOffset(inventory.getHotbarOffset()));
diff --git a/game/server/src/main/java/net/minecraft/server/net/PlayerList.java b/game/server/src/main/java/net/minecraft/server/net/PlayerList.java
index 84431d4fe..d0ce6ff27 100644
--- a/game/server/src/main/java/net/minecraft/server/net/PlayerList.java
+++ b/game/server/src/main/java/net/minecraft/server/net/PlayerList.java
@@ -657,7 +657,7 @@ public class PlayerList
 
     }
 
-    public void sendBlockEntityToPlayer(int x, int y, int z, int dimension, TileEntity tileEntity)
+    public void sendTileEntityToPlayer(int x, int y, int z, int dimension, TileEntity tileEntity)
     {
         getPlayerManager(dimension).markBlockNeedsUpdate(x, y, z);
     }
diff --git a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
index 1676e3720..a0a111915 100644
--- a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
+++ b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
@@ -98,7 +98,7 @@ public class PacketHandlerServer extends PacketHandler
         WorldServer world = mcServer.getDimensionWorld(playerEntity.dimension);
         if (playerEntity.getGamemode() == Gamemode.creative && world.isBlockLoaded(packet.xPosition, packet.yPosition, packet.zPosition))
         {
-            TileEntity tileentity = world.getBlockEntity(packet.xPosition, packet.yPosition, packet.zPosition);
+            TileEntity tileentity = world.getTileEntity(packet.xPosition, packet.yPosition, packet.zPosition);
             if (tileentity instanceof TileEntityMobSpawner)
             {
                 TileEntityMobSpawner tileEntityMobSpawner = (TileEntityMobSpawner) tileentity;
@@ -111,6 +111,13 @@ public class PacketHandlerServer extends PacketHandler
         }
     }
 
+    @Override
+    public void handlePlayerConfig(PacketPlayerConfig packetPlayerConfig) {
+        playerEntity.playerConfig.config = packetPlayerConfig.config;
+        packetPlayerConfig.entityId = playerEntity.id;
+        mcServer.playerList.sendPacketToAllPlayersInDimension(packetPlayerConfig, playerEntity.dimension);
+    }
+
     @Override
     public void handleFlying(PacketMovePlayer packet)
     {
@@ -591,7 +598,7 @@ public class PacketHandlerServer extends PacketHandler
     @Override
     public void handleUseEntity(PacketInteract interactPacket)
     {
-        if (!playerEntity.getGamemode().canInteract() || !playerEntity.isAlive() || playerEntity.getHeldObject() != null /*TODO consider adding entity interactions while holding object*/) return;
+        if (!playerEntity.getGamemode().canInteract() || !playerEntity.isAlive()) return;
         WorldServer worldserver = mcServer.getDimensionWorld(playerEntity.dimension);
         Entity targetEntity = worldserver.getEntityFromId(interactPacket.targetEntityID);
         if (targetEntity != null && playerEntity.distanceToSqr(targetEntity) < 36D)
@@ -701,10 +708,10 @@ public class PacketHandlerServer extends PacketHandler
         WorldServer worldserver = mcServer.getDimensionWorld(playerEntity.dimension);
         if (worldserver.isBlockLoaded(signUpdatePacket.xPosition, signUpdatePacket.yPosition, signUpdatePacket.zPosition))
         {
-            TileEntity blockEntity = worldserver.getBlockEntity(signUpdatePacket.xPosition, signUpdatePacket.yPosition, signUpdatePacket.zPosition);
-            if (blockEntity instanceof TileEntitySign)
+            TileEntity tileEntity = worldserver.getTileEntity(signUpdatePacket.xPosition, signUpdatePacket.yPosition, signUpdatePacket.zPosition);
+            if (tileEntity instanceof TileEntitySign)
             {
-                TileEntitySign sign = (TileEntitySign) blockEntity;
+                TileEntitySign sign = (TileEntitySign) tileEntity;
                 if (!sign.isEditableBy(playerEntity))
                 {
                     LOGGER.warn("Player {} just tried to change non-editable sign", playerEntity.username);
@@ -736,18 +743,18 @@ public class PacketHandlerServer extends PacketHandler
                 }
             }
 
-            if (blockEntity instanceof TileEntitySign)
+            if (tileEntity instanceof TileEntitySign)
             {
                 int x = signUpdatePacket.xPosition;
                 int y = signUpdatePacket.yPosition;
                 int z = signUpdatePacket.zPosition;
-                TileEntitySign tileEntity = (TileEntitySign) blockEntity;
-                System.arraycopy(signUpdatePacket.signLines, 0, tileEntity.signText, 0, 4);
+                TileEntitySign sign = (TileEntitySign) tileEntity;
+                System.arraycopy(signUpdatePacket.signLines, 0, sign.signText, 0, 4);
 
-                tileEntity.setColor(TextFormatting.FORMATTINGS[signUpdatePacket.color]);
-                tileEntity.setPicture(EnumSignPicture.values()[signUpdatePacket.picture]);
+                sign.setColor(TextFormatting.FORMATTINGS[signUpdatePacket.color]);
+                sign.setPicture(EnumSignPicture.values()[signUpdatePacket.picture]);
 
-                tileEntity.setChanged();
+                sign.setChanged();
                 worldserver.markBlockNeedsUpdate(x, y, z);
             }
         }
diff --git a/game/server/src/main/java/net/minecraft/server/player/PlayerManager.java b/game/server/src/main/java/net/minecraft/server/player/PlayerManager.java
index d57432252..700807044 100644
--- a/game/server/src/main/java/net/minecraft/server/player/PlayerManager.java
+++ b/game/server/src/main/java/net/minecraft/server/player/PlayerManager.java
@@ -301,7 +301,7 @@ public class PlayerManager
                 int z = chunkZ * Chunk.CHUNK_SIZE_Z + minZ;
                 sendPacketToPlayersInInstance(new PacketBlockUpdate(x, y, z, world));
                 if (Blocks.isEntityTile[world.getBlockId(x, y, z)]) {
-                    updateTileEntity(world.getBlockEntity(x, y, z));
+                    updateTileEntity(world.getTileEntity(x, y, z));
                 }
             }
             else if(numBlocksToUpdate >= 10)
@@ -340,7 +340,7 @@ public class PlayerManager
                     int z = chunkZ * 16 + (blocksToUpdate[k] >> 4 & 0x0F);
                     if(Blocks.isEntityTile[world.getBlockId(x, y, z)])
                     {
-                        updateTileEntity(world.getBlockEntity(x, y, z));
+                        updateTileEntity(world.getTileEntity(x, y, z));
                     }
                 }
 
diff --git a/game/server/src/main/java/net/minecraft/server/world/ServerPlayerController.java b/game/server/src/main/java/net/minecraft/server/world/ServerPlayerController.java
index f4fca8d05..b2230135f 100644
--- a/game/server/src/main/java/net/minecraft/server/world/ServerPlayerController.java
+++ b/game/server/src/main/java/net/minecraft/server/world/ServerPlayerController.java
@@ -117,7 +117,7 @@ public class ServerPlayerController
     		}
     	}
         Block<?> block = Blocks.getBlock(id);
-        TileEntity tileEntity = thisWorld.getBlockEntity(x, y, z);
+        TileEntity tileEntity = thisWorld.getTileEntity(x, y, z);
         thisWorld.playBlockEvent(player, LevelListener.EVENT_BLOCK_BREAK, x, y, z, id);
         boolean flag = removeBlock(x, y, z);
         if(flag) {
@@ -167,7 +167,7 @@ public class ServerPlayerController
         int blockId = world.getBlockId(blockX, blockY, blockZ);
         if (player.getHeldObject() == null) {
             if (player.isSneaking() && itemstack == null) { // If crouched and hand empty try to pickup block entity
-                TileEntity tileEntity = world.getBlockEntity(blockX, blockY, blockZ);
+                TileEntity tileEntity = world.getTileEntity(blockX, blockY, blockZ);
                 if (tileEntity != null && tileEntity.canBeCarried(world, player)) {
                     player.setHeldObject(tileEntity.pickup(world, player));
                     return true;
diff --git a/game/server/src/main/java/net/minecraft/server/world/WorldManager.java b/game/server/src/main/java/net/minecraft/server/world/WorldManager.java
index 1690a0067..545cf873b 100644
--- a/game/server/src/main/java/net/minecraft/server/world/WorldManager.java
+++ b/game/server/src/main/java/net/minecraft/server/world/WorldManager.java
@@ -113,7 +113,7 @@ public class WorldManager
     @Override
 	public void tileEntityChanged(int x, int y, int z, TileEntity tileEntity)
     {
-        mcServer.playerList.sendBlockEntityToPlayer(x, y, z, worldServer.dimension.id, tileEntity);
+        mcServer.playerList.sendTileEntityToPlayer(x, y, z, worldServer.dimension.id, tileEntity);
     }
 
     @Override
diff --git a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
index b1f1b84ca..41383842a 100644
--- a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
+++ b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
@@ -219,7 +219,7 @@ public class WorldServer extends World
         super.tick();
 
         if (System.currentTimeMillis() - lastWeatherSend > 1000) {
-            mcServer.playerList.sendPacketToAllPlayers(new PacketWeatherStatus(dimension.id, getCurrentWeather() != null ? getCurrentWeather().weatherId : -1, weatherManager.getNextWeather() != null ? weatherManager.getNextWeather().weatherId : -1, weatherManager.getWeatherDuration(), weatherManager.getWeatherIntensity(), weatherManager.getWeatherPower()));
+            mcServer.playerList.sendPacketToAllPlayers(new PacketWeatherStatus(dimension.id, getCurrentWeather() != null ? getCurrentWeather().getId() : -1, weatherManager.getNextWeather() != null ? weatherManager.getNextWeather().getId() : -1, weatherManager.getWeatherDuration(), weatherManager.getWeatherIntensity(), weatherManager.getWeatherPower()));
             lastWeatherSend = System.currentTimeMillis();
         }
     }
diff --git a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
index 6f2b8a8c5..193e63c42 100644
--- a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
+++ b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
@@ -1,5 +1,8 @@
 package net.minecraft.datagen;
 
+import net.minecraft.core.block.Block;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.item.ItemStatue;
 import net.minecraft.datagen.recipeBuilders.RecipeBuilder;
 import net.minecraft.datagen.recipeBuilders.RecipeBuilderShaped;
 import net.minecraft.core.block.Blocks;
@@ -59,6 +62,8 @@ class WorkbenchGenerator {
 
         generateUndyeingRecipes();
 
+        generateStatueRecipes();
+
         RecipeBuilder.Shaped(CORE_NAMESPACE)
                 .setShape(
                     "CCW",
@@ -1326,4 +1331,23 @@ class WorkbenchGenerator {
         Registries.RECIPES.WORKBENCH.register(String.format(format, "wools"), new RecipeEntryUndyeing(new RecipeSymbol("minecraft:wools"), new ItemStack(Blocks.WOOL)));
         Registries.RECIPES.WORKBENCH.register(String.format(format, "chests"), new RecipeEntryUndyeing(new RecipeSymbol("minecraft:chests"), new ItemStack(Blocks.CHEST_PLANKS_OAK)));
     }
+
+    private static void generateStatueRecipes() {
+        final String[] statueNames = new String[] { "stone", "basalt", "limestone", "granite", "marble" };
+        final Item[] statueItems = new Item[ ] { Items.STATUE_STONE, Items.STATUE_BASALT, Items.STATUE_LIMESTONE, Items.STATUE_GRANITE, Items.STATUE_MARBLE };
+        final Block<?>[] statueBodyBlocks = new Block[] { Blocks.STONE, Blocks.BASALT, Blocks.LIMESTONE, Blocks.GRANITE, Blocks.MARBLE };
+        final Block<?>[] statueBaseBlocks = new Block[] { Blocks.SLAB_STONE_POLISHED, Blocks.SLAB_BASALT_POLISHED, Blocks.SLAB_LIMESTONE_POLISHED, Blocks.SLAB_GRANITE_POLISHED, Blocks.SLAB_CAPSTONE_MARBLE };
+
+        for (int i = 0; i < statueItems.length; i++) {
+            RecipeBuilder.Shaped(CORE_NAMESPACE)
+                .setShape(
+                    "#",
+                    "#",
+                    "_"
+                )
+                .addInput('#', statueBodyBlocks[i])
+                .addInput('_', statueBaseBlocks[i])
+                .create("statue_" + statueNames[i], new ItemStack(statueItems[i], 1));
+        }
+    }
 }
