diff --git a/build.gradle.kts b/build.gradle.kts
index c343d02fe..bccdb3470 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -89,6 +89,14 @@ repositories {
         }
         metadataSources { artifact() }
     }
+    ivy {
+        url = uri("https://github.com/Turnip-Labs")
+        patternLayout {
+            artifact("[organisation]/releases/download/[revision]/[module]-bta-[revision].jar")
+            m2Compatible
+        }
+        metadataSources { artifact() }
+    }
     jcenter()
 }
 
@@ -121,12 +129,7 @@ val lwjglNatives = Pair(
 }
 dependencies {
     implementation("org.jetbrains:annotations:24.0.0")?.let { clientInclude(it); serverInclude(it) }
-    implementation("com.github.Zarzelcow:legacy-lwjgl3:78643b2a96") {
-        exclude(group = "net.fabricmc")
-        exclude(group = "org.lwjgl")
-        exclude(group = "org.jetbrains.kotlin")
-        exclude(group = "org.javassist")
-    }.let { clientInclude(it) }
+    implementation("legacy-lwjgl3:legacy-lwjgl3:1.0.0")?.let { clientInclude(it) }
     implementation(platform("org.lwjgl:lwjgl-bom:$lwjglVersion"))
 
     implementation("org.lwjgl", "lwjgl")
diff --git a/src/main/java/net/minecraft/client/Minecraft.java b/src/main/java/net/minecraft/client/Minecraft.java
index d9d1eaf00..80dc10273 100644
--- a/src/main/java/net/minecraft/client/Minecraft.java
+++ b/src/main/java/net/minecraft/client/Minecraft.java
@@ -8,6 +8,7 @@ import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.io.File;
 import java.io.IOException;
+import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Comparator;
@@ -24,6 +25,7 @@ import net.minecraft.client.gui.achievements.AchievementsScreen;
 import net.minecraft.client.gui.chat.ChatScreen;
 import net.minecraft.client.gui.chat.SleepScreenMP;
 import net.minecraft.client.gui.toasts.HudToastsElement;
+import net.minecraft.client.holiday.Holidays;
 import net.minecraft.core.achievement.Achievements;
 import net.minecraft.core.net.command.util.CommandHelper;
 import net.minecraft.core.util.helper.LoggedPrintStream;
@@ -265,7 +267,6 @@ public class Minecraft
     {
     	this.gameWindow = gameWindow;
         this.resolution = new ScaledResolution(this.gameWindow);
-    	
         Global.accessor = this;
         LoggedPrintStream.wrapStreams();
         hasCrashed = false;
@@ -405,6 +406,8 @@ public class Minecraft
 
 		mcDataDir = getMinecraftDir();
 
+        Holidays.initialize();
+
         // Manually initialize blocks and items
         Blocks.init();
         Items.init();
@@ -1217,7 +1220,7 @@ public class Minecraft
                         break bridge;
                     }
                     if (stack.stackSize <= 0) {
-                        this.thePlayer.inventory.mainInventory[this.thePlayer.inventory.currentItem] = null;
+                        this.thePlayer.inventory.mainInventory[this.thePlayer.inventory.getCurrentItemIndex()] = null;
                     } else if (stack.stackSize != numItemsInStack) {
                         worldRenderer.itemRenderer.updateEquippedItem();
                     }
@@ -1261,7 +1264,9 @@ public class Minecraft
             if(clickType == 0)
             {
                 playerController.startDestroyBlock(blockX, blockY, blockZ, objectMouseOver.side, xPlaced, yPlaced, repeat);
-                playerController.swingItem(true);
+                if (thePlayer.getHeldObject() == null) {
+                    playerController.swingItem(true);
+                }
             } else
             {
                 ItemStack stack = thePlayer.inventory.getCurrentItem();
@@ -1277,7 +1282,7 @@ public class Minecraft
                 }
                 if(stack.stackSize <= 0)
                 {
-                    thePlayer.inventory.mainInventory[thePlayer.inventory.currentItem] = null;
+                    thePlayer.inventory.mainInventory[thePlayer.inventory.getCurrentItemIndex()] = null;
                 }
                 else if(stack.stackSize != numItemsInStack)
                 {
@@ -1817,15 +1822,17 @@ public class Minecraft
 
         // Hotbar switch
         if (gameSettings.keyHotBarSwitch.isPressEvent(currentInputDevice)) {
-            if (shift) {
-                thePlayer.setHotbarOffset((thePlayer.inventory.hotbarOffset + 27) % (36));
-                hotbarSwapAnimationProgress = -1.0f;
-            }
-            else {
-                thePlayer.setHotbarOffset((thePlayer.inventory.hotbarOffset + 9) % (36));
-                hotbarSwapAnimationProgress = 1.0f;
+            if (!thePlayer.inventory.currentItemLocked()) {
+                if (shift) {
+                    thePlayer.setHotbarOffset((thePlayer.inventory.getHotbarOffset() + 27) % (36));
+                    hotbarSwapAnimationProgress = -1.0f;
+                }
+                else {
+                    thePlayer.setHotbarOffset((thePlayer.inventory.getHotbarOffset() + 9) % (36));
+                    hotbarSwapAnimationProgress = 1.0f;
+                }
+                thePlayer.inventory.changeCurrentItem(0);
             }
-            thePlayer.inventory.changeCurrentItem(0);
             return true;
         }
 
@@ -1906,7 +1913,7 @@ public class Minecraft
         };
         for(int i = 0; i < hotbarSlots.length; i++) {
             if (hotbarSlots[i].isPressEvent(currentInputDevice)) {
-                thePlayer.inventory.currentItem = i + thePlayer.inventory.hotbarOffset;
+                thePlayer.inventory.setCurrentItemIndex(i + thePlayer.inventory.getHotbarOffset(), false);
                 return true;
             }
         }
@@ -1988,14 +1995,18 @@ public class Minecraft
                 displayScreen(new PauseScreen());
             }
             if(controller.digitalPad.up.pressedThisFrame()) {
-                thePlayer.setHotbarOffset((thePlayer.inventory.hotbarOffset + 27) % (36));
-                hotbarSwapAnimationProgress = -1.0f;
-                thePlayer.inventory.changeCurrentItem(0);
+                if (!thePlayer.inventory.currentItemLocked()) {
+                    thePlayer.setHotbarOffset((thePlayer.inventory.getHotbarOffset() + 27) % (36));
+                    hotbarSwapAnimationProgress = -1.0f;
+                    thePlayer.inventory.changeCurrentItem(0);
+                }
             }
             if(controller.digitalPad.down.pressedThisFrame()) {
-                thePlayer.setHotbarOffset((thePlayer.inventory.hotbarOffset + 9) % (36));
-                hotbarSwapAnimationProgress = 1.0f;
-                thePlayer.inventory.changeCurrentItem(0);
+                if (!thePlayer.inventory.currentItemLocked()) {
+                    thePlayer.setHotbarOffset((thePlayer.inventory.getHotbarOffset() + 9) % (36));
+                    hotbarSwapAnimationProgress = 1.0f;
+                    thePlayer.inventory.changeCurrentItem(0);
+                }
             }
             if(controller.digitalPad.left.pressedThisFrame() && thePlayer.getGamemode().canPlayerFly()) {
                 thePlayer.setNoclip(!thePlayer.noPhysics);
@@ -2388,19 +2399,19 @@ public class Minecraft
         return "P: " + particleEngine.countParticles() + ". T: " + theWorld.getNumLoadedEntitiesString();
     }
 
-    public void respawn(boolean flag, int i)
+    public void respawn(boolean multiplayer, int targetDimension)
     {
-    	Player previousPlayer = thePlayer;
+    	@Nullable Player previousPlayer = thePlayer;
         if(!theWorld.isClientSide && !theWorld.dimension.defaultWorldType.mayRespawn())
         {
-            usePortal(i);
+            usePortal(targetDimension);
         }
 
         ChunkCoordinates spawnCoordinates = null;
         ChunkCoordinates bedSpawnCoordinates = null;
         ChunkCoordinates lastDeathCoordinates = null;
         boolean canRespawnAtBed = true;
-        if(thePlayer != null && !flag)
+        if(thePlayer != null && !multiplayer)
         {
             spawnCoordinates = thePlayer.getPlayerSpawnCoordinate();
             lastDeathCoordinates = thePlayer.getLastDeathCoordinate();
@@ -2435,13 +2446,18 @@ public class Minecraft
             playerGamemode = thePlayer.getGamemode();
         }
         thePlayer = (LocalPlayer)playerController.createPlayer(theWorld);
-        thePlayer.dimension = i;
+        thePlayer.dimension = targetDimension;
         thePlayer.setGamemode(playerGamemode);
-        thePlayer.messageHistory = previousPlayer.messageHistory;
+        if (previousPlayer != null && previousPlayer.getHeldObject() != null) {
+            thePlayer.setHeldObject(previousPlayer.getHeldObject());
+            thePlayer.inventory.setCurrentItemIndex(previousPlayer.inventory.getCurrentItemIndex(), true);
+            thePlayer.inventory.setHotbarOffset(previousPlayer.inventory.getHotbarOffset(), true);
+        }
         activeCamera = new EntityCameraFirstPerson(this, thePlayer);
         thePlayer.resetPos();
         
         if(previousPlayer != null) {
+            thePlayer.messageHistory = previousPlayer.messageHistory;
         	if(!theWorld.isClientSide) {
         		thePlayer.inventory.transferAllContents(previousPlayer.inventory);
         	}
diff --git a/src/main/java/net/minecraft/client/entity/player/LocalPlayer.java b/src/main/java/net/minecraft/client/entity/player/LocalPlayer.java
index 745fc3481..10fa3233e 100644
--- a/src/main/java/net/minecraft/client/entity/player/LocalPlayer.java
+++ b/src/main/java/net/minecraft/client/entity/player/LocalPlayer.java
@@ -71,6 +71,7 @@ public class LocalPlayer extends Player
     public float getFovModifier() {
         float f = 1.0f;
         f *= ((speed * 1.0f) / baseSpeed + 1.0f) / 2.0f; // sprinting
+        f *= heldObject == null ? 1f : 0.8f; // Slightly decrease fov while holding carried object
         return f;
     }
 
diff --git a/src/main/java/net/minecraft/client/entity/player/RemotePlayer.java b/src/main/java/net/minecraft/client/entity/player/RemotePlayer.java
index 4e08e4566..f10f7d695 100644
--- a/src/main/java/net/minecraft/client/entity/player/RemotePlayer.java
+++ b/src/main/java/net/minecraft/client/entity/player/RemotePlayer.java
@@ -129,19 +129,19 @@ public class RemotePlayer extends Player
     }
 
     @Override
-	public void setEquippedSlot(int i, int j, int k, CompoundTag tag)
+	public void setEquippedSlot(int slot, int itemID, int itemMeta, CompoundTag tag)
     {
         ItemStack itemstack = null;
-        if(j >= 0)
+        if(itemID >= 0)
         {
-            itemstack = new ItemStack(j, 1, k, tag);
+            itemstack = new ItemStack(itemID, 1, itemMeta, tag);
         }
-        if(i == 0)
+        if(slot == 0)
         {
-            inventory.mainInventory[inventory.currentItem] = itemstack;
+            inventory.mainInventory[inventory.getCurrentItemIndex()] = itemstack;
         } else
         {
-            inventory.armorInventory[i - 1] = itemstack;
+            inventory.armorInventory[slot - 1] = itemstack;
         }
     }
 
diff --git a/src/main/java/net/minecraft/client/gui/HeldItemTooltipElement.java b/src/main/java/net/minecraft/client/gui/HeldItemTooltipElement.java
index 32e54b30f..b23d0f8b8 100644
--- a/src/main/java/net/minecraft/client/gui/HeldItemTooltipElement.java
+++ b/src/main/java/net/minecraft/client/gui/HeldItemTooltipElement.java
@@ -33,7 +33,7 @@ public class HeldItemTooltipElement extends Gui {
 			ItemStack item = mc.thePlayer.getCurrentEquippedItem();
 			
 			int id = getItemID(item);
-			int i = mc.thePlayer.inventory.currentItem;
+			int i = mc.thePlayer.inventory.getCurrentItemIndex();
 			
 			if(id != lastItemID || i != lastSelectedItem) {
 				updateString(item);
@@ -52,7 +52,7 @@ public class HeldItemTooltipElement extends Gui {
 			ItemStack item = mc.thePlayer.getCurrentEquippedItem();
 
 			int id = getItemID(item);
-			int i = mc.thePlayer.inventory.currentItem;
+			int i = mc.thePlayer.inventory.getCurrentItemIndex();
 
 			if(id != lastItemID || i != lastSelectedItem) {
 				updateString(item);
diff --git a/src/main/java/net/minecraft/client/gui/MainMenuScreen.java b/src/main/java/net/minecraft/client/gui/MainMenuScreen.java
index 4edcdc490..70e805cf0 100644
--- a/src/main/java/net/minecraft/client/gui/MainMenuScreen.java
+++ b/src/main/java/net/minecraft/client/gui/MainMenuScreen.java
@@ -18,6 +18,7 @@ import javax.imageio.ImageIO;
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.gui.hud.IngameHud;
 import net.minecraft.client.gui.hud.DoomIngameHud;
+import net.minecraft.client.holiday.Holidays;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
@@ -125,33 +126,31 @@ public class MainMenuScreen extends Screen
     {
         I18n i18n = I18n.getInstance();
 
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(new Date());
-        if (calendar.get(Calendar.MONTH) + 1 == 1 && calendar.get(Calendar.DATE) == 19)
+        if (Holidays.ANNIVERSARY_JONKADELIC.isActive())
         {
             splashText = i18n.translateKey("gui.main_menu.label.splash.jonkadelic_birthday");
         }
-        else if (calendar.get(Calendar.MONTH) + 1 == 4 && calendar.get(Calendar.DATE) == 29)
+        else if (Holidays.ANNIVERSARY_MAGGANDGEEZ.isActive())
         {
             splashText = i18n.translateKey("gui.main_menu.label.splash.maggandgeez_birthday");
         }
-        else if (calendar.get(Calendar.MONTH) + 1 == 5 && calendar.get(Calendar.DATE) == 17)
+        else if (Holidays.ANNIVERSARY_MINECRAFT.isActive())
         {
             splashText = i18n.translateKey("gui.main_menu.label.splash.minecraft_birthday");
         }
-        else if (calendar.get(Calendar.MONTH) + 1 == 7 && calendar.get(Calendar.DATE) == 20)
+        else if (Holidays.ANNIVERSARY_BTA.isActive())
         {
             splashText = i18n.translateKey("gui.main_menu.label.splash.bta_birthday");
         }
-        else if (calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DATE) == 24)
+        else if (Holidays.XMAS.isActive())
         {
             splashText = i18n.translateKey("gui.main_menu.label.splash.xmas");
         }
-        else if (calendar.get(Calendar.MONTH) + 1 == 1 && calendar.get(Calendar.DATE) == 1)
+        else if (Holidays.NEW_YEAR.isActive())
         {
             splashText = i18n.translateKey("gui.main_menu.label.splash.new_year");
         }
-        else if (calendar.get(Calendar.MONTH) + 1 == 10 && calendar.get(Calendar.DATE) == 31)
+        else if (Holidays.HALLOWEEN.isActive())
         {
             splashText = i18n.translateKey("gui.main_menu.label.splash.halloween");
         }
diff --git a/src/main/java/net/minecraft/client/gui/container/InventoryScreen.java b/src/main/java/net/minecraft/client/gui/container/InventoryScreen.java
index 656915880..3da55e4d7 100644
--- a/src/main/java/net/minecraft/client/gui/container/InventoryScreen.java
+++ b/src/main/java/net/minecraft/client/gui/container/InventoryScreen.java
@@ -264,6 +264,14 @@ public class InventoryScreen extends AbstractContainerScreen
         int j = (width - xSize) / 2;
         int k = (height - ySize) / 2;
         drawTexturedModalRect(j, k, 0, 0, xSize, ySize);
+        if (mc.thePlayer.inventory.currentItemLocked()) {
+            mc.textureManager.loadTexture("/assets/minecraft/textures/gui/sprites/slot_locked.png").bind();
+            int xOff = (18 * (mc.thePlayer.inventory.getCurrentItemIndex() % 9));
+            int hotbar = (((mc.thePlayer.inventory.getHotbarOffset() + 27) / 9) % 4);
+            int yOff = (18 * hotbar) + ((hotbar == 3) ? 4 : 0);
+            drawTexturedModalRect(j + 7 + xOff, k + 83 + yOff, 0, 0, 18, 18, 1f/18, 1f/18);
+        }
+
         GL11.glEnable(GL12.GL_RESCALE_NORMAL);
         GL11.glEnable(GL11.GL_COLOR_MATERIAL);
         GL11.glEnable(GL11.GL_DEPTH_TEST);
diff --git a/src/main/java/net/minecraft/client/gui/container/InventoryScreenCreative.java b/src/main/java/net/minecraft/client/gui/container/InventoryScreenCreative.java
index 6bf894b2a..70cb0b08e 100644
--- a/src/main/java/net/minecraft/client/gui/container/InventoryScreenCreative.java
+++ b/src/main/java/net/minecraft/client/gui/container/InventoryScreenCreative.java
@@ -183,6 +183,13 @@ public class InventoryScreenCreative extends InventoryScreen implements ITextCha
         searchField.xPosition = x + 183;
         searchField.yPosition = y + 7;
         drawTexturedModalRect((double)x, (double)y, 0, 0, xSize, ySize, xSize / 2, ySize / 2);
+		if (mc.thePlayer.inventory.currentItemLocked()) {
+			mc.textureManager.loadTexture("/assets/minecraft/textures/gui/sprites/slot_locked.png").bind();
+			int xOff = (18 * (mc.thePlayer.inventory.getCurrentItemIndex() % 9));
+			int hotbar = (((mc.thePlayer.inventory.getHotbarOffset() + 27) / 9) % 4);
+			int yOff = (18 * hotbar) + ((hotbar == 3) ? 4 : 0);
+			drawTexturedModalRect(x + 7 + xOff, y + 83 + yOff, 0, 0, 18, 18, 1f/18, 1f/18);
+		}
         GL11.glEnable(GL12.GL_RESCALE_NORMAL);
         GL11.glEnable(GL11.GL_COLOR_MATERIAL);
         GL11.glEnable(GL11.GL_DEPTH_TEST);
diff --git a/src/main/java/net/minecraft/client/gui/hud/DoomIngameHud.java b/src/main/java/net/minecraft/client/gui/hud/DoomIngameHud.java
index 73e6788cb..af5b68453 100644
--- a/src/main/java/net/minecraft/client/gui/hud/DoomIngameHud.java
+++ b/src/main/java/net/minecraft/client/gui/hud/DoomIngameHud.java
@@ -6,6 +6,7 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.opengl.GL11;
 
 import java.util.ArrayList;
@@ -88,12 +89,15 @@ public class DoomIngameHud
         mc.textureManager.loadTexture("/assets/minecraft/textures/gui/hud/doom.png").bind();
 
         // Draw main hotbar
-        drawTexturedModalRect(width / 2 - 197, height - 43, 0, 0, 197, 43);
-        drawTexturedModalRect(width / 2, height - 43, 0, 43, 197, 43);
+        drawTexturedModalRectDouble(width / 2d - 197d, height - 43, 0, 0, 197, 43, 1/256d, 1/256d, 0);
+        drawTexturedModalRectDouble(width / 2d, height - 43, 0, 43, 197, 43, 1/256d, 1/256d, 0);
 
         // Draw sides
-        drawTexturedModalRect(0d, height - 43, 0, 86, width / 2 - 197, 43, 1, 43);
-        drawTexturedModalRect(width / 2d + 197d, height - 43, 0, 86, width - (width / 2 + 197), 43, 1, 43);
+        int loops = (int) Math.ceil((((width/2d) - 197)/128));
+        for (int i = 0; i < loops; i++) {
+            drawTexturedModalRectDouble((width / 2d) - 197 - 128 * (i + 1), height - 43, 0, 86, 128, 43, 128, 43, 1/256f, 1/256f);
+            drawTexturedModalRectDouble((width / 2d) + 197d + 128 * i, height - 43, 0, 129 - 43, 128, 43, 128, 43, 1/256f, 1/256f);
+        }
     }
 
     private void drawFace()
@@ -185,7 +189,7 @@ public class DoomIngameHud
         int height = mc.resolution.getScaledHeightScreenCoords();
 
         int i = 1;
-        int activeSlot = mc.thePlayer.inventory.currentItem % 9;
+        int activeSlot = mc.thePlayer.inventory.getCurrentItemIndex() % 9;
         for (int y = 0; y < 2; y++)
         {
             for (int x = 0; x < 5; x++)
@@ -243,7 +247,7 @@ public class DoomIngameHud
         int x = width / 2 + 76;
         int y = height - 36;
 
-        int selectedHotbar = ((mc.thePlayer.inventory.hotbarOffset + 27) % 36) / 9;
+        int selectedHotbar = ((mc.thePlayer.inventory.getHotbarOffset() + 27) % 36) / 9;
 
         drawTexturedModalRect(x, y + 9 * selectedHotbar, 0, 129, 6, 6);
     }
@@ -253,8 +257,8 @@ public class DoomIngameHud
         int width = mc.resolution.getScaledWidthScreenCoords();
         int height = mc.resolution.getScaledHeightScreenCoords();
 
-        int currentItem = mc.thePlayer.inventory.currentItem;
-        int wrappedCurrentItem = mc.thePlayer.inventory.currentItem % 9;
+        int currentItem = mc.thePlayer.inventory.getCurrentItemIndex();
+        int wrappedCurrentItem = mc.thePlayer.inventory.getCurrentItemIndex() % 9;
 
         int offset = 0;
         if (wrappedCurrentItem >= 5)
diff --git a/src/main/java/net/minecraft/client/gui/hud/IngameHud.java b/src/main/java/net/minecraft/client/gui/hud/IngameHud.java
index 3229148c5..53ccc13aa 100644
--- a/src/main/java/net/minecraft/client/gui/hud/IngameHud.java
+++ b/src/main/java/net/minecraft/client/gui/hud/IngameHud.java
@@ -397,6 +397,9 @@ public class IngameHud extends Gui
                             drawDebugScreenLineRight("Light: Sky: " + mc.theWorld.getSavedLightValue(LightLayer.Sky, lightX, lightY, lightZ) + " Block: " + mc.theWorld.getSavedLightValue(LightLayer.Block, lightX, lightY, lightZ));
                         }
 
+                        drawDebugScreenLineRight("Signal: " + mc.theWorld.getSignal(mc.objectMouseOver.x, mc.objectMouseOver.y, mc.objectMouseOver.z, mc.objectMouseOver.side));
+                        drawDebugScreenLineRight("Direct signal: " + mc.theWorld.getDirectSignal(mc.objectMouseOver.x, mc.objectMouseOver.y, mc.objectMouseOver.z, mc.objectMouseOver.side));
+
                         for (Tag<Block> tag : BlockTags.TAG_LIST)
                         {
                             if (tag.appliesTo(block))
diff --git a/src/main/java/net/minecraft/client/gui/hud/component/HotbarComponent.java b/src/main/java/net/minecraft/client/gui/hud/component/HotbarComponent.java
index 6b5f56cea..435aeaabf 100644
--- a/src/main/java/net/minecraft/client/gui/hud/component/HotbarComponent.java
+++ b/src/main/java/net/minecraft/client/gui/hud/component/HotbarComponent.java
@@ -66,7 +66,7 @@ public class HotbarComponent
 
 
         // Render hotbar switcher and dots
-        int selectedHotbar = ((inv.hotbarOffset + 27) % 36) / 9;
+        int selectedHotbar = ((inv.getHotbarOffset() + 27) % 36) / 9;
         IconCoordinate coordinate = TextureRegistry.getTexture("minecraft:gui/hud/hotbar_selector");
         hud.drawIconTexture(x, y, x + 6, y + 22, 0, 0, 6, 22, coordinate);
         hud.drawIconTexture(x, y + selectedHotbar * 5, x + 6, y + selectedHotbar * 5 + 5, 6, selectedHotbar * 5, 12, selectedHotbar * 5 + 5, coordinate);
@@ -76,8 +76,8 @@ public class HotbarComponent
         GL11.glEnable(GL11.GL_BLEND);
         GL11.glEnable(GL12.GL_RESCALE_NORMAL);
         Lighting.enableInventoryLight();
-        int lastHotbarStart = (mc.thePlayer.inventory.hotbarOffset + 27) % 36;
-        int nextHotbarStart = (mc.thePlayer.inventory.hotbarOffset + 9) % 36;
+        int lastHotbarStart = (mc.thePlayer.inventory.getHotbarOffset() + 27) % 36;
+        int nextHotbarStart = (mc.thePlayer.inventory.getHotbarOffset() + 9) % 36;
 
         // Render hotbars being switched if appropriate
         if (mc.hotbarSwapAnimationProgress != 0.0f) {
@@ -115,7 +115,7 @@ public class HotbarComponent
         for (int itemIndex = 0; itemIndex < 9; itemIndex++) {
             int itemX = x + 8 + itemIndex * 20;
             int itemY = y + 3 + (int) (22 * mc.hotbarSwapAnimationProgress);
-            renderInventorySlot(mc, itemIndex + mc.thePlayer.inventory.hotbarOffset, itemX, itemY, partialTick);
+            renderInventorySlot(mc, itemIndex + mc.thePlayer.inventory.getHotbarOffset(), itemX, itemY, partialTick);
         }
 
         Scissor.disable();
@@ -125,7 +125,7 @@ public class HotbarComponent
         GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Reset color
 
         // Render selector
-        hud.drawGuiIcon((x + 4) + (inv.currentItem % 9) * 20, y - 1, 24, 24, TextureRegistry.getTexture("minecraft:gui/hud/hotbar_selection"));
+        hud.drawGuiIcon((x + 4) + (inv.getCurrentItemIndex() % 9) * 20, y - 1, 24, 24, TextureRegistry.getTexture(mc.thePlayer.getHeldObject() == null ? "minecraft:gui/hud/hotbar_selection" : "minecraft:gui/hud/hotbar_selection_locked"));
 
         hud.heldItemTooltipElement.updateAndRender(mc, x + 187/2, y - 20);
     }
diff --git a/src/main/java/net/minecraft/client/holiday/Holiday.java b/src/main/java/net/minecraft/client/holiday/Holiday.java
new file mode 100644
index 000000000..d3be6b828
--- /dev/null
+++ b/src/main/java/net/minecraft/client/holiday/Holiday.java
@@ -0,0 +1,52 @@
+package net.minecraft.client.holiday;
+
+import java.time.Month;
+import java.time.ZoneId;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class Holiday {
+    protected int month;
+    protected int day;
+    protected String resourcePath = null;
+    public Holiday(Month month, int day) {
+        this.month = month.ordinal();
+        this.day = day;
+        Holidays.allHolidays.add(this);
+    }
+
+    public Holiday setCustomResourcePath(String path) {
+        if (path == null) {
+            Holidays.allThemedHolidays.remove(this);
+        } else {
+            Holidays.allThemedHolidays.add(this);
+        }
+        this.resourcePath = path;
+        return this;
+    }
+
+    public boolean hasCustomResources() {
+        return resourcePath != null;
+    }
+
+    public String getCustomResourcesSubPath() {
+        return resourcePath;
+    }
+
+    public boolean isActive() {
+        Calendar c = getLocalCalendar();
+        return c.get(Calendar.MONTH) == month && c.get(Calendar.DAY_OF_MONTH) == day;
+    }
+
+    public static Calendar getLocalCalendar() {
+        return Calendar.getInstance(TimeZone.getTimeZone(ZoneId.systemDefault()), Locale.getDefault());
+    }
+
+    public static Date getLocalDate(int year, int month, int day) {
+        Calendar c = getLocalCalendar();
+        c.set(year, month, day);
+        return c.getTime();
+    }
+}
diff --git a/src/main/java/net/minecraft/client/holiday/Holidays.java b/src/main/java/net/minecraft/client/holiday/Holidays.java
new file mode 100644
index 000000000..d5d644783
--- /dev/null
+++ b/src/main/java/net/minecraft/client/holiday/Holidays.java
@@ -0,0 +1,36 @@
+package net.minecraft.client.holiday;
+
+import java.time.Month;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Holidays {
+    public static final List<Holiday> allHolidays = new ArrayList<>();
+    public static final List<Holiday> allThemedHolidays = new ArrayList<>();
+
+    public static final Holiday HALLOWEEN = new Holiday(Month.OCTOBER, 31).setCustomResourcePath("halloween");
+    public static final Holiday XMAS = new Holiday(Month.DECEMBER, 25).setCustomResourcePath("xmas");
+    public static final Holiday NEW_YEAR = new Holiday(Month.JANUARY, 1);
+
+    public static final Holiday ANNIVERSARY_MINECRAFT = new Holiday(Month.MAY, 17);
+    public static final Holiday ANNIVERSARY_BTA = new Holiday(Month.JULY, 20);
+
+    public static final Holiday ANNIVERSARY_JONKADELIC = new Holiday(Month.JANUARY, 19);
+    public static final Holiday ANNIVERSARY_MAGGANDGEEZ = new Holiday(Month.APRIL, 29);
+
+    private static Holiday currentThemedHoliday;
+
+    public static Holiday getCurrentThemedHoliday() {
+        return currentThemedHoliday;
+    }
+
+    public static void initialize() {
+
+        for (Holiday holiday : allThemedHolidays) {
+            if (holiday.isActive()) {
+                currentThemedHoliday = holiday;
+                break;
+            }
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/client/net/handler/ClientPacketHandler.java b/src/main/java/net/minecraft/client/net/handler/ClientPacketHandler.java
index 7c4ca71ac..32de69b52 100644
--- a/src/main/java/net/minecraft/client/net/handler/ClientPacketHandler.java
+++ b/src/main/java/net/minecraft/client/net/handler/ClientPacketHandler.java
@@ -54,6 +54,7 @@ import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.RSA;
 import net.minecraft.core.world.Explosion;
 import net.minecraft.core.world.ExplosionCannonball;
+import net.minecraft.core.world.ICarriable;
 import net.minecraft.core.world.IVehicle;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
 import net.minecraft.core.world.data.SynchedEntityData;
@@ -306,16 +307,18 @@ public class ClientPacketHandler extends PacketHandler
         int i = playerPacket.currentItem;
         if (i == 0)
         {
-            remotePlayer.inventory.mainInventory[remotePlayer.inventory.currentItem] = null;
+            remotePlayer.inventory.mainInventory[remotePlayer.inventory.getCurrentItemIndex()] = null;
         }
         else
         {
-            remotePlayer.inventory.mainInventory[remotePlayer.inventory.currentItem] = new ItemStack(i, 1, 0);
+            remotePlayer.inventory.mainInventory[remotePlayer.inventory.getCurrentItemIndex()] = new ItemStack(i, 1, 0);
         }
         remotePlayer.absMoveTo(d, d1, d2, f, f1);
         worldClient.addEntityToWorld(playerPacket.entityId, remotePlayer);
         remotePlayer.nickname = StringUtils.substring(playerPacket.nickname, 0, 32);
         remotePlayer.chatColor = playerPacket.chatColor;
+
+        remotePlayer.setHeldObject(playerPacket.heldObjectTag == null ? null : ICarriable.createAndLoadCarriable(remotePlayer, playerPacket.heldObjectTag));
     }
 
     @Override
@@ -387,6 +390,11 @@ public class ClientPacketHandler extends PacketHandler
             }
         }
     }
+    @Override
+    public void handleSetHotbarOffset(SetHotbarOffsetPacket setHotbarOffsetPacket)
+    {
+        mc.thePlayer.inventory.setHotbarOffset(setHotbarOffsetPacket.hotbarOffset, true);
+    }
 
     @Override
     public void handleDestroyEntity(RemoveEntityPacket packet29DestroyentityPacket)
@@ -982,6 +990,14 @@ public class ClientPacketHandler extends PacketHandler
         }
     }
 
+    @Override
+    public void handlePlayerHeldObject(SetHeldObjectPacket setHeldObjectPacket) {
+        Entity entity = getEntityByID(setHeldObjectPacket.entityID);
+        if (entity != null) {
+            entity.setHeldObject(setHeldObjectPacket.objectTag == null ? null : ICarriable.createAndLoadCarriable(entity, setHeldObjectPacket.objectTag));
+        }
+    }
+
     @Override
     public void handleCloseWindow(ContainerClosePacket containerClosePacket)
     {
@@ -1095,7 +1111,7 @@ public class ClientPacketHandler extends PacketHandler
     
     @Override
     public void handleBlockItemSwitch(SetCarriedItemPacket setCarriedItemPacket) {
-        mc.thePlayer.inventory.currentItem = setCarriedItemPacket.id;
+        mc.thePlayer.inventory.setCurrentItemIndex(setCarriedItemPacket.id, true);
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/client/option/VolumeOption.java b/src/main/java/net/minecraft/client/option/VolumeOption.java
index 1a1959a39..272a6c0b2 100644
--- a/src/main/java/net/minecraft/client/option/VolumeOption.java
+++ b/src/main/java/net/minecraft/client/option/VolumeOption.java
@@ -9,7 +9,8 @@ import paulscode.sound.SoundSystem;
 public class VolumeOption extends FloatOption{
 	public final SoundCategory soundCategory;
 
-	public VolumeOption(@NotNull GameSettings gameSettings, String name, float value, SoundCategory soundCategory) {
+	//do *not* add @NotNull to gameSettings here, breaks modding for some abstract reason
+	public VolumeOption(GameSettings gameSettings, String name, float value, SoundCategory soundCategory) {
 		super(gameSettings, name, value);
 		this.soundCategory = soundCategory;
 	}
diff --git a/src/main/java/net/minecraft/client/player/controller/PlayerController.java b/src/main/java/net/minecraft/client/player/controller/PlayerController.java
index 19be7b340..8859082fb 100644
--- a/src/main/java/net/minecraft/client/player/controller/PlayerController.java
+++ b/src/main/java/net/minecraft/client/player/controller/PlayerController.java
@@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.entity.player.LocalPlayer;
 import net.minecraft.core.InventoryAction;
 import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.BlockEntity;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.ArtType;
@@ -34,6 +35,7 @@ public abstract class PlayerController {
 	//Called when the mouse is clicked and about 5 times per second while the button is held down
 	//Repeat is false when the mouse was clicked this frame
 	public void startDestroyBlock(int x, int y, int z, Side side, double xHit, double yHit, boolean repeat) {
+		if (mc.thePlayer.getHeldObject() != null) return;
 		if (!mc.thePlayer.getGamemode().canInteract()) return;
 		if(!mc.thePlayer.getGamemode().doBlockBreakingAnim()) {
 			swingItem(true);
@@ -63,7 +65,7 @@ public abstract class PlayerController {
 	
 	//Called 20 times per second when the mouse button is held and blocks are targeted
 	public void continueDestroyBlock(int x, int y, int z, Side side, double xHit, double yHit) {
-		if(!mc.thePlayer.getGamemode().doBlockBreakingAnim() || !mc.thePlayer.getGamemode().canInteract()) {
+		if(!mc.thePlayer.getGamemode().doBlockBreakingAnim() || !mc.thePlayer.getGamemode().canInteract() || mc.thePlayer.getHeldObject() != null) {
 			return;
 		}
 		
@@ -144,7 +146,7 @@ public abstract class PlayerController {
 	}
 
 	public boolean destroyBlock(int x, int y, int z, Side side, Player player) {
-		if (!player.getGamemode().canInteract()) return false;
+		if (!player.getGamemode().canInteract() || mc.thePlayer.getHeldObject() != null) return false;
 		setMineBlock(null, null, null);
 		World world = mc.theWorld;
 		Block block = Block.getBlock(world.getBlockId(x, y, z));
@@ -179,7 +181,7 @@ public abstract class PlayerController {
 	}
 	
 	protected void hitBlock(int x, int y, int z, Side side, double xHit, double yHit) {
-		if (!mc.thePlayer.getGamemode().canInteract()) return;
+		if (!mc.thePlayer.getGamemode().canInteract() || mc.thePlayer.getHeldObject() != null) return;
 		mc.theWorld.onBlockHit(mc.thePlayer, x, y, z, side);
 		
 		Block block = Block.getBlock(mc.theWorld.getBlockId(x, y, z));
@@ -222,9 +224,9 @@ public abstract class PlayerController {
 		int prevStackSize = stack.stackSize;
 		ItemStack newItemStack = stack.useItemRightClick(world, player);
 		if(newItemStack != stack || newItemStack.stackSize != prevStackSize) {
-			player.inventory.mainInventory[player.inventory.currentItem] = newItemStack;
+			player.inventory.mainInventory[player.inventory.getCurrentItemIndex()] = newItemStack;
 			if(newItemStack == null || newItemStack.stackSize <= 0) {
-				player.inventory.mainInventory[player.inventory.currentItem] = null;
+				player.inventory.mainInventory[player.inventory.getCurrentItemIndex()] = null;
 			}
 			return true;
 		}
@@ -253,17 +255,38 @@ public abstract class PlayerController {
 	public boolean useItemOn(Player player, World world, ItemStack itemstack, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced)
 	{
 		if (!player.getGamemode().canInteract()) return false;
-		int i1 = world.getBlockId(blockX, blockY, blockZ);
-		if (!player.isSneaking() || player.inventory.getCurrentItem() == null) {
-			if (i1 > 0 && Block.blocksList[i1].onBlockRightClicked(world, blockX, blockY, blockZ, player, side, xPlaced, yPlaced)) {
-				return true;
+		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
+				BlockEntity blockEntity = world.getBlockEntity(blockX, blockY, blockZ);
+				if (blockEntity != null && blockEntity.canBeCarried(world, player)) {
+					player.setHeldObject(blockEntity.pickup(world, player));
+					return true;
+				}
+			}
+			if (!player.isSneaking() || itemstack == null) {  // If standing or hand empty perform block right click method
+				if (blockId > 0 && Block.blocksList[blockId].onBlockRightClicked(world, blockX, blockY, blockZ, player, side, xPlaced, yPlaced)) {
+					return true;
+				}
+			}
+			if (itemstack == null) { // No stack do nothing
+				return false;
+			} else { // Use itemstack
+				return itemstack.useItem(player, world, blockX, blockY, blockZ, side, xPlaced, yPlaced);
 			}
-		}
-		if (itemstack == null) {
-			return false;
 		} else {
-			return itemstack.useItem(player, world, blockX, blockY, blockZ, side, xPlaced, yPlaced);
+			if (!player.isSneaking()) {  // If standing or hand empty perform block right click method
+				if (blockId > 0 && Block.blocksList[blockId].onBlockRightClicked(world, blockX, blockY, blockZ, player, side, xPlaced, yPlaced)) {
+					return true;
+				}
+			}
+			boolean didPlace = player.getHeldObject().tryPlace(world, player, blockX, blockY, blockZ, side, xPlaced, yPlaced);
+			if (didPlace) {
+				player.setHeldObject(null);
+			}
+			return didPlace;
 		}
+
 	}
 
 	public Player createPlayer(World world) {
diff --git a/src/main/java/net/minecraft/client/player/controller/PlayerControllerMP.java b/src/main/java/net/minecraft/client/player/controller/PlayerControllerMP.java
index 8e9290846..3a00c9c1d 100644
--- a/src/main/java/net/minecraft/client/player/controller/PlayerControllerMP.java
+++ b/src/main/java/net/minecraft/client/player/controller/PlayerControllerMP.java
@@ -56,7 +56,7 @@ public class PlayerControllerMP extends PlayerController {
 	
 	@Override
 	protected void syncCurrentPlayItem() {
-		int i = mc.thePlayer.inventory.currentItem;
+		int i = mc.thePlayer.inventory.getCurrentItemIndex();
 		if (i != currentItem) {
 			currentItem = i;
 			netHandler.addToSendQueue(new SetCarriedItemPacket(currentItem));
diff --git a/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java b/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
index 05e609360..d4307c23b 100644
--- a/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
+++ b/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
@@ -15,7 +15,7 @@ public class PlayerControllerSP extends PlayerController {
 
 	@Override
 	public boolean destroyBlock(int x, int y, int z, Side side, Player player) {
-		if (!player.getGamemode().canInteract()) return false;
+		if (!player.getGamemode().canInteract() || mc.thePlayer.getHeldObject() != null) return false;
 		int id = mc.theWorld.getBlockId(x, y, z);
 		int meta = mc.theWorld.getBlockMetadata(x, y, z);
 		BlockEntity blockEntity = mc.theWorld.getBlockEntity(x, y, z);
diff --git a/src/main/java/net/minecraft/client/render/ItemRenderer.java b/src/main/java/net/minecraft/client/render/ItemRenderer.java
index bd88d605e..7dd27c1e0 100644
--- a/src/main/java/net/minecraft/client/render/ItemRenderer.java
+++ b/src/main/java/net/minecraft/client/render/ItemRenderer.java
@@ -89,28 +89,38 @@ public class ItemRenderer
         		brightness = mc.theWorld.getLightBrightness(MathHelper.floor(player.x), MathHelper.floor(player.y), MathHelper.floor(player.z));
         	}
             GL11.glColor4f(brightness, brightness, brightness, 1.0f);
-            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);
             EntityRenderer<? extends Entity> render = EntityRenderDispatcher.instance.getRenderer(mc.thePlayer);
-            PlayerRenderer renderplayer = (PlayerRenderer)render;
-            renderplayer.drawFirstPersonHand(mc.thePlayer, false);
+            PlayerRenderer playerRenderer = (PlayerRenderer)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);
+            } else {
+                GL11.glPushMatrix();
+                float swingProgress = player.getSwingProgress(partialTick);
+                GL11.glTranslatef(0, MathHelper.sin(swingProgress * MathHelper.PI * 2 - MathHelper.PI/2)/33f, 0); // Bounces the held object up on swing
+                GL11.glScalef(1, -1f, 1); // Flips y axis because entities are flipped vertically ig
+                GL11.glRotatef(-MathHelper.sin(swingProgress * MathHelper.PI * 2) * 5f, 1, 0, 0); // Slightly rotates the object when swung
+                playerRenderer.drawHeldObject(mc.thePlayer, partialTick);
+                GL11.glPopMatrix();
+            }
         }
         GL11.glPopMatrix();
         GL11.glDisable(GL12.GL_RESCALE_NORMAL);
@@ -273,7 +283,7 @@ public class ItemRenderer
         oHeight = height;
         LocalPlayer entityplayersp = mc.thePlayer;
         ItemStack itemstack = entityplayersp.inventory.getCurrentItem();
-        boolean flag = lastSlot == entityplayersp.inventory.currentItem && itemstack == itemToRender;
+        boolean flag = lastSlot == entityplayersp.inventory.getCurrentItemIndex() && itemstack == itemToRender;
         if(itemToRender == null && itemstack == null)
         {
             flag = true;
@@ -298,7 +308,7 @@ public class ItemRenderer
         if(height < 0.1F)
         {
             itemToRender = itemstack;
-            lastSlot = entityplayersp.inventory.currentItem;
+            lastSlot = entityplayersp.inventory.getCurrentItemIndex();
         }
     }
 
diff --git a/src/main/java/net/minecraft/client/render/block/model/RedstoneWireBlockModel.java b/src/main/java/net/minecraft/client/render/block/model/RedstoneWireBlockModel.java
index 0b7471b8c..74720ad25 100644
--- a/src/main/java/net/minecraft/client/render/block/model/RedstoneWireBlockModel.java
+++ b/src/main/java/net/minecraft/client/render/block/model/RedstoneWireBlockModel.java
@@ -51,32 +51,32 @@ public class RedstoneWireBlockModel<T extends Block> extends StandardBlockModel<
         float blue = color.getBlue() / 255.0f;
 
         tessellator.setColorOpaque_F(brightness * red, brightness * green, brightness * blue);
-        boolean west = RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x - 1, y, z, 1) || !renderBlocks.blockAccess.isBlockNormalCube(x - 1, y, z) && RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x - 1, y - 1, z, -1);
-        boolean east = RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x + 1, y, z, 3) || !renderBlocks.blockAccess.isBlockNormalCube(x + 1, y, z) && RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x + 1, y - 1, z, -1);
-        boolean north = RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x, y, z - 1, 2) || !renderBlocks.blockAccess.isBlockNormalCube(x, y, z - 1) && RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x, y - 1, z - 1, -1);
-        boolean south = RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x, y, z + 1, 0) || !renderBlocks.blockAccess.isBlockNormalCube(x, y, z + 1) && RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x, y - 1, z + 1, -1);
+        boolean west = RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x - 1, y, z, 1) || !renderBlocks.blockAccess.isBlockNormalCube(x - 1, y, z) && RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x - 1, y - 1, z, -1);
+        boolean east = RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x + 1, y, z, 3) || !renderBlocks.blockAccess.isBlockNormalCube(x + 1, y, z) && RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x + 1, y - 1, z, -1);
+        boolean north = RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x, y, z - 1, 2) || !renderBlocks.blockAccess.isBlockNormalCube(x, y, z - 1) && RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x, y - 1, z - 1, -1);
+        boolean south = RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x, y, z + 1, 0) || !renderBlocks.blockAccess.isBlockNormalCube(x, y, z + 1) && RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, 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(renderBlocks.blockAccess.isBlockNormalCube(x - 1, y, z) && RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x - 1, y + 1, z, -1))
+            if(renderBlocks.blockAccess.isBlockNormalCube(x - 1, y, z) && RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x - 1, y + 1, z, -1))
             {
                 west = true;
                 westUp = true;
             }
-            if(renderBlocks.blockAccess.isBlockNormalCube(x + 1, y, z) && RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x + 1, y + 1, z, -1))
+            if(renderBlocks.blockAccess.isBlockNormalCube(x + 1, y, z) && RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x + 1, y + 1, z, -1))
             {
                 east = true;
                 eastUp = true;
             }
-            if(renderBlocks.blockAccess.isBlockNormalCube(x, y, z - 1) && RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x, y + 1, z - 1, -1))
+            if(renderBlocks.blockAccess.isBlockNormalCube(x, y, z - 1) && RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x, y + 1, z - 1, -1))
             {
                 north = true;
                 northUp = true;
             }
-            if(renderBlocks.blockAccess.isBlockNormalCube(x, y, z + 1) && RedstoneWireBlock.isPowerProviderOrWire(renderBlocks.blockAccess, x, y + 1, z + 1, -1))
+            if(renderBlocks.blockAccess.isBlockNormalCube(x, y, z + 1) && RedstoneWireBlock.shouldConnectTo(renderBlocks.blockAccess, x, y + 1, z + 1, -1))
             {
                 south = true;
                 southUp = true;
diff --git a/src/main/java/net/minecraft/client/render/blockentity/FlagBlockEntityRenderer.java b/src/main/java/net/minecraft/client/render/blockentity/FlagBlockEntityRenderer.java
index 2fbce2cec..d8bd8d881 100644
--- a/src/main/java/net/minecraft/client/render/blockentity/FlagBlockEntityRenderer.java
+++ b/src/main/java/net/minecraft/client/render/blockentity/FlagBlockEntityRenderer.java
@@ -17,7 +17,7 @@ public class FlagBlockEntityRenderer extends BlockEntityRenderer<FlagBlockEntity
 	public final Minecraft mc = Minecraft.getMinecraft(this);
     private final FlagModel flagModel;
     private final FlagModel flagModelMirrored;
-    private FlagRenderer flagRenderer = null;
+    private static FlagRenderer flagRenderer = null;
     
     public FlagBlockEntityRenderer()
     {
@@ -42,13 +42,14 @@ public class FlagBlockEntityRenderer extends BlockEntityRenderer<FlagBlockEntity
     private long lastTick = 0;
     public void doRender(FlagBlockEntity flagBlockEntity, double x, double y, double z, float partialTick, boolean shortPole, float windDirection, float windIntensity)
     {
+        World theWorld = Minecraft.getMinecraft(this).theWorld;
         if (flagRenderer == null)
         {
             flagRenderer = new FlagRenderer(renderDispatcher.textureManager);
         }
 
-        if (flagBlockEntity.worldObj.getWorldTime() != lastTick) {
-            lastTick = flagBlockEntity.worldObj.getWorldTime();
+        if (theWorld.getWorldTime() != lastTick) {
+            lastTick = theWorld.getWorldTime();
             flagRenderer.tick();
         }
         
diff --git a/src/main/java/net/minecraft/client/render/entity/ArmoredZombieRenderer.java b/src/main/java/net/minecraft/client/render/entity/ArmoredZombieRenderer.java
index dac770d19..eaf652b09 100644
--- a/src/main/java/net/minecraft/client/render/entity/ArmoredZombieRenderer.java
+++ b/src/main/java/net/minecraft/client/render/entity/ArmoredZombieRenderer.java
@@ -24,10 +24,10 @@ public class ArmoredZombieRenderer extends BipedRenderer<ZombieArmoredMob>
         model.head.visible = renderPass == 0;
         model.hair.visible = renderPass == 0;
         model.body.visible = renderPass == 1 || renderPass == 2;
-        model.arm0.visible = renderPass == 1;
-        model.arm1.visible = renderPass == 1;
-        model.leg0.visible = renderPass == 2 || renderPass == 3;
-        model.leg1.visible = renderPass == 2 || renderPass == 3;
+        model.armRight.visible = renderPass == 1;
+        model.armLeft.visible = renderPass == 1;
+        model.legRight.visible = renderPass == 2 || renderPass == 3;
+        model.legLeft.visible = renderPass == 2 || renderPass == 3;
 
         // Disable armor pieces depending on health
         int[] armorBreakPoints = zombie.getArmorBreakPoints();
@@ -60,19 +60,19 @@ public class ArmoredZombieRenderer extends BipedRenderer<ZombieArmoredMob>
         else if (piece == 1)
         {
             modelArmorChestplate.body.visible = false;
-            modelArmorChestplate.arm1.visible = false;
-            modelArmorChestplate.arm0.visible = false;
+            modelArmorChestplate.armLeft.visible = false;
+            modelArmorChestplate.armRight.visible = false;
         }
         else if (piece == 2)
         {
             modelArmor.body.visible = false;
-            modelArmor.leg1.visible = false;
-            modelArmor.leg0.visible = false;
+            modelArmor.legLeft.visible = false;
+            modelArmor.legRight.visible = false;
         }
         else if (piece == 3)
         {
-            modelArmorChestplate.leg1.visible = false;
-            modelArmorChestplate.leg0.visible = false;
+            modelArmorChestplate.legLeft.visible = false;
+            modelArmorChestplate.legRight.visible = false;
         }
     }
 
diff --git a/src/main/java/net/minecraft/client/render/entity/BipedRenderer.java b/src/main/java/net/minecraft/client/render/entity/BipedRenderer.java
index 590cfab6e..6adaeb592 100644
--- a/src/main/java/net/minecraft/client/render/entity/BipedRenderer.java
+++ b/src/main/java/net/minecraft/client/render/entity/BipedRenderer.java
@@ -26,7 +26,7 @@ public class BipedRenderer<T extends Mob> extends MobRenderer<T>
 		ItemStack itemstack = entity.getHeldItem();
 		if(itemstack != null) {
 			GL11.glPushMatrix();
-			modelBipedMain.arm0.translateTo(0.0625F);
+			modelBipedMain.armRight.translateTo(0.0625F);
 			ItemModelDispatcher.getInstance().getDispatch(itemstack.getItem()).renderItemThirdPerson(Tessellator.instance, renderDispatcher.itemRenderer, entity, itemstack, true);
 			GL11.glPopMatrix();
 		}
diff --git a/src/main/java/net/minecraft/client/render/entity/PlayerRenderer.java b/src/main/java/net/minecraft/client/render/entity/PlayerRenderer.java
index 31d64760f..98a3097de 100644
--- a/src/main/java/net/minecraft/client/render/entity/PlayerRenderer.java
+++ b/src/main/java/net/minecraft/client/render/entity/PlayerRenderer.java
@@ -3,21 +3,28 @@ package net.minecraft.client.render.entity;
 import net.minecraft.client.Minecraft;
 
 import net.minecraft.client.entity.player.LocalPlayer;
+import net.minecraft.client.render.BlockEntityRenderDispatcher;
 import net.minecraft.client.render.Font;
+import net.minecraft.client.render.Lighting;
 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.BlockEntityRenderer;
 import net.minecraft.client.render.camera.EntityCamera;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.model.BipedModel;
 import net.minecraft.client.render.model.PlayerModel;
 import net.minecraft.client.render.model.PlayerSlimModel;
 import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.block.entity.BlockEntity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.*;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.BlocksContainer;
 import org.lwjgl.opengl.GL11;
 
 public class PlayerRenderer extends MobRenderer<Player>
@@ -28,6 +35,8 @@ public class PlayerRenderer extends MobRenderer<Player>
     private final BipedModel modelArmorChestplate;
     private final BipedModel modelArmor;
 
+    private BlocksContainer container = null;
+
     public PlayerRenderer()
     {
         super(new PlayerModel(0.0F), 0.5F);
@@ -37,14 +46,14 @@ public class PlayerRenderer extends MobRenderer<Player>
         modelThick = new PlayerModel(0.0f);
         modelSlim = new PlayerSlimModel(0.0f);
     }
-    protected void renderSpecials(Player entity, float partialTick)
+    protected void renderSpecials(Player player, float partialTick)
     {
-        if (Minecraft.getMinecraft(this).thePlayer.getGamemode() == Gamemode.spectator && entity.getGamemode() == Gamemode.spectator){
+        if (Minecraft.getMinecraft(this).thePlayer.getGamemode() == Gamemode.spectator && player.getGamemode() == Gamemode.spectator){
             GL11.glColor4f(1f, 1f, 1f, 0.25f);
-        } else if (entity.getGamemode() == Gamemode.spectator) {
+        } else if (player.getGamemode() == Gamemode.spectator) {
             GL11.glColor4f(1f, 1f, 1f, 0.0f);
         }
-        ItemStack itemstack = entity.inventory.armorItemInSlot(3);
+        ItemStack itemstack = player.inventory.armorItemInSlot(3);
         if(itemstack != null && itemstack.getItem().id < Block.blocksList.length)
         {
             GL11.glPushMatrix();
@@ -56,36 +65,36 @@ public class PlayerRenderer extends MobRenderer<Player>
                 GL11.glRotatef(180F, 0.0F, 1.0F, 0.0F);
                 GL11.glScalef(f1, -f1, f1);
             }
-            ItemModelDispatcher.getInstance().getDispatch(itemstack).renderItem(Tessellator.instance, renderDispatcher.itemRenderer, entity, itemstack);
+            ItemModelDispatcher.getInstance().getDispatch(itemstack).renderItem(Tessellator.instance, renderDispatcher.itemRenderer, player, itemstack);
             GL11.glPopMatrix();
         }
 
-        boolean renderCape = bindDownloadableTexture("https://api.betterthanadventure.net/capes?username=" + entity.username, null, null);
+        boolean renderCape = bindDownloadableTexture("https://api.betterthanadventure.net/capes?username=" + player.username, null, null);
         if (!renderCape)
         {
-            renderCape = bindDownloadableTexture(entity.capeURL, null, null);
+            renderCape = bindDownloadableTexture(player.capeURL, null, null);
         }
     	
     	if(renderCape) {
             GL11.glPushMatrix();
             GL11.glColor4f(1f, 1f, 1f, 1f);
             GL11.glTranslatef(0.0F, 0.0F, 0.125F);
-            float yawOff = entity.yBodyRotO + (entity.yBodyRot - entity.yBodyRotO) * partialTick;
+            float yawOff = player.yBodyRotO + (player.yBodyRot - player.yBodyRotO) * partialTick;
             float bodyAngle = 5;
-            if(entity.isSneaking())
+            if(player.isSneaking())
             {
                 bodyAngle += 25F;
             }
-            double _xd = entity.xdO + (entity.xd - entity.xdO) * partialTick;
-            double _yd = Math.min(entity.ydO + (entity.yd - entity.ydO) * partialTick, 0);
-            double _zd = entity.zd0 + (entity.zd - entity.zd0) * partialTick;
+            double _xd = player.xdO + (player.xd - player.xdO) * partialTick;
+            double _yd = Math.min(player.ydO + (player.yd - player.ydO) * partialTick, 0);
+            double _zd = player.zd0 + (player.zd - player.zd0) * partialTick;
             double vel = -1/(3 * Math.hypot(_xd, _zd) + 1) + 1;
             double moveAng = Math.atan2(_xd, _zd);
             double yawRad = Math.toRadians(yawOff);
             double multiplier = 1 - Math.abs((((Math.cos(yawRad) + 1) - (Math.cos(moveAng) + 1) + 2)/2) -1); // Hell code, basically measures how similar the angle you're facing is to the angle you're moving, with it returning 1 if the same angle and 0 if opposite angles
-            entity.wobbleTimer += (float) (((entity.tickCount + partialTick) - entity.lastRenderTick)/(30 - 29 * MathHelper.clamp(vel, 0, 1)));
-            entity.lastRenderTick = entity.tickCount;
-            double wobble = Math.sin(entity.wobbleTimer) * (1.5 + 4.5 * vel * multiplier);
+            player.wobbleTimer += (float) (((player.tickCount + partialTick) - player.lastRenderTick)/(30 - 29 * MathHelper.clamp(vel, 0, 1)));
+            player.lastRenderTick = player.tickCount;
+            double wobble = Math.sin(player.wobbleTimer) * (1.5 + 4.5 * vel * multiplier);
             GL11.glRotatef((float) MathHelper.clamp((MathHelper.clamp(bodyAngle + vel * 100 * multiplier, bodyAngle, 100f) + wobble) - _yd * 60, 0, 180), 1.0F, 0.0F, 0.0F);
             GL11.glRotatef(0, 0.0F, 0.0F, 1.0F);
             GL11.glRotatef(0, 0.0F, 1.0F, 0.0F);
@@ -94,14 +103,21 @@ public class PlayerRenderer extends MobRenderer<Player>
             GL11.glPopMatrix();
     	}
 
-		ItemStack itemstack1 = entity.inventory.getCurrentItem();
+		ItemStack itemstack1 = player.inventory.getCurrentItem();
 		if(itemstack1 != null) {
             GL11.glPushMatrix();
-            modelBipedMain.arm0.translateTo(0.0625F);
+            modelBipedMain.armRight.translateTo(0.0625F);
             BlockModel.setRenderBlocks(renderDispatcher.itemRenderer.renderBlocksInstance);
-            ItemModelDispatcher.getInstance().getDispatch(itemstack1).renderItemThirdPerson(Tessellator.instance, renderDispatcher.itemRenderer, entity, itemstack1, true);
+            ItemModelDispatcher.getInstance().getDispatch(itemstack1).renderItemThirdPerson(Tessellator.instance, renderDispatcher.itemRenderer, player, itemstack1, true);
             GL11.glPopMatrix();
 		}
+
+        if (player.getHeldObject() != null) {
+            float walkSpeed = player.walkAnimSpeedO + (player.walkAnimSpeed - player.walkAnimSpeedO) * partialTick;
+            float walkProgress = player.walkAnimPos - player.walkAnimSpeed * (1.0F - partialTick);
+            GL11.glTranslatef(0, MathHelper.cos(walkProgress/2 * 2/3f)/26f * walkSpeed + 0.1f, 0);
+            drawHeldObject(player, partialTick);
+        }
 	}
     public void drawFirstPersonHand(Player player, boolean isLeft)
     {
@@ -112,9 +128,9 @@ public class PlayerRenderer extends MobRenderer<Player>
         modelBipedMain.isRiding = false;
         modelBipedMain.setupAnimation(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0625F);
         if (isLeft){
-            modelBipedMain.arm1.render(0.0625F);
+            modelBipedMain.armLeft.render(0.0625F);
         } else {
-            modelBipedMain.arm0.render(0.0625F);
+            modelBipedMain.armRight.render(0.0625F);
         }
         if (modelBipedMain instanceof PlayerModel)
         {
@@ -125,6 +141,58 @@ public class PlayerRenderer extends MobRenderer<Player>
             }
         }
     }
+
+    public void drawHeldObject(Player player, float partialTick) {
+        if (player.getHeldObject() instanceof BlockEntity.CarriedBlock) {
+            BlockEntity.CarriedBlock carriedBlock = (BlockEntity.CarriedBlock)player.getHeldObject();
+            if (container == null || container.world != player.world) {
+                container = new BlocksContainer(player.world);
+            }
+
+            Tessellator tessellator = Tessellator.instance;
+            Minecraft mc = Minecraft.getMinecraft(this);
+            TextureRegistry.blockAtlas.bind();
+            GL11.glPushMatrix();
+            Lighting.disable();
+
+            GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+            GL11.glEnable(GL11.GL_BLEND);
+            GL11.glDisable(GL11.GL_CULL_FACE);
+            if(mc.isAmbientOcclusionEnabled()) {
+                GL11.glShadeModel(GL11.GL_SMOOTH);
+            } else {
+                GL11.glShadeModel(GL11.GL_FLAT);
+            }
+            GL11.glScalef(0.55f, -0.55f, 0.55f);
+            GL11.glTranslatef(0, -0.75f, -0.75f);
+
+            int blockX = MathHelper.floor(player.x);
+            int blockY = MathHelper.floor(player.y) + 1;
+            int blockZ = MathHelper.floor(player.z);
+
+            BlockModel.setRenderBlocks(new RenderBlocks(container));
+            tessellator.startDrawingQuads();
+            tessellator.setTranslation(-blockX -0.5, -blockY -0.5, -blockZ -0.5);
+
+            container.setLightReferenceEntity(player);
+            container.setBlock(blockX, blockY, blockZ, carriedBlock.block.id, carriedBlock.metadata, carriedBlock.entity);
+            BlockModelDispatcher.getInstance().getDispatch(carriedBlock.block).renderNoCulling(Tessellator.instance, blockX, blockY, blockZ);
+            tessellator.draw();
+            tessellator.setTranslation(0, 0, 0);
+            container.setLightReferenceEntity(null);
+            container.clear();
+
+            BlockEntityRenderer<BlockEntity> renderer = BlockEntityRenderDispatcher.instance.getRenderer(carriedBlock.entity);
+            if (renderer != null) {
+                carriedBlock.entity.worldObj = player.world;
+                renderer.doRender(tessellator, carriedBlock.entity, -0.5, -0.5, -0.5, partialTick);
+                carriedBlock.entity.worldObj = null;
+            }
+
+            Lighting.enableLight();
+            GL11.glPopMatrix();
+        }
+    }
     @Override
     protected void renderSpecials(Tessellator tessellator, Player entity, double d, double d1, double d2)
     {
@@ -231,8 +299,8 @@ public class PlayerRenderer extends MobRenderer<Player>
             {
                 bindTexture("/assets/minecraft/textures/armor/skates.png");
                 BipedModel bipedModel = modelArmorChestplate;
-                bipedModel.leg0.visible = layer == 2 || layer == 3;
-                bipedModel.leg1.visible = layer == 2 || layer == 3;
+                bipedModel.legRight.visible = layer == 2 || layer == 3;
+                bipedModel.legLeft.visible = layer == 2 || layer == 3;
                 setArmorModel(bipedModel);
                 return true;
             }
@@ -244,10 +312,10 @@ public class PlayerRenderer extends MobRenderer<Player>
                 bipedModel.head.visible = layer == 0;
                 bipedModel.hair.visible = layer == 0;
                 bipedModel.body.visible = layer == 1 || layer == 2;
-                bipedModel.arm0.visible = layer == 1;
-                bipedModel.arm1.visible = layer == 1;
-                bipedModel.leg0.visible = layer == 2 || layer == 3;
-                bipedModel.leg1.visible = layer == 2 || layer == 3;
+                bipedModel.armRight.visible = layer == 1;
+                bipedModel.armLeft.visible = layer == 1;
+                bipedModel.legRight.visible = layer == 2 || layer == 3;
+                bipedModel.legLeft.visible = layer == 2 || layer == 3;
                 setArmorModel(bipedModel);
                 return true;
             }
@@ -297,7 +365,11 @@ public class PlayerRenderer extends MobRenderer<Player>
         modelBipedMain = entity.slimModel ? modelSlim : modelThick;
 
         ItemStack itemstack = entity.inventory.getCurrentItem();
+        modelArmorChestplate.holdingLarge = modelArmor.holdingLarge = modelBipedMain.holdingLarge = entity.getHeldObject() != null;
+
         modelArmorChestplate.holdingRightHand = modelArmor.holdingRightHand = modelBipedMain.holdingRightHand = itemstack != null;
+        modelArmorChestplate.holdingRightHand = modelArmor.holdingRightHand = modelBipedMain.holdingRightHand |= entity.getHeldObject() != null;
+        modelArmorChestplate.holdingLeftHand = modelArmor.holdingLeftHand = modelBipedMain.holdingLeftHand |= entity.getHeldObject() != null;
         modelArmorChestplate.sneaking = modelArmor.sneaking = modelBipedMain.sneaking = entity.isSneaking();
         modelArmorChestplate.isRiding = modelArmor.isRiding = modelBipedMain.isRiding = entity.isPassenger();
         double d3 = y - (double)entity.heightOffset;
@@ -306,8 +378,10 @@ public class PlayerRenderer extends MobRenderer<Player>
             d3 -= 0.125D;
         }
         super.render(tessellator, entity, x, d3, z, yaw, partialTick);
+        modelArmorChestplate.holdingLarge = modelArmor.holdingLarge = modelBipedMain.holdingLarge = false;
         modelArmorChestplate.sneaking = modelArmor.sneaking = modelBipedMain.sneaking = false;
         modelArmorChestplate.holdingRightHand = modelArmor.holdingRightHand = modelBipedMain.holdingRightHand = false;
+        modelArmorChestplate.holdingLeftHand = modelArmor.holdingLeftHand = modelBipedMain.holdingLeftHand = false;
         GL11.glDisable(GL11.GL_BLEND);
     }
 
@@ -315,4 +389,10 @@ public class PlayerRenderer extends MobRenderer<Player>
     public void loadEntityTexture(Player entity) {
         bindDownloadableTexture(entity.skinURL, entity.getEntityTexture(), PlayerSkinParser.instance);
     }
+
+    @Override
+    protected float limbSway(Player entity, float partialTick)
+    {
+        return super.limbSway(entity, partialTick);
+    }
 }
diff --git a/src/main/java/net/minecraft/client/render/model/BipedModel.java b/src/main/java/net/minecraft/client/render/model/BipedModel.java
index 94b0b9fec..959de6707 100644
--- a/src/main/java/net/minecraft/client/render/model/BipedModel.java
+++ b/src/main/java/net/minecraft/client/render/model/BipedModel.java
@@ -11,14 +11,15 @@ public class BipedModel extends BaseModel
     public Cube head;
     public Cube hair;
     public Cube body;
-    public Cube arm0;
-    public Cube arm1;
-    public Cube leg0;
-    public Cube leg1;
+    public Cube armRight;
+    public Cube armLeft;
+    public Cube legRight;
+    public Cube legLeft;
     public Cube ear;
     public Cube cloak;
     public boolean holdingLeftHand;
     public boolean holdingRightHand;
+    public boolean holdingLarge = false;
     public boolean sneaking;
 
 
@@ -50,20 +51,20 @@ public class BipedModel extends BaseModel
         body = new Cube(16, 16);
         body.addBox(-4F, 0.0F, -2F, 8, 12, 4, expansion);
         body.setRotationPoint(0.0F, 0.0F + yRotOffset, 0.0F);
-        arm0 = new Cube(40, 16);
-        arm0.addBox(-3F, -2F, -2F, 4, 12, 4, expansion);
-        arm0.setRotationPoint(-5F, 2.0F + yRotOffset, 0.0F);
-        arm1 = new Cube(40, 16);
-        arm1.mirror = true;
-        arm1.addBox(-1F, -2F, -2F, 4, 12, 4, expansion);
-        arm1.setRotationPoint(5F, 2.0F + yRotOffset, 0.0F);
-        leg0 = new Cube(0, 16);
-        leg0.addBox(-2F, 0.0F, -2F, 4, 12, 4, expansion);
-        leg0.setRotationPoint(-2F, 12F + yRotOffset, 0.0F);
-        leg1 = new Cube(0, 16);
-        leg1.mirror = true;
-        leg1.addBox(-2F, 0.0F, -2F, 4, 12, 4, expansion);
-        leg1.setRotationPoint(2.0F, 12F + yRotOffset, 0.0F);
+        armRight = new Cube(40, 16);
+        armRight.addBox(-3F, -2F, -2F, 4, 12, 4, expansion);
+        armRight.setRotationPoint(-5F, 2.0F + yRotOffset, 0.0F);
+        armLeft = new Cube(40, 16);
+        armLeft.mirror = true;
+        armLeft.addBox(-1F, -2F, -2F, 4, 12, 4, expansion);
+        armLeft.setRotationPoint(5F, 2.0F + yRotOffset, 0.0F);
+        legRight = new Cube(0, 16);
+        legRight.addBox(-2F, 0.0F, -2F, 4, 12, 4, expansion);
+        legRight.setRotationPoint(-2F, 12F + yRotOffset, 0.0F);
+        legLeft = new Cube(0, 16);
+        legLeft.mirror = true;
+        legLeft.addBox(-2F, 0.0F, -2F, 4, 12, 4, expansion);
+        legLeft.setRotationPoint(2.0F, 12F + yRotOffset, 0.0F);
     }
 
     @Override
@@ -72,95 +73,100 @@ public class BipedModel extends BaseModel
         setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
         head.render(scale);
         body.render(scale);
-        arm0.render(scale);
-        arm1.render(scale);
-        leg0.render(scale);
-        leg1.render(scale);
+        armRight.render(scale);
+        armLeft.render(scale);
+        legRight.render(scale);
+        legLeft.render(scale);
         hair.render(scale);
     }
 
     @Override
     public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale)
     {
-        head.yRot = headYaw / 57.29578F;
-        head.xRot = headPitch / 57.29578F;
+        head.yRot = headYaw / 57.29578F; // 1 rad
+        head.xRot = headPitch / 57.29578F; // 1 rad
         hair.yRot = head.yRot;
         hair.xRot = head.xRot;
-        arm0.xRot = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 2.0F * limbYaw * 0.5F;
-        arm1.xRot = MathHelper.cos(limbSwing * 0.6662F) * 2.0F * limbYaw * 0.5F;
-        arm0.zRot = 0.0F;
-        arm1.zRot = 0.0F;
-        leg0.xRot = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw;
-        leg1.xRot = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 1.4F * limbYaw;
-        leg0.yRot = 0.0F;
-        leg1.yRot = 0.0F;
+        if (holdingLarge) {
+            armRight.xRot = MathHelper.cos(limbSwing/2 * 0.6662F) * 2.0F * limbYaw * 0.125F - 0.65f;
+            armLeft.xRot = MathHelper.cos(limbSwing/2 * 0.6662F) * 2.0F * limbYaw * 0.125F - 0.65f;
+        } else {
+            armRight.xRot = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 2.0F * limbYaw * 0.5F;
+            armLeft.xRot = MathHelper.cos(limbSwing * 0.6662F) * 2.0F * limbYaw * 0.5F;
+        }
+        armRight.zRot = 0.0F;
+        armLeft.zRot = 0.0F;
+        legRight.xRot = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw;
+        legLeft.xRot = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 1.4F * limbYaw;
+        legRight.yRot = 0.0F;
+        legLeft.yRot = 0.0F;
         if(isRiding)
         {
-            arm0.xRot += -0.6283185F;
-            arm1.xRot += -0.6283185F;
-            leg0.xRot = -1.256637F;
-            leg1.xRot = -1.256637F;
-            leg0.yRot = 0.3141593F;
-            leg1.yRot = -0.3141593F;
+            armRight.xRot += -0.6283185F; // -36 deg
+            armLeft.xRot += -0.6283185F; // -36 deg
+            legRight.xRot = -1.256637F; // -72 deg
+            legLeft.xRot = -1.256637F; // -72 deg
+            legRight.yRot = 0.3141593F; // 18 deg
+            legLeft.yRot = -0.3141593F; // -18 deg
         }
         if(holdingLeftHand)
         {
-            arm1.xRot = arm1.xRot * 0.5F - 0.3141593F;
+            armLeft.xRot = (armLeft.xRot * 0.5F) - 0.3141593F /*18 deg*/;
         }
         if(holdingRightHand)
         {
-            arm0.xRot = arm0.xRot * 0.5F - 0.3141593F;
+            armRight.xRot = (armRight.xRot * 0.5F) - 0.3141593F /*18 deg*/;
         }
-        arm0.yRot = 0.0F;
-        arm1.yRot = 0.0F;
+        armRight.yRot = 0.0F;
+        armLeft.yRot = 0.0F;
         if(onGround > -9990F)
         {
             float f6 = onGround;
             body.yRot = MathHelper.sin(MathHelper.sqrt_float(f6) * MathHelper.PI * 2.0F) * 0.2F;
-            arm0.z = MathHelper.sin(body.yRot) * 5F;
-            arm0.x = -MathHelper.cos(body.yRot) * 5F;
-            arm1.z = -MathHelper.sin(body.yRot) * 5F;
-            arm1.x = MathHelper.cos(body.yRot) * 5F;
-            arm0.yRot += body.yRot;
-            arm1.yRot += body.yRot;
-            arm1.xRot += body.yRot;
+            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;
-            arm0.xRot -= (double)f7 * 1.2D + (double)f8;
-            arm0.yRot += body.yRot * 2.0F;
-            arm0.zRot = MathHelper.sin(onGround * MathHelper.PI) * -0.4F;
+            armRight.xRot -= (double)f7 * 1.2D + (double)f8;
+            armRight.yRot += body.yRot * 2.0F;
+            armRight.zRot = MathHelper.sin(onGround * MathHelper.PI) * -0.4F;
         }
         if(sneaking)
         {
             body.xRot = 0.5F;
-            leg0.xRot -= 0.0F;
-            leg1.xRot -= 0.0F;
-            arm0.xRot += 0.4F;
-            arm1.xRot += 0.4F;
-            leg0.z = 4F;
-            leg1.z = 4F;
-            leg0.y = 9F;
-            leg1.y = 9F;
+            legRight.xRot -= 0.0F;
+            legLeft.xRot -= 0.0F;
+            armRight.xRot += 0.4F;
+            armLeft.xRot += 0.4F;
+            legRight.z = 4F;
+            legLeft.z = 4F;
+            legRight.y = 9F;
+            legLeft.y = 9F;
             head.y = 1.0F;
             hair.y = 1.0F;
         } else
         {
             body.xRot = 0.0F;
-            leg0.z = 0.0F;
-            leg1.z = 0.0F;
-            leg0.y = 12F;
-            leg1.y = 12F;
+            legRight.z = 0.0F;
+            legLeft.z = 0.0F;
+            legRight.y = 12F;
+            legLeft.y = 12F;
             head.y = 0.0F;
             hair.y = 0.0F;
         }
-        arm0.zRot += MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
-        arm1.zRot -= MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
-        arm0.xRot += MathHelper.sin(limbPitch * 0.067F) * 0.05F;
-        arm1.xRot -= MathHelper.sin(limbPitch * 0.067F) * 0.05F;
+        armRight.zRot += MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
+        armLeft.zRot -= MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
+        armRight.xRot += MathHelper.sin(limbPitch * 0.067F) * 0.05F;
+        armLeft.xRot -= MathHelper.sin(limbPitch * 0.067F) * 0.05F;
     }
 
     public void renderCloak(float scale)
diff --git a/src/main/java/net/minecraft/client/render/model/PlayerModel.java b/src/main/java/net/minecraft/client/render/model/PlayerModel.java
index da3e632f2..3cdb2183e 100644
--- a/src/main/java/net/minecraft/client/render/model/PlayerModel.java
+++ b/src/main/java/net/minecraft/client/render/model/PlayerModel.java
@@ -37,12 +37,12 @@ public class PlayerModel extends BipedModel {
         bipedBodyOverlay = new Cube(16, 32, 64, 64);
         bipedBodyOverlay.addBox(-4.0F, 0.0F, -2.0F, 8, 12, 4, expansion + 0.25F, true);
         bipedBodyOverlay.setRotationPoint(0.0F, 0.0F, 0.0F);
-        this.arm1 = new Cube(32, 48, 64, 64);
-        this.arm1.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, expansion, true);
-        this.arm1.setRotationPoint(5.0F, 2.0F, 0.0F);
-        this.leg1 = new Cube(16, 48, 64, 64);
-        this.leg1.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, expansion, true);
-        this.leg1.setRotationPoint(1.9F, 12.0F, 0.0F);
+        this.armLeft = new Cube(32, 48, 64, 64);
+        this.armLeft.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, expansion, true);
+        this.armLeft.setRotationPoint(5.0F, 2.0F, 0.0F);
+        this.legLeft = new Cube(16, 48, 64, 64);
+        this.legLeft.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, expansion, true);
+        this.legLeft.setRotationPoint(1.9F, 12.0F, 0.0F);
         head = new Cube(0, 0, 64, 64);
         head.addBox(-4F, -8F, -4F, 8, 8, 8, expansion, true);
         head.setRotationPoint(0.0F, 0.0F + yRotOffset, 0.0F);
@@ -52,12 +52,12 @@ public class PlayerModel extends BipedModel {
         body = new Cube(16, 16, 64, 64);
         body.addBox(-4F, 0.0F, -2F, 8, 12, 4, expansion, true);
         body.setRotationPoint(0.0F, 0.0F + yRotOffset, 0.0F);
-        arm0 = new Cube(40, 16, 64, 64);
-        arm0.addBox(-3F, -2F, -2F, 4, 12, 4, expansion, true);
-        arm0.setRotationPoint(-5F, 2.0F + yRotOffset, 0.0F);
-        leg0 = new Cube(0, 16, 64, 64);
-        leg0.addBox(-2F, 0.0F, -2F, 4, 12, 4, expansion, true);
-        leg0.setRotationPoint(-2F, 12F + yRotOffset, 0.0F);
+        armRight = new Cube(40, 16, 64, 64);
+        armRight.addBox(-3F, -2F, -2F, 4, 12, 4, expansion, true);
+        armRight.setRotationPoint(-5F, 2.0F + yRotOffset, 0.0F);
+        legRight = new Cube(0, 16, 64, 64);
+        legRight.addBox(-2F, 0.0F, -2F, 4, 12, 4, expansion, true);
+        legRight.setRotationPoint(-2F, 12F + yRotOffset, 0.0F);
     }
 
     @Override
@@ -75,10 +75,10 @@ public class PlayerModel extends BipedModel {
     @Override
 	public void setupAnimation(float limbSwing, float limbYaw, float limbPitch, float headYaw, float headPitch, float scale){
         super.setupAnimation(limbSwing, limbYaw, limbPitch, headYaw, headPitch, scale);
-        copyTranslation(this.leg1, this.bipedLeftLegOverlay);
-        copyTranslation(this.leg0, this.bipedRightLegOverlay);
-        copyTranslation(this.arm1, this.bipedLeftArmOverlay);
-        copyTranslation(this.arm0, this.bipedRightArmOverlay);
+        copyTranslation(this.legLeft, this.bipedLeftLegOverlay);
+        copyTranslation(this.legRight, this.bipedRightLegOverlay);
+        copyTranslation(this.armLeft, this.bipedLeftArmOverlay);
+        copyTranslation(this.armRight, this.bipedRightArmOverlay);
         copyTranslation(this.body, this.bipedBodyOverlay);
     }
 
diff --git a/src/main/java/net/minecraft/client/render/model/PlayerSlimModel.java b/src/main/java/net/minecraft/client/render/model/PlayerSlimModel.java
index 3e6238cc8..0e8645d01 100644
--- a/src/main/java/net/minecraft/client/render/model/PlayerSlimModel.java
+++ b/src/main/java/net/minecraft/client/render/model/PlayerSlimModel.java
@@ -14,12 +14,12 @@ public class PlayerSlimModel extends PlayerModel {
         bipedRightArmOverlay = new Cube(40, 32, 64, 64);
         bipedRightArmOverlay.addBox(-2.0F, -2.0F, -2.0F, 3, 12, 4, expansion + 0.25F);
         bipedRightArmOverlay.setRotationPoint(-5.0F, 2.5F, 10.0F);
-        arm1 = new Cube(32, 48, 64, 64);
-        arm1.addBox(-1.0F, -2.0F, -2.0F, 3, 12, 4, expansion);
-        arm1.setRotationPoint(5.0F, 2.5F, 0.0F);
-        arm0 = new Cube(40, 16, 64, 64);
-        arm0.addBox(-2F, -2F, -2F, 3, 12, 4, expansion);
-        arm0.setRotationPoint(-5F, 2.5F + yRotOffset, 0.0F);
+        armLeft = new Cube(32, 48, 64, 64);
+        armLeft.addBox(-1.0F, -2.0F, -2.0F, 3, 12, 4, expansion);
+        armLeft.setRotationPoint(5.0F, 2.5F, 0.0F);
+        armRight = new Cube(40, 16, 64, 64);
+        armRight.addBox(-2F, -2F, -2F, 3, 12, 4, expansion);
+        armRight.setRotationPoint(-5F, 2.5F + yRotOffset, 0.0F);
 
     }
 
diff --git a/src/main/java/net/minecraft/client/render/model/SkeletonModel.java b/src/main/java/net/minecraft/client/render/model/SkeletonModel.java
index c32dd8f07..34f3d82fb 100644
--- a/src/main/java/net/minecraft/client/render/model/SkeletonModel.java
+++ b/src/main/java/net/minecraft/client/render/model/SkeletonModel.java
@@ -10,19 +10,19 @@ public class SkeletonModel extends ZombieModel
     public SkeletonModel()
     {
         float f = 0.0F;
-        arm0 = new Cube(40, 16);
-        arm0.addBox(-1F, -2F, -1F, 2, 12, 2, f);
-        arm0.setRotationPoint(-5F, 2.0F, 0.0F);
-        arm1 = new Cube(40, 16);
-        arm1.mirror = true;
-        arm1.addBox(-1F, -2F, -1F, 2, 12, 2, f);
-        arm1.setRotationPoint(5F, 2.0F, 0.0F);
-        leg0 = new Cube(0, 16);
-        leg0.addBox(-1F, 0.0F, -1F, 2, 12, 2, f);
-        leg0.setRotationPoint(-2F, 12F, 0.0F);
-        leg1 = new Cube(0, 16);
-        leg1.mirror = true;
-        leg1.addBox(-1F, 0.0F, -1F, 2, 12, 2, f);
-        leg1.setRotationPoint(2.0F, 12F, 0.0F);
+        armRight = new Cube(40, 16);
+        armRight.addBox(-1F, -2F, -1F, 2, 12, 2, f);
+        armRight.setRotationPoint(-5F, 2.0F, 0.0F);
+        armLeft = new Cube(40, 16);
+        armLeft.mirror = true;
+        armLeft.addBox(-1F, -2F, -1F, 2, 12, 2, f);
+        armLeft.setRotationPoint(5F, 2.0F, 0.0F);
+        legRight = new Cube(0, 16);
+        legRight.addBox(-1F, 0.0F, -1F, 2, 12, 2, f);
+        legRight.setRotationPoint(-2F, 12F, 0.0F);
+        legLeft = new Cube(0, 16);
+        legLeft.mirror = true;
+        legLeft.addBox(-1F, 0.0F, -1F, 2, 12, 2, f);
+        legLeft.setRotationPoint(2.0F, 12F, 0.0F);
     }
 }
diff --git a/src/main/java/net/minecraft/client/render/model/ZombieModel.java b/src/main/java/net/minecraft/client/render/model/ZombieModel.java
index 279401957..942e0cfa8 100644
--- a/src/main/java/net/minecraft/client/render/model/ZombieModel.java
+++ b/src/main/java/net/minecraft/client/render/model/ZombieModel.java
@@ -32,20 +32,20 @@ public class ZombieModel extends BipedModel {
         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.arm0 = new Cube(40, 16);
-        this.arm0.addBox(-3.0F, -2.0F, -2.0F, 4, 12, 4, var1);
-        this.arm0.setRotationPoint(-5.0F, 2.0F + var2, 0.0F);
-        this.arm1 = new Cube(40, 16);
-        this.arm1.mirror = true;
-        this.arm1.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, var1);
-        this.arm1.setRotationPoint(5.0F, 2.0F + var2, 0.0F);
-        this.leg0 = new Cube(0, 16);
-        this.leg0.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, var1);
-        this.leg0.setRotationPoint(-2.0F, 12.0F + var2, 0.0F);
-        this.leg1 = new Cube(0, 16);
-        this.leg1.mirror = true;
-        this.leg1.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, var1);
-        this.leg1.setRotationPoint(2.0F, 12.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
@@ -53,23 +53,23 @@ public class ZombieModel extends BipedModel {
         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);
-        this.arm0.zRot = 0.0F;
-        this.arm1.zRot = 0.0F;
-        this.arm0.yRot = -(0.1F - var7 * 0.6F);
-        this.arm1.yRot = 0.1F - var7 * 0.6F;
-        this.arm0.xRot = -1.5707964F;
-        this.arm1.xRot = -1.5707964F;
-        Cube var10000 = this.arm0;
+        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.arm1;
+        var10000 = this.armLeft;
         var10000.xRot -= var7 * 1.2F - var8 * 0.4F;
-        var10000 = this.arm0;
+        var10000 = this.armRight;
         var10000.zRot += MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
-        var10000 = this.arm1;
+        var10000 = this.armLeft;
         var10000.zRot -= MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
-        var10000 = this.arm0;
+        var10000 = this.armRight;
         var10000.xRot += MathHelper.sin(limbPitch * 0.067F) * 0.05F;
-        var10000 = this.arm1;
+        var10000 = this.armLeft;
         var10000.xRot -= MathHelper.sin(limbPitch * 0.067F) * 0.05F;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/client/render/texturepack/TexturePack.java b/src/main/java/net/minecraft/client/render/texturepack/TexturePack.java
index 46d80c445..2b5b706a7 100644
--- a/src/main/java/net/minecraft/client/render/texturepack/TexturePack.java
+++ b/src/main/java/net/minecraft/client/render/texturepack/TexturePack.java
@@ -13,6 +13,7 @@ import java.util.stream.Stream;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.holiday.Holidays;
 import org.slf4j.Logger;
 
 public abstract class TexturePack {
@@ -45,6 +46,12 @@ public abstract class TexturePack {
 
 	public InputStream getResourceAsStream(String s)
 	{
+		if (Holidays.getCurrentThemedHoliday() != null) {
+			assert Holidays.getCurrentThemedHoliday().getCustomResourcesSubPath() != null : "Current themed holiday must have a theme!";
+			String holidayPath = ("/holidays/" + Holidays.getCurrentThemedHoliday().getCustomResourcesSubPath() + "/" + s);
+			InputStream holidayStream = TexturePack.class.getResourceAsStream(holidayPath);
+			if (holidayStream != null) return holidayStream;
+		}
 		return TexturePack.class.getResourceAsStream(s);
 	}
 
diff --git a/src/main/java/net/minecraft/client/render/texturepack/TexturePackCustom.java b/src/main/java/net/minecraft/client/render/texturepack/TexturePackCustom.java
index aa7b7a23c..29b80487c 100644
--- a/src/main/java/net/minecraft/client/render/texturepack/TexturePackCustom.java
+++ b/src/main/java/net/minecraft/client/render/texturepack/TexturePackCustom.java
@@ -15,6 +15,7 @@ import java.util.zip.ZipFile;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.holiday.Holidays;
 import net.minecraft.client.render.texture.BufferedTexture;
 import net.minecraft.client.render.texturepack.Manifest.ManifestException;
 import org.slf4j.Logger;
@@ -185,36 +186,47 @@ public class TexturePackCustom extends TexturePack
     @Override
 	public InputStream getResourceAsStream(String path)
     {
-    	if (file.isFile())
-    	{
+    	return getResourceAsStream(path, true);
+	}
+	private InputStream getResourceAsStream(String path, boolean firstCall)
+	{
+		if (firstCall && Holidays.getCurrentThemedHoliday() != null) {
+			assert Holidays.getCurrentThemedHoliday().getCustomResourcesSubPath() != null : "Current themed holiday must have a theme!";
+			String holidayPath = ("/holidays/" + Holidays.getCurrentThemedHoliday().getCustomResourcesSubPath() + "/" + path);
+			InputStream holidayStream = getResourceAsStream(holidayPath, false);
+			if (holidayStream != null) return holidayStream;
+		}
+
+		if (file.isFile())
+		{
 			String zipEntryPath = path;
 			if (path.startsWith("/")) zipEntryPath = path.substring(1);
-    		try
-    		{
-    			java.util.zip.ZipEntry zipentry = zipFile.getEntry(zipEntryPath);
-    			if(zipentry != null)
-    			{
-    				return zipFile.getInputStream(zipentry);
-    			}
-    		}
-    		catch(Exception ignored)
+			try
+			{
+				java.util.zip.ZipEntry zipentry = zipFile.getEntry(zipEntryPath);
+				if(zipentry != null)
+				{
+					return zipFile.getInputStream(zipentry);
+				}
+			}
+			catch(Exception ignored)
 			{
-    			return null;
+				return null;
 			}
 		}
-    	else
-    	{
-    		try
-    		{
-    			File file = new File(this.file, path);
-    			if (file.exists())
-    			{
-    				return Files.newInputStream(file.toPath());
-    			}
-    		}
-    		catch (Exception ignored)
+		else
+		{
+			try
+			{
+				File file = new File(this.file, path);
+				if (file.exists())
+				{
+					return Files.newInputStream(file.toPath());
+				}
+			}
+			catch (Exception ignored)
 			{
-    			return null;
+				return null;
 			}
 		}
 
diff --git a/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java b/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
index ae6498673..ff02b0730 100644
--- a/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
+++ b/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
@@ -2,6 +2,7 @@ package net.minecraft.client.render.texturepack;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.holiday.Holidays;
 import net.minecraft.client.render.Font;
 import net.minecraft.client.sound.SoundRepository;
 import org.jetbrains.annotations.Nullable;
@@ -30,7 +31,7 @@ public class TexturePackList
 
 	public TexturePackList(Minecraft minecraft, File file) {
 		this.mc = minecraft;
-		
+
 		texturePackDir = new File(file, "texturepacks");
 		if(!texturePackDir.exists()) {
 			texturePackDir.mkdirs();
@@ -100,9 +101,9 @@ public class TexturePackList
 
 	public boolean updateAvailableTexturePacks() {
 		List<TexturePack> currentTexturePacks = new ArrayList<>();
-		
+
 		boolean update = false;
-		
+
 		if(texturePackDir.exists() && texturePackDir.isDirectory()) {
 			File[] filesArr = texturePackDir.listFiles();
 
@@ -130,12 +131,12 @@ public class TexturePackList
 							pack.packId = id;
 							pack.readZipFile();
 							pack.readTexturePackManifest();
-							
+
 							texturePackIDs.put(id, pack);
 							pack.closeTexturePackFile();
 							update = true;
 						}
-						
+
 						TexturePack pack = texturePackIDs.get(id);
 						currentTexturePacks.add(pack);
 					}catch (IOException e) {
@@ -146,16 +147,16 @@ public class TexturePackList
 		}
 		List<TexturePack> previousTexturePacks = this.availableTexturePacks;
 		previousTexturePacks.removeAll(currentTexturePacks);
-		
+
 		if(!previousTexturePacks.isEmpty()) {
 			update = true;
 		}
-		
+
 		for(TexturePack texturePack : previousTexturePacks) {
 			texturePack.disposeOfTexturePack(mc);
 			texturePackIDs.remove(texturePack.packId);
 		}
-		
+
 		this.availableTexturePacks = currentTexturePacks;
 
 		String[] packStrings = mc.gameSettings.skin.value.split(SEPERATOR);
@@ -170,7 +171,7 @@ public class TexturePackList
 
 		return update;
 	}
-	
+
 	/**
 	 * The Texture Pack ID is needed to detect when a texture pack has been changed and the GUI needs to update
 	 */
@@ -180,11 +181,11 @@ public class TexturePackList
 		}else {
 			File manifestFile = new File(file, "manifest.json");
 			File packPngFile = new File(file, "pack.png");
-			
+
 			return file.getName() + ":" + manifestFile.length() + ":" + manifestFile.lastModified() + ":" + packPngFile.length() + ":" + packPngFile.lastModified();
 		}
 	}
-	
+
 	private boolean isTexturePack(File file) {
 		if(file.isDirectory()) {
 			return new File(file, "pack.txt").exists() || new File(file, "manifest.json").exists();
@@ -207,6 +208,9 @@ public class TexturePackList
         return defaultTexturePack;
     }
 	public InputStream getResourceAsStream(String s){
+		return getResourceAsStream(s, true);
+	}
+	private InputStream getResourceAsStream(String s, boolean firstCall) {
 		InputStream stream;
 		for (int i = selectedPacks.size() - 1; i >= 0; i--) {
 			TexturePack pack = selectedPacks.get(i);
@@ -219,8 +223,11 @@ public class TexturePackList
 		if (selectedPacks.isEmpty()) return defaultTexturePack;
 		return selectedPacks.get(selectedPacks.size()-1);
 	}
-	
+
 	public @Nullable TexturePack getHighestPriorityTexturePackWithFile(String path) {
+		return getHighestPriorityTexturePackWithFile(path, true);
+	}
+	private @Nullable TexturePack getHighestPriorityTexturePackWithFile(String path, boolean firstCall) {
 		for(int i = selectedPacks.size() - 1; i >= 0; i--) {
 			TexturePack texturePack = selectedPacks.get(i);
 			if(texturePack.hasFile(path)) {
diff --git a/src/main/java/net/minecraft/core/block/BasketBlock.java b/src/main/java/net/minecraft/core/block/BasketBlock.java
index bcd5444d5..cad26398e 100644
--- a/src/main/java/net/minecraft/core/block/BasketBlock.java
+++ b/src/main/java/net/minecraft/core/block/BasketBlock.java
@@ -58,15 +58,6 @@ public class BasketBlock extends EntityBlock
         return false;
     }
 
-    @Override
-    public void onBlockRemoved(final World world, final int x, final int y, final int z, int data)
-    {
-        final BasketBlockEntity te = (BasketBlockEntity) world.getBlockEntity(x, y, z);
-        world.removeBlockTileEntity(x, y, z);
-        if (world.isClientSide) return;
-        te.dropAllItems();
-    }
-
 
     @Override
     public boolean isSignalSource()
@@ -80,9 +71,9 @@ public class BasketBlock extends EntityBlock
         return getSignal(world, x, y, z, side);
     }
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side)
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side)
     {
-        BasketBlockEntity basketTileEntity = (BasketBlockEntity) blockAccess.getBlockEntity(x, y, z);
+        BasketBlockEntity basketTileEntity = (BasketBlockEntity) worldSource.getBlockEntity(x, y, z);
         if(basketTileEntity != null){
             return basketTileEntity.getNumUnitsInside() == basketTileEntity.getMaxUnits();
         }
diff --git a/src/main/java/net/minecraft/core/block/Block.java b/src/main/java/net/minecraft/core/block/Block.java
index 068207e88..8ec497308 100644
--- a/src/main/java/net/minecraft/core/block/Block.java
+++ b/src/main/java/net/minecraft/core/block/Block.java
@@ -184,7 +184,7 @@ public class Block
         return this.canPlaceOnSurface();
     }
 
-    public boolean renderAsNormalBlockOnCondition(World world, int x, int y, int z)
+    public boolean renderAsNormalBlockOnCondition(WorldSource world, int x, int y, int z)
     {
         return isCubeShaped();
     }
@@ -564,7 +564,10 @@ public class Block
     {
     }
 
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side)
+    /**
+     * Gets the redstone signal output by the block itself, i.e. the power it will provide to any immediately adjacent redstone components.
+     */
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side)
     {
         return false;
     }
@@ -578,6 +581,9 @@ public class Block
     {
     }
 
+    /**
+     * Gets the redstone signal pushed into adjacent solid blocks. Any block experiencing *direct* signal will power itself and all adjacent blocks.
+     */
     public boolean getDirectSignal(World world, int x, int y, int z, Side side)
     {
         return false;
diff --git a/src/main/java/net/minecraft/core/block/Blocks.java b/src/main/java/net/minecraft/core/block/Blocks.java
index 000a8528f..be800a530 100644
--- a/src/main/java/net/minecraft/core/block/Blocks.java
+++ b/src/main/java/net/minecraft/core/block/Blocks.java
@@ -964,16 +964,16 @@ public final class Blocks {
         DISPENSER_COBBLE_STONE = new DispenserBlock("dispenser.cobble.stone", "minecraft:block/dispenser_cobble_stone", 560).withSound(BlockSounds.STONE).withHardness(3.5F).withDisabledNeighborNotifyOnMetadataChange().withImmovableFlagSet()
             .withTags(BlockTags.MINEABLE_BY_PICKAXE);;
 
-        TRAPDOOR_PLANKS_OAK = new TrapDoorBlock("trapdoor.planks.oak", "minecraft:block/trapdoor_planks_oak", 570, Material.wood, false).withSound(BlockSounds.WOOD).withHardness(3F).withDisabledNeighborNotifyOnMetadataChange()
+        TRAPDOOR_PLANKS_OAK = new TrapDoorBlock("trapdoor.planks.oak", "minecraft:block/trapdoor_planks_oak", 570, Material.wood).withSound(BlockSounds.WOOD).withHardness(3F).withDisabledNeighborNotifyOnMetadataChange()
             .withTags(BlockTags.MINEABLE_BY_AXE);
-        TRAPDOOR_IRON = new TrapDoorBlock("trapdoor.iron", "minecraft:block/trapdoor_iron", 571, Material.metal, true).withSound(BlockSounds.METAL).withHardness(5F).withDisabledNeighborNotifyOnMetadataChange().withOverrideColor(MaterialColor.iron)
+        TRAPDOOR_IRON = new TrapDoorBlock("trapdoor.iron", "minecraft:block/trapdoor_iron", 571, Material.metal).withSound(BlockSounds.METAL).withHardness(5F).withDisabledNeighborNotifyOnMetadataChange().withOverrideColor(MaterialColor.iron)
             .withTags(BlockTags.MINEABLE_BY_PICKAXE);
-        TRAPDOOR_GLASS = new TrapDoorBlock("trapdoor.glass", "minecraft:block/trapdoor_glass", 572, Material.glass, false).withSound(BlockSounds.GLASS).withHardness(0.3F).withDisabledNeighborNotifyOnMetadataChange()
+        TRAPDOOR_GLASS = new TrapDoorBlock("trapdoor.glass", "minecraft:block/trapdoor_glass", 572, Material.glass).withSound(BlockSounds.GLASS).withHardness(0.3F).withDisabledNeighborNotifyOnMetadataChange()
             .withTags(BlockTags.MINEABLE_BY_PICKAXE);
         TRAPDOOR_PLANKS_PAINTED = new PaintedTrapDoorBlock("trapdoor.planks.oak.painted", "minecraft:block/trapdoor_planks_oak_painted", 573, Material.wood).withSound(BlockSounds.WOOD).withHardness(3F).withDisabledNeighborNotifyOnMetadataChange()
             .setBlockItem((b) -> new PaintedBlockItem(b, true))
             .withTags(BlockTags.MINEABLE_BY_AXE);
-        TRAPDOOR_STEEL = new TrapDoorBlock("trapdoor.steel", "minecraft:block/trapdoor_steel", 574, Material.metal, true).withSound(BlockSounds.METAL).withHardness(5F).withBlastResistance(2000F).withDisabledNeighborNotifyOnMetadataChange().withOverrideColor(MaterialColor.steel)
+        TRAPDOOR_STEEL = new TrapDoorBlock("trapdoor.steel", "minecraft:block/trapdoor_steel", 574, Material.metal).withSound(BlockSounds.METAL).withHardness(5F).withBlastResistance(2000F).withDisabledNeighborNotifyOnMetadataChange().withOverrideColor(MaterialColor.steel)
             .withTags(BlockTags.MINEABLE_BY_PICKAXE);
 
         TNT = new TNTBlock("tnt", "minecraft:block/tnt", 580).withSound(BlockSounds.GRASS).withHardness(0.0F);
diff --git a/src/main/java/net/minecraft/core/block/ButtonBlock.java b/src/main/java/net/minecraft/core/block/ButtonBlock.java
index df7864c37..dd5884682 100644
--- a/src/main/java/net/minecraft/core/block/ButtonBlock.java
+++ b/src/main/java/net/minecraft/core/block/ButtonBlock.java
@@ -278,9 +278,9 @@ public class ButtonBlock extends Block
     }
 
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side)
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side)
     {
-        return (blockAccess.getBlockMetadata(x, y, z) & 8) > 0;
+        return (worldSource.getBlockMetadata(x, y, z) & 8) > 0;
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/core/block/ChestBlock.java b/src/main/java/net/minecraft/core/block/ChestBlock.java
index ed88a7ba5..8565a79de 100644
--- a/src/main/java/net/minecraft/core/block/ChestBlock.java
+++ b/src/main/java/net/minecraft/core/block/ChestBlock.java
@@ -135,12 +135,6 @@ public class ChestBlock extends EntityBlock {
 		world.setBlockMetadata(x, y, z, meta);
 	}
 	
-	@Override
-	public void onBlockRemoved(World world, int x, int y, int z, int data) {
-		dropChestContent(world, x, y, z);
-		super.onBlockRemoved(world, x, y, z, data);
-	}
-	
 	public void checkIfOtherHalfExists(World world, int x, int y, int z) {
 		int meta = world.getBlockMetadata(x, y, z);
 		Type type = getTypeFromMeta(meta);
@@ -190,25 +184,7 @@ public class ChestBlock extends EntityBlock {
 		super.onNeighborBlockChange(world, x, y, z, blockId);
 		checkIfOtherHalfExists(world, x, y, z);
 	}
-	
-	public static void dropChestContent(World world, int x, int y, int z) {
-		ChestBlockEntity tileEntityChest = (ChestBlockEntity) world.getBlockEntity(x, y, z);
-		if(tileEntityChest == null) {
-            LOGGER.warn("Can't drop chest items because tile entity is null at x:{}, y:{}, z:{}", x, y, z);
-			return;
-		}
-		
-		for(int i = 0; i < tileEntityChest.getContainerSize(); i++) {
-			ItemStack itemStack = tileEntityChest.getItem(i);
-			if(itemStack == null) continue;
-			ItemEntity item = world.dropItem(x, y, z, itemStack);
-			item.xd *= 0.5;
-			item.yd *= 0.5;
-			item.zd *= 0.5;
-			item.pickupDelay = 0;
-		}
-	}
-	
+
 	public static boolean isChest(World world, int x, int y, int z) {
 		return Block.blocksList[world.getBlockId(x, y, z)] instanceof ChestBlock;
 	}
diff --git a/src/main/java/net/minecraft/core/block/DispenserBlock.java b/src/main/java/net/minecraft/core/block/DispenserBlock.java
index 877949a84..fd02b04f7 100644
--- a/src/main/java/net/minecraft/core/block/DispenserBlock.java
+++ b/src/main/java/net/minecraft/core/block/DispenserBlock.java
@@ -24,13 +24,9 @@ import net.minecraft.core.block.material.Material;
 
 public class DispenserBlock extends RotatableEntityBlock
 {
-    private Random random;
-
-
 	public DispenserBlock(String key, String namespaceId, int id)
     {
         super(key, namespaceId, id, Material.stone);
-        random = new Random();
     }
 
     @Override
@@ -85,8 +81,8 @@ public class DispenserBlock extends RotatableEntityBlock
             return true;
         } else
         {
-            DispenserBlockEntity tileentitydispenser = (DispenserBlockEntity)world.getBlockEntity(x, y, z);
-            player.displayDispenserScreen(tileentitydispenser);
+            DispenserBlockEntity dispenserBlockEntity = (DispenserBlockEntity)world.getBlockEntity(x, y, z);
+            player.displayDispenserScreen(dispenserBlockEntity);
             return true;
         }
     }
@@ -160,7 +156,7 @@ public class DispenserBlock extends RotatableEntityBlock
     {
         if(blockId > 0 && Block.blocksList[blockId].isSignalSource())
         {
-            boolean flag = world.isBlockIndirectlyGettingPowered(x, y, z) || world.isBlockIndirectlyGettingPowered(x, y + 1, z);
+            boolean flag = world.hasNeighborSignal(x, y, z) || world.hasNeighborSignal(x, y + 1, z);
             if(flag)
             {
                 world.scheduleBlockUpdate(x, y, z, id, tickDelay());
@@ -171,7 +167,7 @@ public class DispenserBlock extends RotatableEntityBlock
     @Override
 	public void updateTick(World world, int x, int y, int z, Random rand)
     {
-        if(world.isBlockIndirectlyGettingPowered(x, y, z) || world.isBlockIndirectlyGettingPowered(x, y + 1, z))
+        if(world.hasNeighborSignal(x, y, z) || world.hasNeighborSignal(x, y + 1, z))
         {
             dispenseItem(world, x, y, z, rand);
         }
@@ -183,39 +179,4 @@ public class DispenserBlock extends RotatableEntityBlock
         return new DispenserBlockEntity();
     }
 
-    @Override
-    public void onBlockRemoved(World world, int x, int y, int z, int data)
-    {
-        if(world.getBlockEntity(x, y, z) != null) {
-            DispenserBlockEntity tileentitydispenser = (DispenserBlockEntity) world.getBlockEntity(x, y, z);
-            label0:
-            for (int l = 0; l < tileentitydispenser.getContainerSize(); l++) {
-                ItemStack itemstack = tileentitydispenser.getItem(l);
-                if (itemstack == null) {
-                    continue;
-                }
-                float f = random.nextFloat() * 0.8F + 0.1F;
-                float f1 = random.nextFloat() * 0.8F + 0.1F;
-                float f2 = random.nextFloat() * 0.8F + 0.1F;
-                do {
-                    if (itemstack.stackSize <= 0) {
-                        continue label0;
-                    }
-                    int i1 = random.nextInt(21) + 10;
-                    if (i1 > itemstack.stackSize) {
-                        i1 = itemstack.stackSize;
-                    }
-                    itemstack.stackSize -= i1;
-                    ItemEntity entityitem = new ItemEntity(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata()));
-                    float f3 = 0.05F;
-                    entityitem.xd = (float) random.nextGaussian() * f3;
-                    entityitem.yd = (float) random.nextGaussian() * f3 + 0.2F;
-                    entityitem.zd = (float) random.nextGaussian() * f3;
-                    world.entityJoinedWorld(entityitem);
-                } while (true);
-            }
-        }
-
-        super.onBlockRemoved(world, x, y, z, data);
-    }
 }
diff --git a/src/main/java/net/minecraft/core/block/DoorBlock.java b/src/main/java/net/minecraft/core/block/DoorBlock.java
index ad251043e..e0fd691f5 100644
--- a/src/main/java/net/minecraft/core/block/DoorBlock.java
+++ b/src/main/java/net/minecraft/core/block/DoorBlock.java
@@ -3,13 +3,13 @@ package net.minecraft.core.block;
 import java.util.Random;
 import java.util.function.Supplier;
 
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.block.entity.BlockEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Item;
-import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.tag.ItemTags;
 import net.minecraft.core.util.helper.Side;
@@ -18,7 +18,6 @@ import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.LevelListener;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
-import net.minecraft.core.world.save.LevelData;
 import org.jetbrains.annotations.Nullable;
 
 // Referenced classes of package net.minecraft.src:
@@ -51,6 +50,21 @@ public class DoorBlock extends Block
         }
     }
 
+    @Override
+    public void onBlockPlacedByMob(World world, int x, int y, int z, Side side, Mob mob, double sideHeight) {
+        super.onBlockPlacedByMob(world, x, y, z, side, mob, sideHeight);
+
+        int meta = world.getBlockMetadata(x, y, z);
+        if(world.hasNeighborSignal(x, y, z)) {
+            world.setBlockMetadataWithNotify(x, y, z, meta | 4);
+            if (isTop) {
+                world.setBlockMetadataWithNotify(x, y - 1, z, meta | 4);
+            } else {
+                world.setBlockMetadataWithNotify(x, y + 1, z, meta | 4);
+            }
+        }
+    }
+
     @Override
 	public boolean isSolidRender()
     {
@@ -221,7 +235,7 @@ public class DoorBlock extends Block
             } else
             if(blockId > 0 && Block.blocksList[blockId].isSignalSource())
             {
-                boolean flag1 = world.isBlockIndirectlyGettingPowered(x, y, z) || world.isBlockIndirectlyGettingPowered(x, y + 1, z);
+                boolean flag1 = world.hasNeighborSignal(x, y, z) || world.hasNeighborSignal(x, y + 1, z);
                 onPoweredBlockChange(world, x, y, z, flag1);
             }
         }
diff --git a/src/main/java/net/minecraft/core/block/EntityBlock.java b/src/main/java/net/minecraft/core/block/EntityBlock.java
index 7625c31d5..7ca686827 100644
--- a/src/main/java/net/minecraft/core/block/EntityBlock.java
+++ b/src/main/java/net/minecraft/core/block/EntityBlock.java
@@ -28,6 +28,12 @@ public abstract class EntityBlock extends Block
     public void onBlockRemoved(World world, int x, int y, int z, int data)
     {
         super.onBlockRemoved(world, x, y, z, data);
+        if (!world.isClientSide) {
+            BlockEntity blockEntity = world.getBlockEntity(x, y, z);
+            if(blockEntity != null) {
+                blockEntity.dropContents(world, x, y, z);
+            }
+        }
         world.removeBlockTileEntity(x, y, z);
     }
 
diff --git a/src/main/java/net/minecraft/core/block/FurnaceBlock.java b/src/main/java/net/minecraft/core/block/FurnaceBlock.java
index 69c2ce2bd..c7a414eb4 100644
--- a/src/main/java/net/minecraft/core/block/FurnaceBlock.java
+++ b/src/main/java/net/minecraft/core/block/FurnaceBlock.java
@@ -11,6 +11,7 @@ import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 import java.util.Random;
@@ -27,7 +28,6 @@ public class FurnaceBlock extends RotatableEntityBlock
 	public FurnaceBlock(String key, String namespaceId, int id, boolean flag)
     {
         super(key, namespaceId, id, Material.stone);
-        furnaceRand = new Random();
         isActive = flag;
     }
 
@@ -98,7 +98,7 @@ public class FurnaceBlock extends RotatableEntityBlock
         return true;
     }
 
-	public static void updateFurnaceBlockState(boolean lit, World world, int x, int y, int z) {
+	public static void updateFurnaceBlockState(boolean lit, @NotNull World world, int x, int y, int z) {
 		int meta = world.getBlockMetadata(x, y, z);
 		BlockEntity blockEntity = world.getBlockEntity(x, y, z);
 		if(blockEntity == null) {
@@ -127,51 +127,9 @@ public class FurnaceBlock extends RotatableEntityBlock
     {
         return new FurnaceBlockEntity();
     }
-    
-    @Override
-    public void onBlockRemoved(World world, int x, int y, int z, int data)
-    {
-        if(!keepFurnaceInventory)
-        {
-            FurnaceBlockEntity tileentityfurnace = (FurnaceBlockEntity)world.getBlockEntity(x, y, z);
-label0:
-            for(int l = 0; l < tileentityfurnace.getContainerSize(); l++)
-            {
-                ItemStack itemstack = tileentityfurnace.getItem(l);
-                if(itemstack == null)
-                {
-                    continue;
-                }
-                float f = furnaceRand.nextFloat() * 0.8F + 0.1F;
-                float f1 = furnaceRand.nextFloat() * 0.8F + 0.1F;
-                float f2 = furnaceRand.nextFloat() * 0.8F + 0.1F;
-                do
-                {
-                    if(itemstack.stackSize <= 0)
-                    {
-                        continue label0;
-                    }
-                    int i1 = furnaceRand.nextInt(21) + 10;
-                    if(i1 > itemstack.stackSize)
-                    {
-                        i1 = itemstack.stackSize;
-                    }
-                    itemstack.stackSize -= i1;
-                    ItemEntity entityitem = new ItemEntity(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata()));
-                    float f3 = 0.05F;
-                    entityitem.xd = (float)furnaceRand.nextGaussian() * f3;
-                    entityitem.yd = (float)furnaceRand.nextGaussian() * f3 + 0.2F;
-                    entityitem.zd = (float)furnaceRand.nextGaussian() * f3;
-                    world.entityJoinedWorld(entityitem);
-                } while(true);
-            }
-
-        }
-        super.onBlockRemoved(world, x, y, z, data);
-    }
 
     protected Random furnaceRand;
     protected final boolean isActive;
-    protected static boolean keepFurnaceInventory = false;
+    public static boolean keepFurnaceInventory = false;
 
 }
diff --git a/src/main/java/net/minecraft/core/block/GoldMeshBlock.java b/src/main/java/net/minecraft/core/block/GoldMeshBlock.java
index 989f44716..4ab8cd9c2 100644
--- a/src/main/java/net/minecraft/core/block/GoldMeshBlock.java
+++ b/src/main/java/net/minecraft/core/block/GoldMeshBlock.java
@@ -43,22 +43,10 @@ public class GoldMeshBlock extends EntityBlock {
         boolean flag = meshGold.setFilterItem(player, heldItem);
         if(heldItem != null && heldItem.stackSize <= 0)
         {
-            player.inventory.setItem(player.inventory.currentItem, null);
+            player.inventory.setItem(player.inventory.getCurrentItemIndex(), null);
         }
         return flag;
     }
-    @Override
-    public void onBlockRemoved(World world, int x, int y, int z, int data) {
-        GoldMeshBlockEntity mesh = (GoldMeshBlockEntity) world.getBlockEntity(x, y, z);
-        if (mesh.filterItem != null){
-            ItemEntity item = world.dropItem(x, y, z, mesh.filterItem);
-            item.xd *= 0.5;
-            item.yd *= 0.5;
-            item.zd *= 0.5;
-            item.pickupDelay = 0;
-        }
-        super.onBlockRemoved(world, x, y, z, data);
-    }
 
     @Override
     public boolean collidesWithEntity(Entity entity, World world, int x, int y, int z) {
diff --git a/src/main/java/net/minecraft/core/block/JarBlock.java b/src/main/java/net/minecraft/core/block/JarBlock.java
index 82b78b608..4764f5a97 100644
--- a/src/main/java/net/minecraft/core/block/JarBlock.java
+++ b/src/main/java/net/minecraft/core/block/JarBlock.java
@@ -113,19 +113,6 @@ public class JarBlock extends EntityBlock {
         }
     }
 
-    @Override
-    public void onBlockRemoved(World world, int x, int y, int z, int data) {
-        FlowerJarBlockEntity tileEntity = (FlowerJarBlockEntity) world.getBlockEntity(x, y, z);
-        int flowerInPot = tileEntity.flowerInPot;
-        if (flowerInPot > 0 && hasTag(flowerInPot, BlockTags.PLANTABLE_IN_JAR)) {
-            tileEntity.flowerInPot = 0;
-            if (!world.isClientSide) {
-                world.dropItem(x, y, z, new ItemStack(flowerInPot, 1, 0));
-            }
-        }
-        super.onBlockRemoved(world, x, y, z, data);
-    }
-
     @Override
     public boolean isSolidRender()
     {
diff --git a/src/main/java/net/minecraft/core/block/JukeboxBlock.java b/src/main/java/net/minecraft/core/block/JukeboxBlock.java
index 6617e90d1..096fbdb3f 100644
--- a/src/main/java/net/minecraft/core/block/JukeboxBlock.java
+++ b/src/main/java/net/minecraft/core/block/JukeboxBlock.java
@@ -50,30 +50,8 @@ public class JukeboxBlock extends EntityBlock
         {
             return;
         }
-        JukeboxBlockEntity tileentityrecordplayer = (JukeboxBlockEntity)world.getBlockEntity(i, j, k);
-        int l = tileentityrecordplayer.record;
-        if (l != 0) {
-            world.playSoundEffect(1005, i, j, k, 0);
-            world.playRecord(null, null, i, j, k);
-            tileentityrecordplayer.record = 0;
-            tileentityrecordplayer.setChanged();
-            world.setBlockMetadataWithNotify(i, j, k, 0);
-            int i1 = l;
-            float f = 0.7F;
-            double d = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
-            double d1 = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.2D + 0.6D;
-            double d2 = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
-            ItemEntity entityitem = new ItemEntity(world, (double) i + d, (double) j + d1, (double) k + d2, new ItemStack(i1, 1, 0));
-            entityitem.pickupDelay = 10;
-            world.entityJoinedWorld(entityitem);
-        }
-    }
-
-    @Override
-    public void onBlockRemoved(World world, int x, int y, int z, int data)
-    {
-        ejectRecord(world, x, y, z);
-        super.onBlockRemoved(world, x, y, z, data);
+        BlockEntity blockEntity = world.getBlockEntity(i, j, k);
+        blockEntity.dropContents(world, i, j, k);
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/core/block/LampBlock.java b/src/main/java/net/minecraft/core/block/LampBlock.java
index 9b5350105..be592ae3a 100644
--- a/src/main/java/net/minecraft/core/block/LampBlock.java
+++ b/src/main/java/net/minecraft/core/block/LampBlock.java
@@ -2,59 +2,48 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.BlockEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 
-import java.util.Random;
+public class LampBlock extends Block {
+    public boolean isActive;
 
-public class LampBlock extends Block
-{
     public LampBlock(String key, String namespaceId, int id, boolean isActivated) {
         super(key, namespaceId, id, Material.stone);
         isActive = isActivated;
-        setTicking(true);
     }
 
     @Override
-    public int tickDelay()
-    {
-        return 2;
-    }
-    
-    @Override
-	public void onBlockPlacedByWorld(World world, int x, int y, int z)
-    {
-        super.onBlockPlacedByWorld(world, x, y, z);
-        world.scheduleBlockUpdate(x, y, z, id, tickDelay());
-    }
+    public void onBlockPlacedByMob(World world, int x, int y, int z, Side side, Mob mob, double sideHeight) {
+        if (world.isClientSide) {
+            return;
+        }
 
-    @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
-    {
-        boolean isPoweredByBlock = world.isBlockGettingPowered(x, y, z) || world.isBlockIndirectlyGettingPowered(x, y, z);
-        if(isActive)
-        {
-            if(!isPoweredByBlock)
-                world.setBlockAndMetadataWithNotify(x, y, z, Blocks.LAMP_IDLE.id, world.getBlockMetadata(x, y, z));
-        } else
-        if(isPoweredByBlock)
-        {
+        final boolean hasSignal = world.hasDirectSignal(x, y, z) || world.hasNeighborSignal(x, y, z);
+
+        if (hasSignal && !isActive) {
             world.setBlockAndMetadataWithNotify(x, y, z, Blocks.LAMP_ACTIVE.id, world.getBlockMetadata(x, y, z));
+        } else if (!hasSignal && isActive) {
+            world.setBlockAndMetadataWithNotify(x, y, z, Blocks.LAMP_IDLE.id, world.getBlockMetadata(x, y, z));
         }
     }
 
     @Override
-	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId)
-    {
-        world.scheduleBlockUpdate(x, y, z, id, tickDelay());
+    public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
+        final boolean hasSignal = world.hasDirectSignal(x, y, z) || world.hasNeighborSignal(x, y, z);
+
+        if (hasSignal && !isActive) {
+            world.setBlockAndMetadataWithNotify(x, y, z, Blocks.LAMP_ACTIVE.id, world.getBlockMetadata(x, y, z));
+        } else if (!hasSignal && isActive) {
+            world.setBlockAndMetadataWithNotify(x, y, z, Blocks.LAMP_IDLE.id, world.getBlockMetadata(x, y, z));
+        }
     }
 
     @Override
-    public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int x, int y, int z, int meta, BlockEntity blockEntity)
-    {
-        return new ItemStack[] { new ItemStack(Blocks.LAMP_IDLE, 1, meta) };
+    public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int x, int y, int z, int meta, BlockEntity blockEntity) {
+        return new ItemStack[]{new ItemStack(Blocks.LAMP_IDLE, 1, meta)};
     }
-
-    public boolean isActive;
 }
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/block/LegacyChestBlock.java b/src/main/java/net/minecraft/core/block/LegacyChestBlock.java
index ee4ad0fe7..83b7b936d 100644
--- a/src/main/java/net/minecraft/core/block/LegacyChestBlock.java
+++ b/src/main/java/net/minecraft/core/block/LegacyChestBlock.java
@@ -43,7 +43,10 @@ public class LegacyChestBlock extends EntityBlock {
 	
 	@Override
 	public void onBlockRemoved(World world, int x, int y, int z, int data) {
-		ChestBlock.dropChestContent(world, x, y, z);
+		BlockEntity entity = world.getBlockEntity(x, y, z);
+		if (entity != null) {
+			entity.dropContents(world, x, y, z);
+		}
 		super.onBlockRemoved(world, x, y, z, data);
 	}
 	
diff --git a/src/main/java/net/minecraft/core/block/MotionSensorBlock.java b/src/main/java/net/minecraft/core/block/MotionSensorBlock.java
index 027013f01..8d8c53c39 100644
--- a/src/main/java/net/minecraft/core/block/MotionSensorBlock.java
+++ b/src/main/java/net/minecraft/core/block/MotionSensorBlock.java
@@ -99,7 +99,7 @@ public class MotionSensorBlock extends RotatableEntityBlock
         return getSignal(world, x, y, z, side);
     }
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side)
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side)
     {
         return isActive;
     }
diff --git a/src/main/java/net/minecraft/core/block/NoteBlock.java b/src/main/java/net/minecraft/core/block/NoteBlock.java
index 3ae00756d..e82d6bd7f 100644
--- a/src/main/java/net/minecraft/core/block/NoteBlock.java
+++ b/src/main/java/net/minecraft/core/block/NoteBlock.java
@@ -21,7 +21,7 @@ public class NoteBlock extends EntityBlock
     {
         if(blockId > 0 && Block.blocksList[blockId].isSignalSource())
         {
-            boolean flag = world.isBlockGettingPowered(x, y, z);
+            boolean flag = world.hasDirectSignal(x, y, z);
             NoteBlockEntity tileentitynote = (NoteBlockEntity)world.getBlockEntity(x, y, z);
             if(tileentitynote.previousRedstoneState != flag)
             {
diff --git a/src/main/java/net/minecraft/core/block/PaintedTrapDoorBlock.java b/src/main/java/net/minecraft/core/block/PaintedTrapDoorBlock.java
index c469ff609..8df5e8b66 100644
--- a/src/main/java/net/minecraft/core/block/PaintedTrapDoorBlock.java
+++ b/src/main/java/net/minecraft/core/block/PaintedTrapDoorBlock.java
@@ -10,7 +10,7 @@ import net.minecraft.core.world.World;
 
 public class PaintedTrapDoorBlock extends TrapDoorBlock {
     public PaintedTrapDoorBlock(String key, String namespaceId, int id, Material material) {
-        super(key, namespaceId, id, material, false);
+        super(key, namespaceId, id, material);
     }
     
     @Override
diff --git a/src/main/java/net/minecraft/core/block/PortalBlock.java b/src/main/java/net/minecraft/core/block/PortalBlock.java
index 85de42374..84bcb5825 100644
--- a/src/main/java/net/minecraft/core/block/PortalBlock.java
+++ b/src/main/java/net/minecraft/core/block/PortalBlock.java
@@ -265,7 +265,7 @@ public class PortalBlock extends TransparentBlock
         y = bounds[2];
         z = bounds[3];
 
-        world.editingBlocks = true;
+        world.noNeighborUpdate = true;
         for(int ra = 1; ra < bounds[4]; ra++)
         {
             for(int ry = 1; ry < bounds[5]; ry++)
@@ -279,7 +279,7 @@ public class PortalBlock extends TransparentBlock
         
         world.markBlocksDirty(x + (bounds[0] == 0 ? 1 : 0), y + 1, z + (bounds[0] == 1 ? 1 : 0), x + (bounds[0] == 0 ? bounds[4] : 0), y + bounds[5], z + (bounds[0] == 1 ? bounds[4] : 0));
 
-        world.editingBlocks = false;
+        world.noNeighborUpdate = false;
         return true;
     }
 
diff --git a/src/main/java/net/minecraft/core/block/PressurePlateBlock.java b/src/main/java/net/minecraft/core/block/PressurePlateBlock.java
index 8331bf503..4b790392b 100644
--- a/src/main/java/net/minecraft/core/block/PressurePlateBlock.java
+++ b/src/main/java/net/minecraft/core/block/PressurePlateBlock.java
@@ -162,10 +162,10 @@ public class PressurePlateBlock extends Block
     }
 
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side)
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side)
     {
 
-        return isPressed(blockAccess.getBlockMetadata(x, y, z));
+        return isPressed(worldSource.getBlockMetadata(x, y, z));
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/core/block/RailBlock.java b/src/main/java/net/minecraft/core/block/RailBlock.java
index 74b5d5e29..d0749b316 100644
--- a/src/main/java/net/minecraft/core/block/RailBlock.java
+++ b/src/main/java/net/minecraft/core/block/RailBlock.java
@@ -103,8 +103,8 @@ public class RailBlock extends Block {
 
         if(this == Blocks.RAIL_POWERED) {
             boolean gettingPower =
-                    world.isBlockIndirectlyGettingPowered(x, y, z) ||
-                    world.isBlockIndirectlyGettingPowered(x, y + 1, z) ||
+                    world.hasNeighborSignal(x, y, z) ||
+                    world.hasNeighborSignal(x, y + 1, z) ||
                     isConnectedPoweredRail1(world, x, y, z, true, 0) ||
                     isConnectedPoweredRail1(world, x, y, z, false, 0);
 
@@ -150,7 +150,7 @@ public class RailBlock extends Block {
 
     private void performRailTurn(World world, int x, int y, int z, boolean forceUpdate) {
         if (!world.isClientSide) {
-            new Rail(world, x, y, z).railTurn(world.isBlockIndirectlyGettingPowered(x, y, z), forceUpdate);
+            new Rail(world, x, y, z).railTurn(world.hasNeighborSignal(x, y, z), forceUpdate);
         }
     }
 
@@ -217,7 +217,7 @@ public class RailBlock extends Block {
 
             if(isPoweredFlagSet) {
                 // If rail powered return true
-                if(world.isBlockIndirectlyGettingPowered(x, y, z) || world.isBlockIndirectlyGettingPowered(x, y + 1, z)) {
+                if(world.hasNeighborSignal(x, y, z) || world.hasNeighborSignal(x, y + 1, z)) {
                     return true;
                 } else { // else check 1 block further down if powered
                     return isConnectedPoweredRail1(world, x, y, z, forward, distance + 1);
diff --git a/src/main/java/net/minecraft/core/block/RedstoneBlock.java b/src/main/java/net/minecraft/core/block/RedstoneBlock.java
index 89a15b9f1..126ffeb1c 100644
--- a/src/main/java/net/minecraft/core/block/RedstoneBlock.java
+++ b/src/main/java/net/minecraft/core/block/RedstoneBlock.java
@@ -23,7 +23,7 @@ public class RedstoneBlock extends Block
     }
 	
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side)
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side)
     {
     	return true;
     }
@@ -31,7 +31,7 @@ public class RedstoneBlock extends Block
     @Override
     public boolean getDirectSignal(World world, int x, int y, int z, Side side)
     {
-        return getSignal(world, x, y, z, side);
+        return false;
     }
     
     @Override
diff --git a/src/main/java/net/minecraft/core/block/RedstonePumpkinBlock.java b/src/main/java/net/minecraft/core/block/RedstonePumpkinBlock.java
index 6d64c8580..35c3d21ca 100644
--- a/src/main/java/net/minecraft/core/block/RedstonePumpkinBlock.java
+++ b/src/main/java/net/minecraft/core/block/RedstonePumpkinBlock.java
@@ -29,15 +29,15 @@ public class RedstonePumpkinBlock extends RotatableBlock {
 
     @Override
     public boolean getDirectSignal(World world, int x, int y, int z, Side side) {
-        return getSignal(world, x, y, z, side);
+        return getSignal(world, x, y, z, side.getOpposite());
     }
 
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side) {
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side) {
         if (!side.isHorizontal()) {
             return false;
         }
-        Side mySide = Side.getSideById(blockAccess.getBlockMetadata(x, y, z));
+        Side mySide = Side.getSideById(worldSource.getBlockMetadata(x, y, z));
         return mySide == side.getOpposite();
     }
 }
diff --git a/src/main/java/net/minecraft/core/block/RedstoneTorchBlock.java b/src/main/java/net/minecraft/core/block/RedstoneTorchBlock.java
index a721200fa..a683353bc 100644
--- a/src/main/java/net/minecraft/core/block/RedstoneTorchBlock.java
+++ b/src/main/java/net/minecraft/core/block/RedstoneTorchBlock.java
@@ -4,41 +4,33 @@ import net.minecraft.client.util.helper.Colors;
 import net.minecraft.core.block.entity.BlockEntity;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
-import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.Color;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Random;
 
-// Referenced classes of package net.minecraft.src:
-//            TorchBlock, Block, RedstoneUpdateInfo, World,
-//            IBlockAccess
+public class RedstoneTorchBlock extends TorchBlock {
+    private final boolean torchActive;
 
-public class RedstoneTorchBlock extends TorchBlock
-{
-    protected RedstoneTorchBlock(String key, String namespaceId, int id, boolean isActive) {
+    public RedstoneTorchBlock(String key, String namespaceId, int id, boolean isActive) {
         super(key, namespaceId, id);
         torchActive = isActive;
         setTicking(true);
     }
 
     @Override
-    public int tickDelay()
-    {
+    public int tickDelay() {
         return 2;
     }
 
     @Override
-	public void onBlockPlacedByWorld(World world, int x, int y, int z)
-    {
-        if(world.getBlockMetadata(x, y, z) == 0) {
+    public void onBlockPlacedByWorld(World world, int x, int y, int z) {
+        if (world.getBlockMetadata(x, y, z) == 0) {
             super.onBlockPlacedByWorld(world, x, y, z);
         }
-        if(torchActive) {
+        if (torchActive) {
             world.notifyBlocksOfNeighborChange(x, y - 1, z, id);
             world.notifyBlocksOfNeighborChange(x, y + 1, z, id);
             world.notifyBlocksOfNeighborChange(x - 1, y, z, id);
@@ -50,7 +42,7 @@ public class RedstoneTorchBlock extends TorchBlock
 
     @Override
     public void onBlockRemoved(World world, int x, int y, int z, int data) {
-        if(torchActive) {
+        if (torchActive) {
             world.notifyBlocksOfNeighborChange(x, y - 1, z, id);
             world.notifyBlocksOfNeighborChange(x, y + 1, z, id);
             world.notifyBlocksOfNeighborChange(x - 1, y, z, id);
@@ -61,69 +53,64 @@ public class RedstoneTorchBlock extends TorchBlock
     }
 
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side) {
-        if(!torchActive) {
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side) {
+        if (!torchActive) {
             return false;
         }
-        int meta = blockAccess.getBlockMetadata(x, y, z);
-        if(meta == 5 && side == Side.TOP) {
+        int meta = worldSource.getBlockMetadata(x, y, z);
+        if (meta == 5 && side == Side.TOP) {
             return false;
         }
-        if(meta == 3 && side == Side.SOUTH) {
+        if (meta == 3 && side == Side.SOUTH) {
             return false;
         }
-        if(meta == 4 && side == Side.NORTH) {
+        if (meta == 4 && side == Side.NORTH) {
             return false;
         }
-        if(meta == 1 && side == Side.EAST) {
+        if (meta == 1 && side == Side.EAST) {
             return false;
         }
         return meta != 2 || side != Side.WEST;
     }
 
-    private boolean isPoweredByBlock(World world, int x, int y, int z) {
+    private boolean hasNeighborSignal(World world, int x, int y, int z) {
         int meta = world.getBlockMetadata(x, y, z);
-        if(meta == 5 && world.isBlockIndirectlyProvidingPowerTo(x, y - 1, z, Side.BOTTOM)) {
+        if (meta == 5 && world.getSignal(x, y - 1, z, Side.BOTTOM)) {
             return true;
         }
-        if(meta == 3 && world.isBlockIndirectlyProvidingPowerTo(x, y, z - 1, Side.NORTH)) {
+        if (meta == 3 && world.getSignal(x, y, z - 1, Side.NORTH)) {
             return true;
         }
-        if(meta == 4 && world.isBlockIndirectlyProvidingPowerTo(x, y, z + 1, Side.SOUTH)) {
+        if (meta == 4 && world.getSignal(x, y, z + 1, Side.SOUTH)) {
             return true;
         }
-        if(meta == 1 && world.isBlockIndirectlyProvidingPowerTo(x - 1, y, z, Side.WEST)) {
+        if (meta == 1 && world.getSignal(x - 1, y, z, Side.WEST)) {
             return true;
         }
-        return meta == 2 && world.isBlockIndirectlyProvidingPowerTo(x + 1, y, z, Side.EAST);
+        return meta == 2 && world.getSignal(x + 1, y, z, Side.EAST);
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
-    {
-        boolean isPowered = isPoweredByBlock(world, x, y, z);
-        if(torchActive)
-        {
-            if(isPowered)
-            {
+    public void updateTick(World world, int x, int y, int z, Random rand) {
+        boolean isPowered = hasNeighborSignal(world, x, y, z);
+        if (torchActive) {
+            if (isPowered) {
                 world.setBlockAndMetadataWithNotify(x, y, z, Blocks.TORCH_REDSTONE_IDLE.id, world.getBlockMetadata(x, y, z));
             }
-        } else if(!isPowered) {
+        } else if (!isPowered) {
             world.setBlockAndMetadataWithNotify(x, y, z, Blocks.TORCH_REDSTONE_ACTIVE.id, world.getBlockMetadata(x, y, z));
         }
     }
 
     @Override
-	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId)
-    {
+    public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
         super.onNeighborBlockChange(world, x, y, z, blockId);
         world.scheduleBlockUpdate(x, y, z, id, tickDelay());
     }
 
     @Override
-    public boolean getDirectSignal(World world, int x, int y, int z, Side side)
-    {
-        if(side == Side.BOTTOM) {
+    public boolean getDirectSignal(World world, int x, int y, int z, Side side) {
+        if (side == Side.BOTTOM) {
             return getSignal(world, x, y, z, side);
         } else {
             return false;
@@ -132,51 +119,47 @@ public class RedstoneTorchBlock extends TorchBlock
 
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int x, int y, int z, int meta, BlockEntity blockEntity) {
-        return new ItemStack[] { new ItemStack(Blocks.TORCH_REDSTONE_ACTIVE) };
+        return new ItemStack[]{new ItemStack(Blocks.TORCH_REDSTONE_ACTIVE)};
     }
 
     @Override
-    public boolean isSignalSource()
-    {
+    public boolean isSignalSource() {
         return true;
     }
 
     @Override
-	public void animationTick(World world, int x, int y, int z, Random rand) {
-		if (!torchActive) {
-			return;
-		}
-		
-		int meta = world.getBlockMetadata(x, y, z);
-		double px = (x + 0.5D) + (rand.nextFloat() - 0.5D) * 0.2D;
-		double py = (y + 0.7D) + (rand.nextFloat() - 0.5D) * 0.2D;
-		double pz = (z + 0.5D) + (rand.nextFloat() - 0.5D) * 0.2D;
-		
-		double verticalOffset = 0.22D;
-		double horizontalOffset = 0.27D;
+    public void animationTick(World world, int x, int y, int z, Random rand) {
+        if (!torchActive) {
+            return;
+        }
 
-        final int redstoneBrightness = 10;
-		Color color = Colors.allRedstoneColors[redstoneBrightness];
-		if(color == null) {
-			return;
-		}
-		float red = color.getRed() / 255.0f;
-		float green = color.getGreen() / 255.0f;
-		float blue = color.getBlue() / 255.0f;
-		
-		if (meta == 1) {
-			world.spawnParticle("reddust", px - horizontalOffset, py + verticalOffset, pz, red, green, blue, redstoneBrightness);
-		} else if (meta == 2) {
-			world.spawnParticle("reddust", px + horizontalOffset, py + verticalOffset, pz, red, green, blue, redstoneBrightness);
-		} else if (meta == 3) {
-			world.spawnParticle("reddust", px, py + verticalOffset, pz - horizontalOffset, red, green, blue, redstoneBrightness);
-		} else if (meta == 4) {
-			world.spawnParticle("reddust", px, py + verticalOffset, pz + horizontalOffset, red, green, blue, redstoneBrightness);
-		} else {
-			world.spawnParticle("reddust", px, py, pz, red, green, blue, redstoneBrightness);
-		}
-	}
+        int meta = world.getBlockMetadata(x, y, z);
+        double px = (x + 0.5D) + (rand.nextFloat() - 0.5D) * 0.2D;
+        double py = (y + 0.7D) + (rand.nextFloat() - 0.5D) * 0.2D;
+        double pz = (z + 0.5D) + (rand.nextFloat() - 0.5D) * 0.2D;
 
-    private final boolean torchActive;
+        double verticalOffset = 0.22D;
+        double horizontalOffset = 0.27D;
 
+        final int redstoneBrightness = 10;
+        Color color = Colors.allRedstoneColors[redstoneBrightness];
+        if (color == null) {
+            return;
+        }
+        float red = color.getRed() / 255.0f;
+        float green = color.getGreen() / 255.0f;
+        float blue = color.getBlue() / 255.0f;
+
+        if (meta == 1) {
+            world.spawnParticle("reddust", px - horizontalOffset, py + verticalOffset, pz, red, green, blue, redstoneBrightness);
+        } else if (meta == 2) {
+            world.spawnParticle("reddust", px + horizontalOffset, py + verticalOffset, pz, red, green, blue, redstoneBrightness);
+        } else if (meta == 3) {
+            world.spawnParticle("reddust", px, py + verticalOffset, pz - horizontalOffset, red, green, blue, redstoneBrightness);
+        } else if (meta == 4) {
+            world.spawnParticle("reddust", px, py + verticalOffset, pz + horizontalOffset, red, green, blue, redstoneBrightness);
+        } else {
+            world.spawnParticle("reddust", px, py, pz, red, green, blue, redstoneBrightness);
+        }
+    }
 }
diff --git a/src/main/java/net/minecraft/core/block/RedstoneWireBlock.java b/src/main/java/net/minecraft/core/block/RedstoneWireBlock.java
index c127c1d9c..55328cca5 100644
--- a/src/main/java/net/minecraft/core/block/RedstoneWireBlock.java
+++ b/src/main/java/net/minecraft/core/block/RedstoneWireBlock.java
@@ -1,195 +1,162 @@
 package net.minecraft.core.block;
 
+import net.minecraft.client.util.helper.Colors;
 import net.minecraft.core.block.entity.BlockEntity;
+import net.minecraft.core.block.material.Material;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.util.helper.Axis;
-import net.minecraft.core.util.helper.Side;
-import net.minecraft.core.world.WorldSource;
-import net.minecraft.core.world.World;
-import net.minecraft.core.block.material.Material;
 import net.minecraft.core.util.helper.Color;
-import net.minecraft.client.util.helper.Colors;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.chunk.ChunkPosition;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
 
-// Referenced classes of package net.minecraft.src:
-//            Block, Material, World, ChunkPosition, 
-//            Item, IBlockAccess, ModelBed, AxisAlignedBB
+public class RedstoneWireBlock extends Block {
+    private boolean shouldSignal = true;
+    private final Set<ChunkPosition> toUpdate = new HashSet<>();
 
-public class RedstoneWireBlock extends Block
-{
-
-    public RedstoneWireBlock(String key, String namespaceId, int id)
-    {
+    public RedstoneWireBlock(String key, String namespaceId, int id) {
         super(key, namespaceId, id, Material.decoration);
-        wiresProvidePower = true;
-        chunkPositionSet = new HashSet<>();
         setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.0625F, 1.0F);
     }
 
     @Override
-	public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
-    {
+    public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z) {
         return null;
     }
 
     @Override
-	public boolean isSolidRender()
-    {
+    public boolean isSolidRender() {
         return false;
     }
 
     @Override
-	public boolean isCubeShaped()
-    {
+    public boolean isCubeShaped() {
         return false;
     }
 
     @Override
-	public boolean canPlaceBlockAt(World world, int x, int y, int z)
-    {
+    public boolean canPlaceBlockAt(World world, int x, int y, int z) {
         return world.canPlaceOnSurfaceOfBlock(x, y - 1, z);
     }
 
-    private void updateAndPropagateCurrentStrength(World world, int x, int y, int z)
-    {
-        func_21030_a(world, x, y, z, x, y, z);
-        ArrayList<ChunkPosition> arraylist = new ArrayList<>(chunkPositionSet);
-        chunkPositionSet.clear();
-        for (ChunkPosition chunkposition : arraylist) {
-            world.notifyBlocksOfNeighborChange(chunkposition.x, chunkposition.y, chunkposition.z, id);
+    private void updatePowerStrength(World world, int x, int y, int z) {
+        updatePowerStrength(world, x, y, z, x, y, z);
+        ArrayList<ChunkPosition> toUpdate = new ArrayList<>(this.toUpdate);
+        this.toUpdate.clear();
+        for (ChunkPosition pos : toUpdate) {
+            world.notifyBlocksOfNeighborChange(pos.x, pos.y, pos.z, id);
         }
-
     }
 
-    private void func_21030_a(World world, int x, int y, int z, int l, int i1, int j1) {
-        int meta = world.getBlockMetadata(x, y, z);
-        int l1 = 0;
-        wiresProvidePower = false;
-        boolean flag = world.isBlockIndirectlyGettingPowered(x, y, z);
-        wiresProvidePower = true;
-        if(flag) {
-            l1 = 15;
+    private void updatePowerStrength(World world, int x0, int y0, int z0, int x1, int y1, int z1) {
+        int strength = world.getBlockMetadata(x0, y0, z0);
+        int newStrength = 0;
+        shouldSignal = false;
+        boolean hasNeighborSignal = world.hasNeighborSignal(x0, y0, z0);
+        shouldSignal = true;
+        if (hasNeighborSignal) {
+            newStrength = 15;
         } else {
-            for(int i2 = 0; i2 < 4; i2++)
-            {
-                int k2 = x;
-                int i3 = z;
-                if(i2 == 0)
-                {
-                    k2--;
+            for (int i = 0; i < 4; i++) {
+                int xi = x0;
+                int zi = z0;
+                if (i == 0) {
+                    xi--;
                 }
-                if(i2 == 1)
-                {
-                    k2++;
+                if (i == 1) {
+                    xi++;
                 }
-                if(i2 == 2)
-                {
-                    i3--;
+                if (i == 2) {
+                    zi--;
                 }
-                if(i2 == 3)
-                {
-                    i3++;
+                if (i == 3) {
+                    zi++;
                 }
-                if(k2 != l || y != i1 || i3 != j1)
-                {
-                    l1 = getMaxCurrentStrength(world, k2, y, i3, l1);
+                if (xi != x1 || y0 != y1 || zi != z1) {
+                    newStrength = checkTarget(world, xi, y0, zi, newStrength);
                 }
-                if(world.isBlockNormalCube(k2, y, i3) && !world.isBlockNormalCube(x, y + 1, z))
-                {
-                    if(k2 != l || y + 1 != i1 || i3 != j1)
-                    {
-                        l1 = getMaxCurrentStrength(world, k2, y + 1, i3, l1);
+                if (world.isBlockNormalCube(xi, y0, zi) && !world.isBlockNormalCube(x0, y0 + 1, z0)) {
+                    if (xi != x1 || y0 + 1 != y1 || zi != z1) {
+                        newStrength = checkTarget(world, xi, y0 + 1, zi, newStrength);
                     }
                     continue;
                 }
-                if(!world.isBlockNormalCube(k2, y, i3) && (k2 != l || y - 1 != i1 || i3 != j1))
-                {
-                    l1 = getMaxCurrentStrength(world, k2, y - 1, i3, l1);
+                if (!world.isBlockNormalCube(xi, y0, zi) && (xi != x1 || y0 - 1 != y1 || zi != z1)) {
+                    newStrength = checkTarget(world, xi, y0 - 1, zi, newStrength);
                 }
             }
 
-            if(l1 > 0)
-            {
-                l1--;
-            } else
-            {
-                l1 = 0;
+            if (newStrength > 0) {
+                newStrength--;
+            } else {
+                newStrength = 0;
             }
         }
-        if(meta != l1)
-        {
-            world.editingBlocks = true;
-            world.setBlockMetadataWithNotify(x, y, z, l1);
-            world.markBlocksDirty(x, y, z, x, y, z);
-            world.editingBlocks = false;
-            for(int j2 = 0; j2 < 4; j2++)
-            {
-                int l2 = x;
-                int j3 = z;
-                int k3 = y - 1;
-                if(j2 == 0)
-                {
-                    l2--;
+        if (strength != newStrength) {
+            world.noNeighborUpdate = true;
+            world.setBlockMetadataWithNotify(x0, y0, z0, newStrength);
+            world.markBlocksDirty(x0, y0, z0, x0, y0, z0);
+            world.noNeighborUpdate = false;
+            for (int i = 0; i < 4; i++) {
+                int xi = x0;
+                int zi = z0;
+                int yi = y0 - 1;
+                if (i == 0) {
+                    xi--;
                 }
-                if(j2 == 1)
-                {
-                    l2++;
+                if (i == 1) {
+                    xi++;
                 }
-                if(j2 == 2)
-                {
-                    j3--;
+                if (i == 2) {
+                    zi--;
                 }
-                if(j2 == 3)
-                {
-                    j3++;
+                if (i == 3) {
+                    zi++;
                 }
-                if(world.isBlockNormalCube(l2, y, j3))
-                {
-                    k3 += 2;
+                if (world.isBlockNormalCube(xi, y0, zi)) {
+                    yi += 2;
                 }
-                int l3 = 0;
-                l3 = getMaxCurrentStrength(world, l2, y, j3, -1);
-                l1 = world.getBlockMetadata(x, y, z);
-                if(l1 > 0)
-                {
-                    l1--;
+                int targetStrength = 0;
+                targetStrength = checkTarget(world, xi, y0, zi, -1);
+                newStrength = world.getBlockMetadata(x0, y0, z0);
+                if (newStrength > 0) {
+                    newStrength--;
                 }
-                if(l3 >= 0 && l3 != l1)
-                {
-                    func_21030_a(world, l2, y, j3, x, y, z);
+                if (targetStrength >= 0 && targetStrength != newStrength) {
+                    updatePowerStrength(world, xi, y0, zi, x0, y0, z0);
                 }
-                l3 = getMaxCurrentStrength(world, l2, k3, j3, -1);
-                l1 = world.getBlockMetadata(x, y, z);
-                if(l1 > 0)
-                {
-                    l1--;
+                targetStrength = checkTarget(world, xi, yi, zi, -1);
+                newStrength = world.getBlockMetadata(x0, y0, z0);
+                if (newStrength > 0) {
+                    newStrength--;
                 }
-                if(l3 >= 0 && l3 != l1)
-                {
-                    func_21030_a(world, l2, k3, j3, x, y, z);
+                if (targetStrength >= 0 && targetStrength != newStrength) {
+                    updatePowerStrength(world, xi, yi, zi, x0, y0, z0);
                 }
             }
 
-            if(meta == 0 || l1 == 0)
-            {
-                chunkPositionSet.add(new ChunkPosition(x, y, z));
-                chunkPositionSet.add(new ChunkPosition(x - 1, y, z));
-                chunkPositionSet.add(new ChunkPosition(x + 1, y, z));
-                chunkPositionSet.add(new ChunkPosition(x, y - 1, z));
-                chunkPositionSet.add(new ChunkPosition(x, y + 1, z));
-                chunkPositionSet.add(new ChunkPosition(x, y, z - 1));
-                chunkPositionSet.add(new ChunkPosition(x, y, z + 1));
+            if (strength == 0 || newStrength == 0) {
+                toUpdate.add(new ChunkPosition(x0, y0, z0));
+                toUpdate.add(new ChunkPosition(x0 - 1, y0, z0));
+                toUpdate.add(new ChunkPosition(x0 + 1, y0, z0));
+                toUpdate.add(new ChunkPosition(x0, y0 - 1, z0));
+                toUpdate.add(new ChunkPosition(x0, y0 + 1, z0));
+                toUpdate.add(new ChunkPosition(x0, y0, z0 - 1));
+                toUpdate.add(new ChunkPosition(x0, y0, z0 + 1));
             }
         }
     }
 
-    private void notifyWireNeighborsOfNeighborChange(World world, int x, int y, int z)
-    {
+    private void checkCornerChangeAt(World world, int x, int y, int z) {
         if (world.getBlockId(x, y, z) == id) {
             world.notifyBlocksOfNeighborChange(x, y, z, id);
             world.notifyBlocksOfNeighborChange(x - 1, y, z, id);
@@ -202,128 +169,109 @@ public class RedstoneWireBlock extends Block
     }
 
     @Override
-	public void onBlockPlacedByWorld(World world, int x, int y, int z)
-    {
+    public void onBlockPlacedByWorld(World world, int x, int y, int z) {
         super.onBlockPlacedByWorld(world, x, y, z);
-        if(world.isClientSide)
-        {
+        if (world.isClientSide) {
             return;
         }
-        updateAndPropagateCurrentStrength(world, x, y, z);
+        updatePowerStrength(world, x, y, z);
         world.notifyBlocksOfNeighborChange(x, y + 1, z, id);
         world.notifyBlocksOfNeighborChange(x, y - 1, z, id);
-        notifyWireNeighborsOfNeighborChange(world, x - 1, y, z);
-        notifyWireNeighborsOfNeighborChange(world, x + 1, y, z);
-        notifyWireNeighborsOfNeighborChange(world, x, y, z - 1);
-        notifyWireNeighborsOfNeighborChange(world, x, y, z + 1);
-        if(world.isBlockNormalCube(x - 1, y, z))
-        {
-            notifyWireNeighborsOfNeighborChange(world, x - 1, y + 1, z);
-        } else
-        {
-            notifyWireNeighborsOfNeighborChange(world, x - 1, y - 1, z);
-        }
-        if(world.isBlockNormalCube(x + 1, y, z))
-        {
-            notifyWireNeighborsOfNeighborChange(world, x + 1, y + 1, z);
-        } else
-        {
-            notifyWireNeighborsOfNeighborChange(world, x + 1, y - 1, z);
-        }
-        if(world.isBlockNormalCube(x, y, z - 1))
-        {
-            notifyWireNeighborsOfNeighborChange(world, x, y + 1, z - 1);
-        } else
-        {
-            notifyWireNeighborsOfNeighborChange(world, x, y - 1, z - 1);
-        }
-        if(world.isBlockNormalCube(x, y, z + 1))
-        {
-            notifyWireNeighborsOfNeighborChange(world, x, y + 1, z + 1);
-        } else
-        {
-            notifyWireNeighborsOfNeighborChange(world, x, y - 1, z + 1);
+        checkCornerChangeAt(world, x - 1, y, z);
+        checkCornerChangeAt(world, x + 1, y, z);
+        checkCornerChangeAt(world, x, y, z - 1);
+        checkCornerChangeAt(world, x, y, z + 1);
+        if (world.isBlockNormalCube(x - 1, y, z)) {
+            checkCornerChangeAt(world, x - 1, y + 1, z);
+        } else {
+            checkCornerChangeAt(world, x - 1, y - 1, z);
+        }
+        if (world.isBlockNormalCube(x + 1, y, z)) {
+            checkCornerChangeAt(world, x + 1, y + 1, z);
+        } else {
+            checkCornerChangeAt(world, x + 1, y - 1, z);
+        }
+        if (world.isBlockNormalCube(x, y, z - 1)) {
+            checkCornerChangeAt(world, x, y + 1, z - 1);
+        } else {
+            checkCornerChangeAt(world, x, y - 1, z - 1);
+        }
+        if (world.isBlockNormalCube(x, y, z + 1)) {
+            checkCornerChangeAt(world, x, y + 1, z + 1);
+        } else {
+            checkCornerChangeAt(world, x, y - 1, z + 1);
         }
     }
 
     @Override
-    public void onBlockRemoved(World world, int x, int y, int z, int data)
-    {
+    public void onBlockRemoved(World world, int x, int y, int z, int data) {
         super.onBlockRemoved(world, x, y, z, data);
-        if(world.isClientSide)
-        {
+        if (world.isClientSide) {
             return;
         }
         world.notifyBlocksOfNeighborChange(x, y + 1, z, id);
         world.notifyBlocksOfNeighborChange(x, y - 1, z, id);
-        updateAndPropagateCurrentStrength(world, x, y, z);
-        notifyWireNeighborsOfNeighborChange(world, x - 1, y, z);
-        notifyWireNeighborsOfNeighborChange(world, x + 1, y, z);
-        notifyWireNeighborsOfNeighborChange(world, x, y, z - 1);
-        notifyWireNeighborsOfNeighborChange(world, x, y, z + 1);
-        if(world.isBlockNormalCube(x - 1, y, z))
-        {
-            notifyWireNeighborsOfNeighborChange(world, x - 1, y + 1, z);
-        } else
-        {
-            notifyWireNeighborsOfNeighborChange(world, x - 1, y - 1, z);
-        }
-        if(world.isBlockNormalCube(x + 1, y, z))
-        {
-            notifyWireNeighborsOfNeighborChange(world, x + 1, y + 1, z);
-        } else
-        {
-            notifyWireNeighborsOfNeighborChange(world, x + 1, y - 1, z);
-        }
-        if(world.isBlockNormalCube(x, y, z - 1))
-        {
-            notifyWireNeighborsOfNeighborChange(world, x, y + 1, z - 1);
-        } else
-        {
-            notifyWireNeighborsOfNeighborChange(world, x, y - 1, z - 1);
-        }
-        if(world.isBlockNormalCube(x, y, z + 1))
-        {
-            notifyWireNeighborsOfNeighborChange(world, x, y + 1, z + 1);
-        } else
-        {
-            notifyWireNeighborsOfNeighborChange(world, x, y - 1, z + 1);
+        updatePowerStrength(world, x, y, z);
+        checkCornerChangeAt(world, x - 1, y, z);
+        checkCornerChangeAt(world, x + 1, y, z);
+        checkCornerChangeAt(world, x, y, z - 1);
+        checkCornerChangeAt(world, x, y, z + 1);
+        if (world.isBlockNormalCube(x - 1, y, z)) {
+            checkCornerChangeAt(world, x - 1, y + 1, z);
+        } else {
+            checkCornerChangeAt(world, x - 1, y - 1, z);
+        }
+        if (world.isBlockNormalCube(x + 1, y, z)) {
+            checkCornerChangeAt(world, x + 1, y + 1, z);
+        } else {
+            checkCornerChangeAt(world, x + 1, y - 1, z);
+        }
+        if (world.isBlockNormalCube(x, y, z - 1)) {
+            checkCornerChangeAt(world, x, y + 1, z - 1);
+        } else {
+            checkCornerChangeAt(world, x, y - 1, z - 1);
+        }
+        if (world.isBlockNormalCube(x, y, z + 1)) {
+            checkCornerChangeAt(world, x, y + 1, z + 1);
+        } else {
+            checkCornerChangeAt(world, x, y - 1, z + 1);
         }
     }
 
-    private int getMaxCurrentStrength(World world, int x, int y, int z, int inputMeta) {
-        if(world.getBlockId(x, y, z) != id) {
-            return inputMeta;
+    private int checkTarget(World world, int x, int y, int z, int sourceStrength) {
+        if (world.getBlockId(x, y, z) != id) {
+            return sourceStrength;
         }
 
-        int meta = world.getBlockMetadata(x, y, z);
-        return Math.max(meta, inputMeta);
+        int targetStrength = world.getBlockMetadata(x, y, z);
+        return Math.max(targetStrength, sourceStrength);
     }
 
     @Override
-	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
-        if(world.isClientSide) {return;}
+    public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
+        if (world.isClientSide) {
+            return;
+        }
 
-        int meta = world.getBlockMetadata(x, y, z);
-        boolean flag = canPlaceBlockAt(world, x, y, z);
-        if(!flag) {
-            dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, meta, null, null);
+        int strength = world.getBlockMetadata(x, y, z);
+        boolean canPlaceBlockAt = canPlaceBlockAt(world, x, y, z);
+        if (!canPlaceBlockAt) {
+            dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, strength, null, null);
             world.setBlockWithNotify(x, y, z, 0);
         } else {
-            updateAndPropagateCurrentStrength(world, x, y, z);
+            updatePowerStrength(world, x, y, z);
         }
         super.onNeighborBlockChange(world, x, y, z, blockId);
     }
 
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int x, int y, int z, int meta, BlockEntity blockEntity) {
-        return new ItemStack[] { new ItemStack(Items.DUST_REDSTONE ) };
+        return new ItemStack[]{new ItemStack(Items.DUST_REDSTONE)};
     }
 
     @Override
-    public boolean getDirectSignal(World world, int x, int y, int z, Side side)
-    {
-        if(!wiresProvidePower) {
+    public boolean getDirectSignal(World world, int x, int y, int z, Side side) {
+        if (!shouldSignal) {
             return false;
         } else {
             return getSignal(world, x, y, z, side);
@@ -331,115 +279,100 @@ public class RedstoneWireBlock extends Block
     }
 
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side)
-    {
-        if(!wiresProvidePower) {
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side) {
+        if (!shouldSignal) {
             return false;
         }
-        if(blockAccess.getBlockMetadata(x, y, z) == 0) {
+        if (worldSource.getBlockMetadata(x, y, z) == 0) {
             return false;
         }
-        if(side == Side.TOP) {
+        if (side == Side.TOP) {
             return true;
         }
-        boolean flag = isPowerProviderOrWire(blockAccess, x - 1, y, z, 1) || !blockAccess.isBlockNormalCube(x - 1, y, z) && isPowerProviderOrWire(blockAccess, x - 1, y - 1, z, -1);
-        boolean flag1 = isPowerProviderOrWire(blockAccess, x + 1, y, z, 3) || !blockAccess.isBlockNormalCube(x + 1, y, z) && isPowerProviderOrWire(blockAccess, x + 1, y - 1, z, -1);
-        boolean flag2 = isPowerProviderOrWire(blockAccess, x, y, z - 1, 2) || !blockAccess.isBlockNormalCube(x, y, z - 1) && isPowerProviderOrWire(blockAccess, x, y - 1, z - 1, -1);
-        boolean flag3 = isPowerProviderOrWire(blockAccess, x, y, z + 1, 0) || !blockAccess.isBlockNormalCube(x, y, z + 1) && isPowerProviderOrWire(blockAccess, x, y - 1, z + 1, -1);
-        if(!blockAccess.isBlockNormalCube(x, y + 1, z))
-        {
-            if(blockAccess.isBlockNormalCube(x - 1, y, z) && isPowerProviderOrWire(blockAccess, x - 1, y + 1, z, -1))
-            {
-                flag = true;
+        boolean negXShouldConnectTo = shouldConnectTo(worldSource, x - 1, y, z, 1) || !worldSource.isBlockNormalCube(x - 1, y, z) && shouldConnectTo(worldSource, x - 1, y - 1, z, -1);
+        boolean posXShouldConnectTo = shouldConnectTo(worldSource, x + 1, y, z, 3) || !worldSource.isBlockNormalCube(x + 1, y, z) && shouldConnectTo(worldSource, x + 1, y - 1, z, -1);
+        boolean negZShouldConnectTo = shouldConnectTo(worldSource, x, y, z - 1, 2) || !worldSource.isBlockNormalCube(x, y, z - 1) && shouldConnectTo(worldSource, x, y - 1, z - 1, -1);
+        boolean posZShouldConnectTo = shouldConnectTo(worldSource, x, y, z + 1, 0) || !worldSource.isBlockNormalCube(x, y, z + 1) && shouldConnectTo(worldSource, x, y - 1, z + 1, -1);
+        if (!worldSource.isBlockNormalCube(x, y + 1, z)) {
+            if (worldSource.isBlockNormalCube(x - 1, y, z) && shouldConnectTo(worldSource, x - 1, y + 1, z, -1)) {
+                negXShouldConnectTo = true;
             }
-            if(blockAccess.isBlockNormalCube(x + 1, y, z) && isPowerProviderOrWire(blockAccess, x + 1, y + 1, z, -1))
-            {
-                flag1 = true;
+            if (worldSource.isBlockNormalCube(x + 1, y, z) && shouldConnectTo(worldSource, x + 1, y + 1, z, -1)) {
+                posXShouldConnectTo = true;
             }
-            if(blockAccess.isBlockNormalCube(x, y, z - 1) && isPowerProviderOrWire(blockAccess, x, y + 1, z - 1, -1))
-            {
-                flag2 = true;
+            if (worldSource.isBlockNormalCube(x, y, z - 1) && shouldConnectTo(worldSource, x, y + 1, z - 1, -1)) {
+                negZShouldConnectTo = true;
             }
-            if(blockAccess.isBlockNormalCube(x, y, z + 1) && isPowerProviderOrWire(blockAccess, x, y + 1, z + 1, -1))
-            {
-                flag3 = true;
+            if (worldSource.isBlockNormalCube(x, y, z + 1) && shouldConnectTo(worldSource, x, y + 1, z + 1, -1)) {
+                posZShouldConnectTo = true;
             }
         }
-        if(!flag2 && !flag1 && !flag && !flag3 && side.getAxis() != Axis.Y)
-        {
+        if (!negZShouldConnectTo && !posXShouldConnectTo && !negXShouldConnectTo && !posZShouldConnectTo && side.getAxis() != Axis.Y) {
             return true;
         }
-        if(side == Side.NORTH && flag2 && !flag && !flag1)
-        {
+        if (side == Side.NORTH && negZShouldConnectTo && !negXShouldConnectTo && !posXShouldConnectTo) {
             return true;
         }
-        if(side == Side.SOUTH && flag3 && !flag && !flag1)
-        {
+        if (side == Side.SOUTH && posZShouldConnectTo && !negXShouldConnectTo && !posXShouldConnectTo) {
             return true;
         }
-        if(side == Side.WEST && flag && !flag2 && !flag3)
-        {
+        if (side == Side.WEST && negXShouldConnectTo && !negZShouldConnectTo && !posZShouldConnectTo) {
             return true;
         }
-        return side == Side.EAST && flag1 && !flag2 && !flag3;
+        return side == Side.EAST && posXShouldConnectTo && !negZShouldConnectTo && !posZShouldConnectTo;
     }
 
     @Override
-    public boolean isSignalSource()
-    {
-        return wiresProvidePower;
+    public boolean isSignalSource() {
+        return shouldSignal;
     }
 
-	@Override
-	public void animationTick(World world, int x, int y, int z, Random rand) {
-		int meta = world.getBlockMetadata(x, y, z);
-		if(meta == 0) {
-			return;
-		}
-		double px = (double) x + 0.5D + (rand.nextFloat() - 0.5D) * 0.2D;
-		double py = (double) y + 0.0625D;
-		double pz = (double) z + 0.5D + (rand.nextFloat() - 0.5D) * 0.2D;
+    @Override
+    public void animationTick(World world, int x, int y, int z, Random rand) {
+        int meta = world.getBlockMetadata(x, y, z);
+        if (meta == 0) {
+            return;
+        }
+        double px = (double) x + 0.5D + (rand.nextFloat() - 0.5D) * 0.2D;
+        double py = (double) y + 0.0625D;
+        double pz = (double) z + 0.5D + (rand.nextFloat() - 0.5D) * 0.2D;
 
         final int redstoneBrightness = meta & 0xF;
-		Color color = Colors.allRedstoneColors[redstoneBrightness];
-		if(color == null) {
-			return;
-		}
-		float red = color.getRed() / 255.0f;
-		float green = color.getGreen() / 255.0f;
-		float blue = color.getBlue() / 255.0f;
+        Color color = Colors.allRedstoneColors[redstoneBrightness];
+        if (color == null) {
+            return;
+        }
+        float red = color.getRed() / 255.0f;
+        float green = color.getGreen() / 255.0f;
+        float blue = color.getBlue() / 255.0f;
 
-		world.spawnParticle("reddust", px, py, pz, red, green, blue, redstoneBrightness);
-	}
+        world.spawnParticle("reddust", px, py, pz, red, green, blue, redstoneBrightness);
+    }
 
-    public static boolean isPowerProviderOrWire(WorldSource worldSource, int x, int y, int z, int l)
-    {
+    public static boolean shouldConnectTo(WorldSource worldSource, int x, int y, int z, int data) {
         int blockId = worldSource.getBlockId(x, y, z);
-        if(blockId == Blocks.WIRE_REDSTONE.id) {
+        if (blockId == Blocks.WIRE_REDSTONE.id) {
             return true;
         }
-        if(blockId <= 0) {
+        if (blockId <= 0) {
             return false;
         }
-        if(Block.blocksList[blockId].isSignalSource()) {
+        if (Block.blocksList[blockId].isSignalSource()) {
             return true;
         }
         if (blockId == Blocks.PUMPKIN_REDSTONE.id) {
-            if (l < 0 || l > 3) {
+            if (data < 0 || data > 3) {
                 return false;
             }
-            Side[] lookup = { Side.NORTH, Side.EAST, Side.SOUTH, Side.WEST };
+            Side[] lookup = {Side.NORTH, Side.EAST, Side.SOUTH, Side.WEST};
             Side side = Side.getSideById(worldSource.getBlockMetadata(x, y, z));
-            return side == lookup[l];
+            return side == lookup[data];
         }
-        if(blockId == Blocks.REPEATER_IDLE.id || blockId == Blocks.REPEATER_ACTIVE.id) {
+        if (blockId == Blocks.REPEATER_IDLE.id || blockId == Blocks.REPEATER_ACTIVE.id) {
             int meta = worldSource.getBlockMetadata(x, y, z);
-            return l == BedBlock.footToHeadMap[meta & 0b11];
+            return data == BedBlock.footToHeadMap[meta & 0b11];
         } else {
             return false;
         }
     }
-
-    private boolean wiresProvidePower;
-    private final Set<ChunkPosition> chunkPositionSet;
 }
diff --git a/src/main/java/net/minecraft/core/block/RepeaterBlock.java b/src/main/java/net/minecraft/core/block/RepeaterBlock.java
index 680360b39..d0bef696c 100644
--- a/src/main/java/net/minecraft/core/block/RepeaterBlock.java
+++ b/src/main/java/net/minecraft/core/block/RepeaterBlock.java
@@ -81,11 +81,11 @@ public class RepeaterBlock extends Block
     }
 
     @Override
-    public boolean getSignal(WorldSource blockAccess, int x, int y, int z, Side side) {
+    public boolean getSignal(WorldSource worldSource, int x, int y, int z, Side side) {
         if(!isRepeaterPowered) {
             return false;
         }
-        int meta = blockAccess.getBlockMetadata(x, y, z) & 3;
+        int meta = worldSource.getBlockMetadata(x, y, z) & 3;
         if(meta == 0 && side == Side.SOUTH) {
             return true;
         }
@@ -121,16 +121,16 @@ public class RepeaterBlock extends Block
         switch(direction)
         {
         case 0: // '\0'
-            return world.isBlockIndirectlyProvidingPowerTo(x, y, z + 1, Side.SOUTH) || world.getBlockId(x, y, z + 1) == Blocks.WIRE_REDSTONE.id && world.getBlockMetadata(x, y, z + 1) > 0;
+            return world.getSignal(x, y, z + 1, Side.SOUTH) || world.getBlockId(x, y, z + 1) == Blocks.WIRE_REDSTONE.id && world.getBlockMetadata(x, y, z + 1) > 0;
 
         case 2: // '\002'
-            return world.isBlockIndirectlyProvidingPowerTo(x, y, z - 1, Side.NORTH) || world.getBlockId(x, y, z - 1) == Blocks.WIRE_REDSTONE.id && world.getBlockMetadata(x, y, z - 1) > 0;
+            return world.getSignal(x, y, z - 1, Side.NORTH) || world.getBlockId(x, y, z - 1) == Blocks.WIRE_REDSTONE.id && world.getBlockMetadata(x, y, z - 1) > 0;
 
         case 3: // '\003'
-            return world.isBlockIndirectlyProvidingPowerTo(x + 1, y, z, Side.EAST) || world.getBlockId(x + 1, y, z) == Blocks.WIRE_REDSTONE.id && world.getBlockMetadata(x + 1, y, z) > 0;
+            return world.getSignal(x + 1, y, z, Side.EAST) || world.getBlockId(x + 1, y, z) == Blocks.WIRE_REDSTONE.id && world.getBlockMetadata(x + 1, y, z) > 0;
 
         case 1: // '\001'
-            return world.isBlockIndirectlyProvidingPowerTo(x - 1, y, z, Side.WEST) || world.getBlockId(x - 1, y, z) == Blocks.WIRE_REDSTONE.id && world.getBlockMetadata(x - 1, y, z) > 0;
+            return world.getSignal(x - 1, y, z, Side.WEST) || world.getBlockId(x - 1, y, z) == Blocks.WIRE_REDSTONE.id && world.getBlockMetadata(x - 1, y, z) > 0;
         }
         return false;
     }
diff --git a/src/main/java/net/minecraft/core/block/SlabBlock.java b/src/main/java/net/minecraft/core/block/SlabBlock.java
index 50fb2099f..dbc0925fe 100644
--- a/src/main/java/net/minecraft/core/block/SlabBlock.java
+++ b/src/main/java/net/minecraft/core/block/SlabBlock.java
@@ -70,7 +70,7 @@ public class SlabBlock extends Block
     }
 
     @Override
-    public boolean renderAsNormalBlockOnCondition(World world, int x, int y, int z)
+    public boolean renderAsNormalBlockOnCondition(WorldSource world, int x, int y, int z)
     {
         int meta = world.getBlockMetadata(x, y, z);
         return (meta & 0x3) == 1;
diff --git a/src/main/java/net/minecraft/core/block/SpikesBlock.java b/src/main/java/net/minecraft/core/block/SpikesBlock.java
index 9e80c1cfd..29239e24c 100644
--- a/src/main/java/net/minecraft/core/block/SpikesBlock.java
+++ b/src/main/java/net/minecraft/core/block/SpikesBlock.java
@@ -7,18 +7,14 @@ import net.minecraft.core.entity.Mob;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.util.helper.DamageType;
 import net.minecraft.core.world.WorldSource;
 
-// Referenced classes of package net.minecraft.src:
-//            Block, Material, Entity, Item,
-//            World, AxisAlignedBB
-
-//TODO make it not extend blockWeb
-public class SpikesBlock extends CobwebBlock
+public class SpikesBlock extends Block
 {
 
     public SpikesBlock(String key, String namespaceId, int id, Material mat)
@@ -26,6 +22,18 @@ public class SpikesBlock extends CobwebBlock
         super(key, namespaceId, id, mat);
     }
 
+    @Override
+    public void onBlockPlacedByMob(World world, int x, int y, int z, Side side, Mob mob, double sideHeight) {
+        if (world.isClientSide) {
+            return;
+        }
+
+        int meta = world.getBlockMetadata(x, y, z);
+        if(world.hasNeighborSignal(x, y, z)) {
+            world.setBlockMetadataWithNotify(x, y, z, meta | 1);
+        }
+    }
+
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int x, int y, int z, int meta, BlockEntity blockEntity)
     {
@@ -53,7 +61,7 @@ public class SpikesBlock extends CobwebBlock
 
 		int meta = world.getBlockMetadata(x, y, z);
 		boolean wasPowered = (meta & 1) > 0;
-		boolean isPowered = world.isBlockIndirectlyGettingPowered(x, y, z);
+		boolean isPowered = world.hasNeighborSignal(x, y, z);
 		
 		if(isPowered != wasPowered) {
 			if(isPowered) {
@@ -98,4 +106,14 @@ public class SpikesBlock extends CobwebBlock
     {
         return (i & 1) != 1;
     }
+
+    @Override
+    public boolean isSolidRender() {
+        return false;
+    }
+
+    @Override
+    public boolean isCubeShaped() {
+        return false;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/block/StillFluidBlock.java b/src/main/java/net/minecraft/core/block/StillFluidBlock.java
index 3b8b57696..309865dcf 100644
--- a/src/main/java/net/minecraft/core/block/StillFluidBlock.java
+++ b/src/main/java/net/minecraft/core/block/StillFluidBlock.java
@@ -32,11 +32,11 @@ public class StillFluidBlock extends FluidBlock
     private void setFlowing(World world, int i, int j, int k)
     {
         int l = world.getBlockMetadata(i, j, k);
-        world.editingBlocks = true;
+        world.noNeighborUpdate = true;
         world.setBlockAndMetadata(i, j, k, id - 1, l);
         world.markBlocksDirty(i, j, k, i, j, k);
         world.scheduleBlockUpdate(i, j, k, id - 1, tickDelay());
-        world.editingBlocks = false;
+        world.noNeighborUpdate = false;
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/core/block/TNTBlock.java b/src/main/java/net/minecraft/core/block/TNTBlock.java
index 28509f42d..afc651056 100644
--- a/src/main/java/net/minecraft/core/block/TNTBlock.java
+++ b/src/main/java/net/minecraft/core/block/TNTBlock.java
@@ -19,14 +19,14 @@ public class TNTBlock extends Block {
 	@Override
 	public void onBlockPlacedByWorld(World world, int x, int y, int z) {
 		super.onBlockPlacedByWorld(world, x, y, z);
-		if (world.isBlockIndirectlyGettingPowered(x, y, z)) {
+		if (world.hasNeighborSignal(x, y, z)) {
 			ignite(world, x, y, z, true);
 		}
 	}
 
 	@Override
 	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
-		if (blockId > 0 && Block.blocksList[blockId].isSignalSource() && world.isBlockIndirectlyGettingPowered(x, y, z)) {
+		if (blockId > 0 && Block.blocksList[blockId].isSignalSource() && world.hasNeighborSignal(x, y, z)) {
 			ignite(world, x, y, z, true);
 		}
 	}
diff --git a/src/main/java/net/minecraft/core/block/TrapDoorBlock.java b/src/main/java/net/minecraft/core/block/TrapDoorBlock.java
index fcd92ecca..be570f0d0 100644
--- a/src/main/java/net/minecraft/core/block/TrapDoorBlock.java
+++ b/src/main/java/net/minecraft/core/block/TrapDoorBlock.java
@@ -1,6 +1,7 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.PlacementMode;
 import net.minecraft.core.item.Item;
@@ -18,94 +19,89 @@ import net.minecraft.core.world.WorldSource;
 //            Block, Material, IBlockAccess, World, 
 //            AxisAlignedBB, Player, Vec3D, MovingObjectPosition
 
-public class TrapDoorBlock extends Block
-{
-
-	
-	private boolean isIron;
-	
-	public TrapDoorBlock(String key, String namespaceId, int id, Material material, boolean isIron)
-    {
+public class TrapDoorBlock extends Block {
+    public TrapDoorBlock(String key, String namespaceId, int id, Material material) {
         super(key, namespaceId, id, material);
         float f = 0.5F;
         float f1 = 1.0F;
         setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f);
-        this.isIron = isIron;
     }
 
     @Override
-	public boolean isSolidRender()
-    {
+    public void onBlockPlacedByMob(World world, int x, int y, int z, Side side, Mob mob, double sideHeight) {
+        super.onBlockPlacedByMob(world, x, y, z, side, mob, sideHeight);
+
+        int meta = world.getBlockMetadata(x, y, z);
+        final boolean isPowered = world.hasNeighborSignal(x, y, z);
+
+        if (isPowered) {
+            meta = setTrapdoorPowered(meta, true);
+            meta = setTrapdoorOpen(meta, true);
+            world.setBlockMetadataWithNotify(x, y, z, setTrapdoorPowered(meta, true));
+        }
+    }
+
+    @Override
+    public boolean isSolidRender() {
         return false;
     }
 
     @Override
-	public boolean isCubeShaped()
-    {
+    public boolean isCubeShaped() {
         return false;
     }
 
     @Override
-    public AABB getSelectedBoundingBoxFromPool(WorldSource world, int x, int y, int z)
-    {
+    public AABB getSelectedBoundingBoxFromPool(WorldSource world, int x, int y, int z) {
         setBlockBoundsBasedOnState(world, x, y, z);
         return super.getSelectedBoundingBoxFromPool(world, x, y, z);
     }
 
     @Override
-	public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
-    {
+    public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z) {
         setBlockBoundsBasedOnState(world, x, y, z);
         return super.getCollisionBoundingBoxFromPool(world, x, y, z);
     }
 
     @Override
-    public void setBlockBoundsBasedOnState(WorldSource world, int x, int y, int z)
-    {
+    public void setBlockBoundsBasedOnState(WorldSource world, int x, int y, int z) {
         setBlockBoundsForBlockRender(world.getBlockMetadata(x, y, z));
     }
 
-    public void setBlockBoundsForBlockRender(int i)
-    {
+    public void setBlockBoundsForBlockRender(int i) {
         float f = 0.1875F;
-        
-        if(isTrapdoorOpen(i))
-        {
-            if((i & 3) == 0)
-            {
+
+        if (isTrapdoorOpen(i)) {
+            if ((i & 3) == 0) {
                 setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
             }
-            if((i & 3) == 1)
-            {
+            if ((i & 3) == 1) {
                 setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
             }
-            if((i & 3) == 2)
-            {
+            if ((i & 3) == 2) {
                 setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
             }
-            if((i & 3) == 3)
-            {
+            if ((i & 3) == 3) {
                 setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
             }
-        }else {
-        	if(isUpperHalf(i)) {
+        } else {
+            if (isUpperHalf(i)) {
                 setBlockBounds(0.0F, 1.0f - f, 0.0F, 1.0F, 1.0f, 1.0F);
-        	}else {
+            } else {
                 setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, f, 1.0F);
-        	}
+            }
         }
     }
-    
+
     @Override
     public void onBlockLeftClicked(World world, int x, int y, int z, Player player, Side side, double xHit, double yHit) {
-    	if(!Item.hasTag(player.getCurrentEquippedItem(), ItemTags.PREVENT_LEFT_CLICK_INTERACTIONS)) {
-    		onBlockRightClicked(world, x, y, z, player, null, 0.0, 0.0);
-    	}
+        if (!Item.hasTag(player.getCurrentEquippedItem(), ItemTags.PREVENT_LEFT_CLICK_INTERACTIONS)) {
+            onBlockRightClicked(world, x, y, z, player, null, 0.0, 0.0);
+        }
     }
 
     @Override
-    public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
-    {
+    public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced) {
         if (blockMaterial != Material.metal) {
             int l = world.getBlockMetadata(x, y, z);
             world.setBlockMetadataWithNotify(x, y, z, l ^ 4);
@@ -115,76 +111,107 @@ public class TrapDoorBlock extends Block
         return false;
     }
 
-	@Override
-	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
-		if(world.isClientSide) {
-			return;
-		}
+    @Override
+    public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
+        if (world.isClientSide) {
+            return;
+        }
 
-		if(isIron || blockId > 0 && Block.getBlock(blockId).isSignalSource()) {
-			int meta = world.getBlockMetadata(x, y, z);
-			boolean isOpened = isTrapdoorOpen(meta);
-			boolean isPowered = world.isBlockIndirectlyGettingPowered(x, y, z);
+        int meta = world.getBlockMetadata(x, y, z);
+        final boolean wasPowered = isTrapdoorPowered(meta);
+        final boolean isPowered = world.hasNeighborSignal(x, y, z);
 
-			if(isOpened != isPowered) {
-				world.setBlockMetadataWithNotify(x, y, z, meta ^ 4);
-				world.playSoundEffect(null, 1003, x, y, z, 0);
-			}
-		}
-	}
+        if (wasPowered != isPowered) {
+            if (isPowered != isTrapdoorOpen(meta)) {
+                world.playSoundEffect(null, 1003, x, y, z, 0);
+            }
+            meta = setTrapdoorPowered(meta, isPowered);
+            meta = setTrapdoorOpen(meta, isPowered);
+            world.setBlockMetadataWithNotify(x, y, z, setTrapdoorPowered(meta, isPowered));
+        }
+    }
 
     @Override
-    public HitResult collisionRayTrace(World world, int x, int y, int z, Vec3 start, Vec3 end)
-    {
+    public HitResult collisionRayTrace(World world, int x, int y, int z, Vec3 start, Vec3 end) {
         setBlockBoundsBasedOnState(world, x, y, z);
         return super.collisionRayTrace(world, x, y, z, start, end);
     }
-    
+
     @Override
     public int getPlacedBlockMetadata(Player player, ItemStack stack, World world, int x, int y, int z, Side side, double xPlaced, double yPlaced) {
-    	int meta = getMetaForDirection(player.getHorizontalPlacementDirection(side, PlacementMode.SIDE));
-    	if(player.getVerticalPlacementDirection(side, yPlaced) == Direction.UP) {
-    		meta |= 8;
-    	}
-    	return meta;
+        int meta = getMetaForDirection(player.getHorizontalPlacementDirection(side, PlacementMode.SIDE));
+        if (player.getVerticalPlacementDirection(side, yPlaced) == Direction.UP) {
+            meta = setUpperHalf(meta, true);
+        }
+        return meta;
     }
-    
+
     @Override
     public boolean isClimbable(World world, int x, int y, int z) {
-    	Block block = world.getBlock(x, y - 1, z);
-    	int meta = world.getBlockMetadata(x, y, z);
-    	if(isTrapdoorOpen(meta) && block instanceof LadderBlock) {
-    		LadderBlock ladder = (LadderBlock) block;
-    		Side ladderSide = ladder.getSideFromMeta(world.getBlockMetadata(x, y - 1, z));
-    		Direction trapdoorDirection = getDirectionForMeta(meta);
-    		return ladderSide.getDirection().getOpposite() == trapdoorDirection;
-    	}
-    	return false;
-    }
-    
-    public static boolean isTrapdoorOpen(int metadata)
-    {
-        return (metadata & 4) != 0;
-    }
-    
+        Block block = world.getBlock(x, y - 1, z);
+        int meta = world.getBlockMetadata(x, y, z);
+        if (isTrapdoorOpen(meta) && block instanceof LadderBlock) {
+            LadderBlock ladder = (LadderBlock) block;
+            Side ladderSide = ladder.getSideFromMeta(world.getBlockMetadata(x, y - 1, z));
+            Direction trapdoorDirection = getDirectionForMeta(meta);
+            return ladderSide.getDirection().getOpposite() == trapdoorDirection;
+        }
+        return false;
+    }
+
+    public static boolean isTrapdoorOpen(int metadata) {
+        return (metadata & 0b0000_0100) != 0;
+    }
+
+    public static int setTrapdoorOpen(int metadata, boolean isOpen) {
+        if (isOpen) {
+            metadata |= 0b0000_0100;
+        } else {
+            metadata &= 0b1111_1011;
+        }
+        return metadata;
+    }
+
+    public static boolean isTrapdoorPowered(int metadata) {
+        return (metadata & 0b0001_0000) != 0;
+    }
+
+    public static int setTrapdoorPowered(int metadata, boolean isPowered) {
+        if (isPowered) {
+            metadata |= 0b0001_0000;
+        } else {
+            metadata &= 0b1110_1111;
+        }
+        return metadata;
+    }
+
     public static boolean isUpperHalf(int meta) {
-    	return (meta & 8) != 0;
+        return (meta & 8) != 0;
     }
-    
+
+    public static int setUpperHalf(int metadata, boolean isUpperHalf) {
+        if (isUpperHalf) {
+            metadata |= 0b0000_1000;
+        } else {
+            metadata &= 0b1111_0111;
+        }
+        return metadata;
+    }
+
     public int getMetaForDirection(Direction dir) {
-    	if(dir == Direction.NORTH) return 1;
-    	if(dir == Direction.EAST) return 2;
-    	if(dir == Direction.SOUTH) return 0;
-    	if(dir == Direction.WEST) return 3;
-    	return 0;
-    }
-    
-    public Direction getDirectionForMeta(int meta) {
-    	meta = meta & 3;
-    	if(meta == 0) return Direction.SOUTH;
-    	if(meta == 1) return Direction.NORTH;
-    	if(meta == 2) return Direction.EAST;
-    	if(meta == 3) return Direction.WEST;
-    	return Direction.NONE;
+        if (dir == Direction.NORTH) return 1;
+        if (dir == Direction.EAST) return 2;
+        if (dir == Direction.SOUTH) return 0;
+        if (dir == Direction.WEST) return 3;
+        return 0;
+    }
+
+    public Direction getDirectionForMeta(int metadata) {
+        metadata = metadata & 3;
+        if (metadata == 0) return Direction.SOUTH;
+        if (metadata == 1) return Direction.NORTH;
+        if (metadata == 2) return Direction.EAST;
+        if (metadata == 3) return Direction.WEST;
+        return Direction.NONE;
     }
 }
diff --git a/src/main/java/net/minecraft/core/block/TrommelBlock.java b/src/main/java/net/minecraft/core/block/TrommelBlock.java
index 2df0d5901..a6f320407 100644
--- a/src/main/java/net/minecraft/core/block/TrommelBlock.java
+++ b/src/main/java/net/minecraft/core/block/TrommelBlock.java
@@ -22,7 +22,6 @@ public class TrommelBlock extends RotatableEntityBlock
     {
         super(key, namespaceId, id, material);
         this.isActive = isActive;
-        random = new Random();
     }
 
     @Override
@@ -68,72 +67,31 @@ public class TrommelBlock extends RotatableEntityBlock
         world.spawnParticle("smoke", xPos, yPos, zPos, 0.0D, 0.0D, 0.0D, 0);
     }
     
-    public static void updateTrommelBlockState(boolean flag, World world, int i, int j, int k)
+    public static void updateTrommelBlockState(boolean lit, World world, int x, int y, int z)
     {
-        int l = world.getBlockMetadata(i, j, k);
-        BlockEntity blockEntity = world.getBlockEntity(i, j, k);
+        int l = world.getBlockMetadata(x, y, z);
+        BlockEntity blockEntity = world.getBlockEntity(x, y, z);
         if(blockEntity == null) {
-            String msg = "Trommel is missing Tile Entity at x: " + i + " y: " + j + " z: " + k + ", block will be removed!";
+            String msg = "Trommel is missing Tile Entity at x: " + x + " y: " + y + " z: " + z + ", block will be removed!";
             if(Global.BUILD_CHANNEL.isUnstableBuild()) {
                 throw new RuntimeException(msg);
             }
-            world.setBlockWithNotify(i, j, k, 0);
+            world.setBlockWithNotify(x, y, z, 0);
             LOGGER.warn(msg);
             return;
         }
         keepTrommelInventory = true;
-        if(flag)
+        if(lit)
         {
-            world.setBlockWithNotify(i, j, k, Blocks.TROMMEL_ACTIVE.id);
+            world.setBlockWithNotify(x, y, z, Blocks.TROMMEL_ACTIVE.id);
         } else
         {
-            world.setBlockWithNotify(i, j, k, Blocks.TROMMEL_IDLE.id);
+            world.setBlockWithNotify(x, y, z, Blocks.TROMMEL_IDLE.id);
         }
         keepTrommelInventory = false;
-        world.setBlockMetadataWithNotify(i, j, k, l);
+        world.setBlockMetadataWithNotify(x, y, z, l);
         blockEntity.validate();
-        world.setBlockTileEntity(i, j, k, blockEntity);
-    }
-    
-    @Override
-    public void onBlockRemoved(World world, int x, int y, int z, int data)
-    {
-    	if (!keepTrommelInventory)
-    	{
-    		if(world.getBlockEntity(x, y, z) != null)
-    		{
-    			TrommelBlockEntity trommel = (TrommelBlockEntity) world.getBlockEntity(x, y, z);
-    			label0:
-				for (int l = 0; l < trommel.getContainerSize(); l++)
-				{
-					ItemStack itemstack = trommel.getItem(l);
-					if (itemstack == null) {
-						continue;
-					}
-					float f = random.nextFloat() * 0.8F + 0.1F;
-					float f1 = random.nextFloat() * 0.8F + 0.1F;
-					float f2 = random.nextFloat() * 0.8F + 0.1F;
-					do {
-						if (itemstack.stackSize <= 0) {
-							continue label0;
-						}
-						int i1 = random.nextInt(21) + 10;
-						if (i1 > itemstack.stackSize) {
-							i1 = itemstack.stackSize;
-						}
-						itemstack.stackSize -= i1;
-						ItemEntity item = new ItemEntity(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata()));
-						float f3 = 0.05F;
-						item.xd = (float) random.nextGaussian() * f3;
-						item.yd = (float) random.nextGaussian() * f3 + 0.2F;
-						item.zd = (float) random.nextGaussian() * f3;
-						world.entityJoinedWorld(item);
-					} while (true);
-				}
-    		}
-    	}
-
-        super.onBlockRemoved(world, x, y, z, data);
+        world.setBlockTileEntity(x, y, z, blockEntity);
     }
 
 
@@ -144,6 +102,5 @@ public class TrommelBlock extends RotatableEntityBlock
     }
 
     private boolean isActive;
-    protected static boolean keepTrommelInventory = false;
-    private Random random;
+    public static boolean keepTrommelInventory = false;
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/BasketBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/BasketBlockEntity.java
index 0f92e779d..5d0c24185 100644
--- a/src/main/java/net/minecraft/core/block/entity/BasketBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/BasketBlockEntity.java
@@ -20,31 +20,6 @@ public class BasketBlockEntity extends BlockEntity
     private int numUnitsInside = 0;
     private final Map<BasketEntry, Integer> contents = new HashMap<>();
 
-    public void dropAllItems()
-    {
-        final Random rand = new Random();
-
-        for (Map.Entry<BasketEntry, Integer> entry : contents.entrySet())
-        {
-            BasketEntry be = entry.getKey();
-            int numItems = entry.getValue();
-
-            while (numItems > 0)
-            {
-                int maxStackSize = be.getItem().getItemStackLimit();
-                int stackSize = maxStackSize;
-                int remainingItems = numItems - maxStackSize;
-                if (remainingItems < 0) stackSize = numItems;
-                numItems -= stackSize;
-                dropItemStack(rand, new ItemStack(be.id, stackSize, be.metadata, be.tag));
-            }
-        }
-
-        contents.clear();
-
-        worldObj.notifyBlockChange(x, y, z, Blocks.BASKET.id);
-        updateNumUnits();
-    }
 
     private void updateNumUnits()
     {
@@ -76,12 +51,21 @@ public class BasketBlockEntity extends BlockEntity
         final float f1 = rand.nextFloat() * 0.8F + 0.1F;
         final float f2 = rand.nextFloat() * 0.8F + 0.1F;
 
-        final ItemEntity entityitem = new ItemEntity(worldObj, x + f, y + f1, z + f2, itemstack);
+        World workingWorld;
+        if (worldObj != null) {
+            workingWorld = worldObj;
+        } else if (carriedBlock != null) {
+            workingWorld = carriedBlock.world;
+        } else {
+            return;
+        }
+
+        final ItemEntity item = new ItemEntity(workingWorld, x + f, y + f1, z + f2, itemstack);
         final float f3 = 0.05F;
-        entityitem.xd = (float) rand.nextGaussian() * f3;
-        entityitem.yd = (float) rand.nextGaussian() * f3 + 0.25F;
-        entityitem.zd = (float) rand.nextGaussian() * f3;
-        worldObj.entityJoinedWorld(entityitem);
+        item.xd = (float) rand.nextGaussian() * f3;
+        item.yd = (float) rand.nextGaussian() * f3 + 0.25F;
+        item.zd = (float) rand.nextGaussian() * f3;
+        workingWorld.entityJoinedWorld(item);
     }
 
     public int getNumUnitsInside()
@@ -115,7 +99,7 @@ public class BasketBlockEntity extends BlockEntity
 		}
 
 		updateNumUnits();
-		worldObj.notifyBlockChange(x, y, z, Blocks.BASKET.id);
+        world.notifyBlockChange(x, y, z, Blocks.BASKET.id);
 	}
 
     @Override
@@ -137,15 +121,32 @@ public class BasketBlockEntity extends BlockEntity
     @Override
     public void tick()
     {
-        if (worldObj == null || worldObj.isClientSide) return;
+        if (worldObj != null && worldObj.isClientSide) return;
+        if (carriedBlock != null && carriedBlock.world.isClientSide) return;
+
+        double posX, posY, posZ;
+        World workingWorld;
+        if (worldObj != null) {
+            workingWorld = worldObj;
+            posX = x;
+            posY = y;
+            posZ = z;
+        } else if (carriedBlock != null) {
+            workingWorld = carriedBlock.world;
+            posX = carriedBlock.holder.x - 0.5;
+            posY = carriedBlock.holder.y - carriedBlock.holder.heightOffset;
+            posZ = carriedBlock.holder.z - 0.5;
+        } else {
+            return;
+        }
 
-        final AABB aabb = AABB.getTemporaryBB(x, y, z, x + 1, y + 2, z + 1);
+        final AABB aabb = AABB.getTemporaryBB(posX, posY, posZ, posX + 1, posY + 2, posZ + 1);
 
-        final List<Entity> entities = worldObj.getEntitiesWithinAABB(ItemEntity.class, aabb);
+        final List<Entity> entities = workingWorld.getEntitiesWithinAABB(ItemEntity.class, aabb);
 
         boolean shouldUpdate = false;
 
-        if (entities.size() > 0)
+        if (!entities.isEmpty())
         {
             for (final Entity e : entities)
             {
@@ -164,7 +165,9 @@ public class BasketBlockEntity extends BlockEntity
 
         if (shouldUpdate)
         {
-            worldObj.notifyBlockChange(x, y, z, Blocks.BASKET.id);
+            if (worldObj != null) {
+                worldObj.notifyBlockChange(x, y, z, Blocks.BASKET.id);
+            }
             updateNumUnits();
         }
     }
@@ -204,6 +207,42 @@ public class BasketBlockEntity extends BlockEntity
         return new BlockEntityDataPacket(this);
     }
 
+    @Override
+    public void dropContents(World world, int x, int y, int z) {
+        super.dropContents(world, x, y, z);
+        final Random rand = new Random();
+
+        for (Map.Entry<BasketEntry, Integer> entry : contents.entrySet())
+        {
+            BasketEntry be = entry.getKey();
+            int numItems = entry.getValue();
+
+            while (numItems > 0)
+            {
+                int maxStackSize = be.getItem().getItemStackLimit();
+                int stackSize = maxStackSize;
+                int remainingItems = numItems - maxStackSize;
+                if (remainingItems < 0) stackSize = numItems;
+                numItems -= stackSize;
+                dropItemStack(rand, new ItemStack(be.id, stackSize, be.metadata, be.tag));
+            }
+        }
+
+        contents.clear();
+
+        world.notifyBlockChange(x, y, z, Blocks.BASKET.id);
+        updateNumUnits();
+    }
+
+    @Override
+    public void heldTick(World world, Entity holder) {
+        tick();
+    }
+    @Override
+    public boolean canBeCarried(World world, Entity potentialHolder) {
+        return true;
+    }
+
     private static final class BasketEntry
     {
         public final int id;
diff --git a/src/main/java/net/minecraft/core/block/entity/BlastFurnaceBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/BlastFurnaceBlockEntity.java
index 14913b32c..41fd7caf2 100644
--- a/src/main/java/net/minecraft/core/block/entity/BlastFurnaceBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/BlastFurnaceBlockEntity.java
@@ -88,14 +88,14 @@ public class BlastFurnaceBlockEntity extends FurnaceBlockEntity
         {
             currentBurnTime--;
         }
-        if(worldObj != null && !worldObj.isClientSide)
+        if(worldObj == null || !worldObj.isClientSide)
         {
-        	if(worldObj.getBlockId(x, y, z) == Blocks.FURNACE_BLAST_IDLE.id) {
+        	if(worldObj == null || worldObj.getBlockId(x, y, z) == Blocks.FURNACE_BLAST_IDLE.id) {
             	if(currentBurnTime == 0 && furnaceItemStacks[0] == null) {
             		if(furnaceItemStacks[1] != null && furnaceItemStacks[1].itemID == Blocks.NETHERRACK.id) {
             			furnaceItemStacks[1].stackSize--;
             			if(furnaceItemStacks[1].stackSize <= 0) furnaceItemStacks[1] = null;
-            			BlastFurnaceBlock.updateFurnaceBlockState(true, worldObj, x, y, z);
+            			updateFurnace();
             			furnaceUpdated = true;
             		}
             	}
@@ -143,7 +143,11 @@ public class BlastFurnaceBlockEntity extends FurnaceBlockEntity
 
     @Override
     protected void updateFurnace(){
-        BlastFurnaceBlock.updateFurnaceBlockState(currentBurnTime > 0, worldObj, x, y, z);
+        if (worldObj != null) {
+            BlastFurnaceBlock.updateFurnaceBlockState(currentBurnTime > 0, worldObj, x, y, z);
+        } else if (carriedBlock != null) {
+            carriedBlock.block = currentBurnTime > 0 ? Blocks.FURNACE_BLAST_ACTIVE : Blocks.FURNACE_BLAST_IDLE;
+        }
     }
 
     private boolean canSmelt()
diff --git a/src/main/java/net/minecraft/core/block/entity/BlockEntity.java b/src/main/java/net/minecraft/core/block/entity/BlockEntity.java
index 034d03dce..a3e142cc9 100644
--- a/src/main/java/net/minecraft/core/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/BlockEntity.java
@@ -1,29 +1,35 @@
 package net.minecraft.core.block.entity;
 
 import com.mojang.logging.LogUtils;
-import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
 import com.mojang.nbt.CompoundTag;
 import net.minecraft.core.block.piston.MovingPistonBlockEntity;
+import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.Mob;
+import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.net.packet.Packet;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.ICarriable;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
-// Referenced classes of package net.minecraft.src:
-//            NBTTagCompound, World, Block, FurnaceBlockEntity,
-//            ChestBlockEntity, JukeboxBlockEntity, DispenserBlockEntity, SignBlockEntity,
-//            MobSpawnerBlockEntity, NoteBlockEntity, TileEntityPiston
-
-public class BlockEntity
+public class BlockEntity implements ICarriable
 {
     private static final Logger LOGGER = LogUtils.getLogger();
 
     private static final Map<String, Class<? extends BlockEntity>> nameToClassMap = new HashMap<>();
     private static final Map<Class<? extends BlockEntity>, String> classToNameMap = new HashMap<>();
-    public World worldObj;
+    public @Nullable World worldObj; // Null when loading data from nbt and null when held by entity
+    public @Nullable CarriedBlock carriedBlock;
     public int x;
     public int y;
     public int z;
@@ -166,4 +172,148 @@ public class BlockEntity
         addMapping(FlowerJarBlockEntity.class, "FlowerJar");
         addMapping(GoldMeshBlockEntity.class, "MeshGold");
     }
+
+    @Override
+    public void heldTick(World world, Entity holder) {
+
+    }
+
+    public void dropContents(World world, int x, int y, int z) {
+
+    }
+
+    @Override
+    public boolean tryPlace(World world, Entity holder, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced) {
+        x = blockX + side.getOffsetX();
+        y = blockY + side.getOffsetY();
+        z = blockZ + side.getOffsetZ();
+
+        Block currentBlock = world.getBlock(x, y, z);
+        if (currentBlock != null && !currentBlock.hasTag(BlockTags.PLACE_OVERWRITES)) return false;
+        world.setBlockAndMetadataWithNotify(x, y, z, carriedBlock.block.id, carriedBlock.metadata);
+
+        worldObj = world;
+        this.carriedBlock = null;
+        this.validate();
+        world.removeBlockTileEntity(x, y, z);
+        world.setBlockTileEntity(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, yPlaced);
+        }
+        return true;
+    }
+
+    @Override
+    public void drop(World world, Entity holder) {
+        final int holderX = MathHelper.floor(holder.x);
+        final int holderY = MathHelper.floor(holder.y);
+        final int holderZ = MathHelper.floor(holder.z);
+        for (int _y = holderY - 1; _y <= holderY + 1; _y++) {
+            for (int _x = holderX - 1; _x <= holderX + 1; _x++) {
+                for (int _z = holderZ - 1; _z <= holderZ + 1; _z++) {
+                    if (tryPlace(world, holder, _x, _y - 1, _z, Side.TOP, 0, 0)) {
+                        return;
+                    }
+                }
+            }
+        }
+        if (world.isClientSide) return;
+        dropContents(world, holderX, holderY, holderZ);
+        assert carriedBlock != null;
+        carriedBlock.block.dropBlockWithCause(world, EnumDropCause.WORLD, holderX, holderY, holderZ, carriedBlock.metadata, this, null); // TODO this might be scuffed since the position won't have correlated to a real block
+    }
+
+    @Override
+    public boolean canBeCarried(World world, Entity potentialHolder) {
+        return false;
+    }
+
+    @Override
+    public ICarriable pickup(World world, Entity holder) {
+        Block currentBlock = world.getBlock(x, y, z);
+        int currentMeta = world.getBlockMetadata(x, y, z);
+        world.removeBlockTileEntity(x, y, z);
+        Chunk c = world.getChunkFromBlockCoords(x, z);
+        c.setBlockIDRaw(x & 0b1111, y, z & 0b1111, 0);
+        c.recalcHeightmap();
+        world.notifyBlockChange(x, y, z, 0);
+        this.worldObj = null;
+        this.carriedBlock = getCarriedEntry(world, holder, currentBlock, currentMeta);
+        return carriedBlock;
+    }
+
+    public CarriedBlock getCarriedEntry(World world, Entity holder, Block currentBlock, int currentMeta) {
+        return new CarriedBlock(holder, currentBlock, currentMeta, this);
+    }
+
+    public static class CarriedBlock implements ICarriable {
+        // Ignore warnings, nbt read process *should* guarantee these to be non-null
+        public @NotNull Block block;
+        public int metadata;
+        public @NotNull BlockEntity entity;
+        public @NotNull Entity holder;
+        public @NotNull World world;
+        public CarriedBlock(@NotNull Entity holder, @NotNull Block block, int metadata, @NotNull BlockEntity entity) {
+            this.holder = holder;
+            this.block = block;
+            this.metadata = metadata;
+            this.entity = entity;
+            this.world = holder.world;
+        }
+
+        protected CarriedBlock() {
+
+        }
+
+        @Override
+        public void heldTick(World world, Entity holder) {
+            entity.heldTick(world, holder);
+        }
+
+        @Override
+        public boolean tryPlace(World world, Entity holder, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced) {
+            return entity.tryPlace(world, holder, blockX, blockY, blockZ, side, xPlaced, yPlaced);
+        }
+
+        @Override
+        public void drop(World world, Entity holder) {
+            entity.drop(world, holder);
+        }
+
+        @Override
+        public boolean canBeCarried(World world, Entity potentialHolder) {
+            return entity.canBeCarried(world, potentialHolder);
+        }
+
+        @Override
+        public ICarriable pickup(World world, Entity holder) {
+            return entity.pickup(world, holder);
+        }
+
+        @Override
+        public void writeToNBT(CompoundTag tag) {
+            CompoundTag entityTag = new CompoundTag();
+            entity.writeToNBT(entityTag);
+            tag.put("entity", entityTag);
+            tag.putInt("block", block.id);
+            tag.putShort("meta", (short) metadata);
+            tag.putString("type", "blockEntity");
+        }
+
+        @Override
+        public void readFromNBT(CompoundTag tag) {
+            entity = createAndLoadEntity(tag.getCompound("entity"));
+            entity.carriedBlock = this;
+            block = Objects.requireNonNull(Block.getBlock(tag.getInteger("block")));
+            metadata = tag.getShort("meta");
+        }
+
+        public static CarriedBlock createAndLoadCarriedBlock(@NotNull Entity holder, CompoundTag tag) {
+            CarriedBlock carriedBlock = new CarriedBlock();
+            carriedBlock.holder = holder;
+            carriedBlock.readFromNBT(tag);
+            return carriedBlock;
+        }
+    }
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/ChestBlockEntity.java
index f6f7dbd4c..a9b147df7 100644
--- a/src/main/java/net/minecraft/core/block/entity/ChestBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/ChestBlockEntity.java
@@ -5,16 +5,25 @@ package net.minecraft.core.block.entity;
 //            BlockEntity, IInventory, ItemStack, NBTTagCompound,
 //            NBTTagList, World, Player
 
+import com.mojang.logging.LogUtils;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.ChestBlock;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.ItemEntity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.inventory.container.Container;
 import com.mojang.nbt.CompoundTag;
 import com.mojang.nbt.ListTag;
 import net.minecraft.core.player.inventory.InventorySorter;
+import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.world.World;
+import org.slf4j.Logger;
 
 public class ChestBlockEntity extends BlockEntity
     implements Container
 {
+    private static final Logger LOGGER = LogUtils.getLogger();
 
     public ChestBlockEntity()
     {
@@ -132,5 +141,29 @@ public class ChestBlockEntity extends BlockEntity
         InventorySorter.sortInventory(chestContents);
     }
 
+    @Override
+    public void dropContents(World world, int x, int y, int z) {
+        super.dropContents(world, x, y, z);
+        for(int i = 0; i < this.getContainerSize(); i++) {
+            ItemStack itemStack = this.getItem(i);
+            if(itemStack == null) continue;
+            ItemEntity item = world.dropItem(x, y, z, itemStack);
+            item.xd *= 0.5;
+            item.yd *= 0.5;
+            item.zd *= 0.5;
+            item.pickupDelay = 0;
+        }
+    }
+
+    @Override
+    public boolean canBeCarried(World world, Entity potentialHolder) {
+        return true;
+    }
+
+    @Override
+    public CarriedBlock getCarriedEntry(World world, Entity holder, Block currentBlock, int currentMeta) {
+        return super.getCarriedEntry(world, holder, currentBlock, ChestBlock.getMetaWithDirection(ChestBlock.getMetaWithType(currentMeta, ChestBlock.Type.SINGLE), Direction.NORTH));
+    }
+
     private ItemStack[] chestContents;
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/DispenserBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/DispenserBlockEntity.java
index 02643c2c7..63a328024 100644
--- a/src/main/java/net/minecraft/core/block/entity/DispenserBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/DispenserBlockEntity.java
@@ -1,11 +1,15 @@
 package net.minecraft.core.block.entity;
 
+import net.minecraft.core.block.Block;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.ItemEntity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.IDispensable;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.inventory.container.Container;
 import com.mojang.nbt.CompoundTag;
 import com.mojang.nbt.ListTag;
+import net.minecraft.core.world.World;
 
 import java.util.Random;
 
@@ -20,7 +24,7 @@ public class DispenserBlockEntity extends BlockEntity
     public DispenserBlockEntity()
     {
         dispenserContents = new ItemStack[9];
-        dispenserRandom = new Random();
+        random = new Random();
     }
 
     @Override
@@ -66,7 +70,7 @@ public class DispenserBlockEntity extends BlockEntity
         int j = 1;
         for(int k = 0; k < dispenserContents.length; k++)
         {
-            if(dispenserContents[k] != null && dispenserRandom.nextInt(j++) == 0)
+            if(dispenserContents[k] != null && random.nextInt(j++) == 0)
             {
                 i = k;
             }
@@ -166,6 +170,47 @@ public class DispenserBlockEntity extends BlockEntity
         // Do nothing
     }
 
+    @Override
+    public void dropContents(World world, int x, int y, int z) {
+        super.dropContents(world, x, y, z);
+        label0:
+        for (int l = 0; l < this.getContainerSize(); l++) {
+            ItemStack itemstack = this.getItem(l);
+            if (itemstack == null) {
+                continue;
+            }
+            float f = random.nextFloat() * 0.8F + 0.1F;
+            float f1 = random.nextFloat() * 0.8F + 0.1F;
+            float f2 = random.nextFloat() * 0.8F + 0.1F;
+            do {
+                if (itemstack.stackSize <= 0) {
+                    continue label0;
+                }
+                int i1 = random.nextInt(21) + 10;
+                if (i1 > itemstack.stackSize) {
+                    i1 = itemstack.stackSize;
+                }
+                itemstack.stackSize -= i1;
+                ItemEntity entityitem = new ItemEntity(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata()));
+                float f3 = 0.05F;
+                entityitem.xd = (float) random.nextGaussian() * f3;
+                entityitem.yd = (float) random.nextGaussian() * f3 + 0.2F;
+                entityitem.zd = (float) random.nextGaussian() * f3;
+                world.entityJoinedWorld(entityitem);
+            } while (true);
+        }
+    }
+
+    @Override
+    public boolean canBeCarried(World world, Entity potentialHolder) {
+        return true;
+    }
+
+    @Override
+    public CarriedBlock getCarriedEntry(World world, Entity holder, Block currentBlock, int currentMeta) {
+        return super.getCarriedEntry(world, holder, currentBlock, (currentMeta & ~0b111) | 0b010 /*Reset rotation, primarily to make it render in hand properly*/);
+    }
+
     private ItemStack dispenserContents[];
-    private Random dispenserRandom;
+    private final Random random;
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/FlagBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/FlagBlockEntity.java
index 1736888d0..9dbd9fd2c 100644
--- a/src/main/java/net/minecraft/core/block/entity/FlagBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/FlagBlockEntity.java
@@ -6,6 +6,7 @@ import java.util.UUID;
 import com.mojang.nbt.CompoundTag;
 import com.mojang.nbt.ListTag;
 
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
@@ -13,6 +14,7 @@ import net.minecraft.core.net.packet.Packet;
 import net.minecraft.core.net.packet.BlockEntityDataPacket;
 import net.minecraft.core.player.inventory.container.Container;
 import net.minecraft.core.util.helper.UUIDHelper;
+import net.minecraft.core.world.World;
 import org.jetbrains.annotations.Nullable;
 
 public class FlagBlockEntity extends BlockEntity
diff --git a/src/main/java/net/minecraft/core/block/entity/FlowerJarBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/FlowerJarBlockEntity.java
index 32f4af1cc..c94621a16 100644
--- a/src/main/java/net/minecraft/core/block/entity/FlowerJarBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/FlowerJarBlockEntity.java
@@ -1,8 +1,13 @@
 package net.minecraft.core.block.entity;
 
 import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.packet.Packet;
 import net.minecraft.core.net.packet.BlockEntityDataPacket;
+import net.minecraft.core.world.World;
 
 public class FlowerJarBlockEntity extends BlockEntity {
 
@@ -22,8 +27,20 @@ public class FlowerJarBlockEntity extends BlockEntity {
         }
     }
 
+    @Override
+    public void dropContents(World world, int x, int y, int z) {
+        super.dropContents(world, x, y, z);
+        if (flowerInPot > 0 && Block.hasTag(flowerInPot, BlockTags.PLANTABLE_IN_JAR)) {
+            flowerInPot = 0;
+            if (!world.isClientSide) {
+                world.dropItem(x, y, z, new ItemStack(flowerInPot, 1, 0));
+            }
+        }
+    }
+
     @Override
     public Packet getDescriptionPacket() {
         return new BlockEntityDataPacket(this);
     }
+
 }
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/block/entity/FurnaceBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/FurnaceBlockEntity.java
index c2aac8276..92f4f32d4 100644
--- a/src/main/java/net/minecraft/core/block/entity/FurnaceBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/FurnaceBlockEntity.java
@@ -8,24 +8,32 @@ package net.minecraft.core.block.entity;
 
 import com.mojang.nbt.CompoundTag;
 import com.mojang.nbt.ListTag;
+import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.FurnaceBlock;
 import net.minecraft.core.crafting.LookupFuelFurnace;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryFurnace;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.ItemEntity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.inventory.container.Container;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.World;
 
 import java.util.List;
+import java.util.Random;
 
 public class FurnaceBlockEntity extends BlockEntity
         implements Container
 {
+    private final Random random;
 
     public FurnaceBlockEntity()
     {
+        random = new Random();
         furnaceItemStacks = new ItemStack[3];
         currentBurnTime = 0;
         maxBurnTime = 0;
@@ -54,7 +62,7 @@ public class FurnaceBlockEntity extends BlockEntity
             {
                 ItemStack itemstack = furnaceItemStacks[index];
                 furnaceItemStacks[index] = null;
-                if (index == 2) {
+                if (worldObj != null && index == 2) {
                     worldObj.markBlockNeedsUpdate(x, y, z);
                 }
                 return itemstack;
@@ -63,7 +71,7 @@ public class FurnaceBlockEntity extends BlockEntity
             if(furnaceItemStacks[index].stackSize <= 0)
             {
                 furnaceItemStacks[index] = null;
-                if (index == 2) {
+                if (worldObj != null && index == 2) {
                     worldObj.markBlockNeedsUpdate(x, y, z);
                 }
             }
@@ -82,7 +90,7 @@ public class FurnaceBlockEntity extends BlockEntity
         {
             itemstack.stackSize = getMaxStackSize();
         }
-        if (index == 2 && itemstack == null) {
+        if (worldObj != null && index == 2 && itemstack == null) {
             worldObj.markBlockNeedsUpdate(x, y, z);
         }
     }
@@ -171,14 +179,14 @@ public class FurnaceBlockEntity extends BlockEntity
         {
             currentBurnTime--;
         }
-        if(worldObj != null && !worldObj.isClientSide)
+        if(worldObj == null || !worldObj.isClientSide)
         {
-        	if(worldObj.getBlockId(x, y, z) == Blocks.FURNACE_STONE_IDLE.id) {
+        	if(worldObj == null || worldObj.getBlockId(x, y, z) == Blocks.FURNACE_STONE_IDLE.id) {
             	if(currentBurnTime == 0 && furnaceItemStacks[0] == null) {
             		if(furnaceItemStacks[1] != null && furnaceItemStacks[1].itemID == Blocks.NETHERRACK.id) {
             			furnaceItemStacks[1].stackSize--;
             			if(furnaceItemStacks[1].stackSize <= 0) furnaceItemStacks[1] = null;
-            			FurnaceBlock.updateFurnaceBlockState(true, worldObj, x, y, z);
+            			updateFurnace();
             			furnaceUpdated = true;
             		}
             	}
@@ -294,13 +302,17 @@ public class FurnaceBlockEntity extends BlockEntity
         {
             furnaceItemStacks[0] = null;
         }
-        if (wasEmpty && furnaceItemStacks[2] != null) {
+        if (worldObj != null && wasEmpty && furnaceItemStacks[2] != null) {
             worldObj.markBlockNeedsUpdate(x, y, z);
         }
     }
 
     protected void updateFurnace(){
-        FurnaceBlock.updateFurnaceBlockState(currentBurnTime > 0, worldObj, x, y, z);
+        if (worldObj != null) {
+            FurnaceBlock.updateFurnaceBlockState(currentBurnTime > 0, worldObj, x, y, z);
+        } else if (carriedBlock != null) {
+            carriedBlock.block = currentBurnTime > 0 ? Blocks.FURNACE_STONE_ACTIVE : Blocks.FURNACE_STONE_IDLE;
+        }
     }
 
     private int getBurnTimeFromItem(ItemStack itemStack)
@@ -320,11 +332,75 @@ public class FurnaceBlockEntity extends BlockEntity
         return entityplayer.distanceToSqr((double) x + 0.5D, (double) y + 0.5D, (double) z + 0.5D) <= 64D;
     }
 
+    @Override
+    public void dropContents(World world, int x, int y, int z) {
+        super.dropContents(world, x, y, z);
+        if(!FurnaceBlock.keepFurnaceInventory)
+        {
+            label0:
+            for(int l = 0; l < this.getContainerSize(); l++)
+            {
+                ItemStack itemstack = this.getItem(l);
+                if(itemstack == null)
+                {
+                    continue;
+                }
+                float f = random.nextFloat() * 0.8F + 0.1F;
+                float f1 = random.nextFloat() * 0.8F + 0.1F;
+                float f2 = random.nextFloat() * 0.8F + 0.1F;
+                do
+                {
+                    if(itemstack.stackSize <= 0)
+                    {
+                        continue label0;
+                    }
+                    int i1 = random.nextInt(21) + 10;
+                    if(i1 > itemstack.stackSize)
+                    {
+                        i1 = itemstack.stackSize;
+                    }
+                    itemstack.stackSize -= i1;
+                    ItemEntity itemEntity = new ItemEntity(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata()));
+                    float f3 = 0.05F;
+                    itemEntity.xd = (float)random.nextGaussian() * f3;
+                    itemEntity.yd = (float)random.nextGaussian() * f3 + 0.2F;
+                    itemEntity.zd = (float)random.nextGaussian() * f3;
+                    world.entityJoinedWorld(itemEntity);
+                } while(true);
+            }
+
+        }
+    }
+
     @Override
     public void sortContainer() {
         // Do nothing
     }
 
+    @Override
+    public void heldTick(World world, Entity holder) {
+        tick();
+    }
+
+    @Override
+    public boolean tryPlace(World world, Entity holder, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced) {
+        boolean success = super.tryPlace(world, holder, blockX, blockY, blockZ, side, xPlaced, yPlaced);
+        if (success) {
+            updateFurnace();
+        }
+        return success;
+    }
+
+    @Override
+    public boolean canBeCarried(World world, Entity potentialHolder) {
+        return true;
+    }
+
+    @Override
+    public CarriedBlock getCarriedEntry(World world, Entity holder, Block currentBlock, int currentMeta) {
+        return super.getCarriedEntry(world, holder, currentBlock, (currentMeta & ~0b111) | 0b010 /*Reset rotation, primarily to make it render in hand properly*/);
+    }
+
     protected ItemStack[] furnaceItemStacks;
     public int maxBurnTime;
     public int currentCookTime;
diff --git a/src/main/java/net/minecraft/core/block/entity/GoldMeshBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/GoldMeshBlockEntity.java
index 16c673589..6a4366a6f 100644
--- a/src/main/java/net/minecraft/core/block/entity/GoldMeshBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/GoldMeshBlockEntity.java
@@ -1,10 +1,12 @@
 package net.minecraft.core.block.entity;
 
 import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.entity.ItemEntity;
 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.BlockEntityDataPacket;
+import net.minecraft.core.world.World;
 import org.jetbrains.annotations.Nullable;
 
 public class GoldMeshBlockEntity extends BlockEntity {
@@ -62,4 +64,16 @@ public class GoldMeshBlockEntity extends BlockEntity {
     public Packet getDescriptionPacket() {
         return new BlockEntityDataPacket(this);
     }
+
+    @Override
+    public void dropContents(World world, int x, int y, int z) {
+        super.dropContents(world, x, y, z);
+        if (filterItem != null){
+            ItemEntity item = world.dropItem(x, y, z, filterItem);
+            item.xd *= 0.5;
+            item.yd *= 0.5;
+            item.zd *= 0.5;
+            item.pickupDelay = 0;
+        }
+    }
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/JukeboxBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/JukeboxBlockEntity.java
index a0265330f..819537f2b 100644
--- a/src/main/java/net/minecraft/core/block/entity/JukeboxBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/JukeboxBlockEntity.java
@@ -5,6 +5,10 @@ package net.minecraft.core.block.entity;
 //            BlockEntity, NBTTagCompound
 
 import net.minecraft.core.block.Block;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.ItemEntity;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.save.conversion.ChunkConverter;
 import com.mojang.nbt.CompoundTag;
 
@@ -38,5 +42,24 @@ public class JukeboxBlockEntity extends BlockEntity {
         }
     }
 
+    @Override
+    public void dropContents(World world, int x, int y, int z) {
+        if (record != 0) {
+            world.playSoundEffect(1005, x, y, z, 0);
+            world.playRecord(null, null, x, y, z);
+            record = 0;
+            setChanged();
+            world.setBlockMetadataWithNotify(x, y, z, 0);
+            int i1 = record;
+            float f = 0.7F;
+            double d = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
+            double d1 = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.2D + 0.6D;
+            double d2 = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
+            ItemEntity entityitem = new ItemEntity(world, (double) x + d, (double) y + d1, (double) z + d2, new ItemStack(i1, 1, 0));
+            entityitem.pickupDelay = 10;
+            world.entityJoinedWorld(entityitem);
+        }
+    }
+
     public int record;
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/MobSpawnerBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/MobSpawnerBlockEntity.java
index 8383010e4..26be181a2 100644
--- a/src/main/java/net/minecraft/core/block/entity/MobSpawnerBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/MobSpawnerBlockEntity.java
@@ -1,6 +1,7 @@
 package net.minecraft.core.block.entity;
 
 import com.mojang.logging.LogUtils;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityDispatcher;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.enums.MobCategory;
@@ -10,6 +11,7 @@ import com.mojang.nbt.CompoundTag;
 import net.minecraft.core.net.packet.Packet;
 import net.minecraft.core.net.packet.SetMobSpawnerPacket;
 import net.minecraft.core.entity.SpawnListEntry;
+import net.minecraft.core.world.World;
 import org.slf4j.Logger;
 
 import java.util.List;
@@ -192,4 +194,5 @@ public class MobSpawnerBlockEntity extends BlockEntity
         tag.putString("EntityId", mobId != null ? mobId : "none");
         tag.putShort("Delay", (short)delay);
     }
+
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/NoteBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/NoteBlockEntity.java
index 8ca0bac10..e221f94e3 100644
--- a/src/main/java/net/minecraft/core/block/entity/NoteBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/NoteBlockEntity.java
@@ -6,6 +6,7 @@ package net.minecraft.core.block.entity;
 
 import net.minecraft.core.block.material.Material;
 import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.entity.Entity;
 import net.minecraft.core.world.World;
 
 public class NoteBlockEntity extends BlockEntity
@@ -74,4 +75,5 @@ public class NoteBlockEntity extends BlockEntity
 
     public byte note;
     public boolean previousRedstoneState;
+
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/SeatBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/SeatBlockEntity.java
index 7a0463c87..7d7e15ea0 100644
--- a/src/main/java/net/minecraft/core/block/entity/SeatBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/SeatBlockEntity.java
@@ -3,6 +3,7 @@ package net.minecraft.core.block.entity;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.world.IVehicle;
+import net.minecraft.core.world.World;
 
 public class SeatBlockEntity
     extends BlockEntity
@@ -87,4 +88,5 @@ public class SeatBlockEntity
     public float getXRotDelta() {
         return 0;
     }
+
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/SensorBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/SensorBlockEntity.java
index 6919c71a6..1eb9ce2dd 100644
--- a/src/main/java/net/minecraft/core/block/entity/SensorBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/SensorBlockEntity.java
@@ -93,4 +93,5 @@ public class SensorBlockEntity extends BlockEntity {
 			MotionSensorBlock.updateSensorBlockState(false, worldObj, x, y, z);
 		}
 	}
+
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/SignBlockEntity.java
index f34335af4..85cbf6a68 100644
--- a/src/main/java/net/minecraft/core/block/entity/SignBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/SignBlockEntity.java
@@ -1,12 +1,14 @@
 package net.minecraft.core.block.entity;
 
 import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.entity.Entity;
 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.BlockEntityDataPacket;
 import net.minecraft.core.util.helper.UUIDHelper;
+import net.minecraft.core.world.World;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.UUID;
@@ -125,4 +127,5 @@ public class SignBlockEntity extends BlockEntity
     {
         return new BlockEntityDataPacket(this);
     }
+
 }
diff --git a/src/main/java/net/minecraft/core/block/entity/TrommelBlockEntity.java b/src/main/java/net/minecraft/core/block/entity/TrommelBlockEntity.java
index afcd2da8d..f02f1a0da 100644
--- a/src/main/java/net/minecraft/core/block/entity/TrommelBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/entity/TrommelBlockEntity.java
@@ -12,6 +12,8 @@ import net.minecraft.core.crafting.LookupFuelFurnace;
 import net.minecraft.core.data.DataLoader;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel;
 import net.minecraft.core.data.registry.Registries;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.ItemEntity;
 import net.minecraft.core.entity.monster.SlimeMob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Item;
@@ -38,7 +40,7 @@ public class TrommelBlockEntity extends BlockEntity
         currentItemBurnTime = 0;
         itemPopTime = 0;
         maxBurnTime = 50;
-        rand = new Random();
+        random = new Random();
         nextToSieve = 1;
 //        for (ItemStack i : trommellableItems){
 //            simulateTrommelDrops(64 , i);
@@ -174,16 +176,20 @@ public class TrommelBlockEntity extends BlockEntity
         {
             burnTime--;
         }
-        if(worldObj != null && !worldObj.isClientSide)
+        if(worldObj == null || !worldObj.isClientSide)
         {
-        	if(worldObj.getBlockId(x, y, z) == Blocks.TROMMEL_IDLE.id) {
+        	if(worldObj == null || worldObj.getBlockId(x, y, z) == Blocks.TROMMEL_IDLE.id) {
             	if(currentItemBurnTime == 0 && itemStacks[0] == null) {
             		if(itemStacks[4] != null && itemStacks[4].itemID == Blocks.NETHERRACK.id) {
             			itemStacks[4].stackSize--;
             			if(itemStacks[4].stackSize <= 0) itemStacks[4] = null;
-            			TrommelBlock.updateTrommelBlockState(true, worldObj, x, y, z);
-            			flag1 = true;
-            		}
+            			if (worldObj != null) {
+                            TrommelBlock.updateTrommelBlockState(true, worldObj, x, y, z);
+                        } else if (carriedBlock != null) {
+                            carriedBlock.block = Blocks.TROMMEL_ACTIVE;
+                        }
+                        flag1 = true;
+                    }
             	}
         	}
             if(!canProduce(nextToSieve))
@@ -225,7 +231,11 @@ public class TrommelBlockEntity extends BlockEntity
             if(isBurning != (burnTime > 0))
             {
                 flag1 = true;
-                TrommelBlock.updateTrommelBlockState(burnTime > 0, worldObj, x, y, z);
+                if (worldObj != null) {
+                    TrommelBlock.updateTrommelBlockState(burnTime > 0, worldObj, x, y, z);
+                } else if (carriedBlock != null) {
+                    carriedBlock.block = burnTime > 0 ? Blocks.TROMMEL_ACTIVE : Blocks.TROMMEL_IDLE;
+                }
             }
         }
         if(flag1)
@@ -236,9 +246,7 @@ public class TrommelBlockEntity extends BlockEntity
 
     private boolean canProduce(int slotIndex)
     {
-        if(itemStacks[slotIndex] != null && canItemBeTrommeled(itemStacks[slotIndex]))
-            return true;
-        return false;
+        return itemStacks[slotIndex] != null && canItemBeTrommeled(itemStacks[slotIndex]);
     }
 
     public void sieveItem(int slotIndex)
@@ -259,28 +267,31 @@ public class TrommelBlockEntity extends BlockEntity
         	// Check if chest is adjacent
         	int xOffset = 0;
         	int zOffset = 0;
-        	int meta = worldObj.getBlockMetadata(x, y, z) & 0x07;
-        	if (meta == 2)
-        	{
-        		xOffset = -1;
-        	}
-        	else if (meta == 5)
-        	{
-        		zOffset = -1;
-        	}
-        	else if (meta == 3)
-        	{
-        		xOffset = 1;
-        	}
-        	else if (meta == 4)
-        	{
-        		zOffset = 1; 
-        	}
-        	int adjacentId = worldObj.getBlockId(x + xOffset, y, z + zOffset);
+        	if (worldObj != null) {
+                int meta = worldObj.getBlockMetadata(x, y, z) & 0x07;
+                if (meta == 2)
+                {
+                    xOffset = -1;
+                }
+                else if (meta == 5)
+                {
+                    zOffset = -1;
+                }
+                else if (meta == 3)
+                {
+                    xOffset = 1;
+                }
+                else if (meta == 4)
+                {
+                    zOffset = 1;
+                }
+            }
+        	int adjacentId = worldObj != null ? worldObj.getBlockId(x + xOffset, y, z + zOffset) : 0;
         	
         	Container chest = null;
         	if (Block.blocksList[adjacentId] instanceof ChestBlock) {
-        		chest = ChestBlock.getInventory(worldObj, x + xOffset, y, z + zOffset);
+                assert worldObj != null;
+                chest = ChestBlock.getInventory(worldObj, x + xOffset, y, z + zOffset);
         	}
         	
         	if (chest != null)
@@ -305,34 +316,43 @@ public class TrommelBlockEntity extends BlockEntity
         			ItemStack slot = chest.getItem(i);
         			if (slot == null)
         			{
-
         				chest.setItem(i, itemResult);
         				return;
         			}
         		}
         	}
             if(itemResult.stackSize > 0) {
-            	worldObj.dropItem(x, y, z, itemResult);
+                if (worldObj != null) {
+                    worldObj.dropItem(x, y, z, itemResult);
+                } else if (carriedBlock != null) {
+                    carriedBlock.world.dropItem(MathHelper.floor(carriedBlock.holder.x), MathHelper.floor(carriedBlock.holder.y), MathHelper.floor(carriedBlock.holder.z), itemResult);
+                }
+
             }
         }
-        if(rand.nextInt(4000)==0) {
+        if(random.nextInt(4000)==0) {
 
             float f = (((float) 1 - 0.5F)) / 4F;
             float f1 = (((float) 1 - 0.5F)) / 4F;
-            SlimeMob entityslime = new SlimeMob(worldObj);
-            entityslime.setSlimeSize(1);
-            entityslime.moveTo(x + (double)f, y + 1D, z + (double)f1, rand.nextFloat() * 360F, 0.0F);
+            SlimeMob slimeMob = new SlimeMob(carriedBlock != null ? carriedBlock.world : worldObj);
+            slimeMob.setSlimeSize(1);
             float f3 = 0.05F;
-            entityslime.xd = (float) rand.nextGaussian() * f3;
-            entityslime.yd = (float) rand.nextGaussian() * f3 + 0.2F;
-            entityslime.zd = (float) rand.nextGaussian() * f3;
-            worldObj.entityJoinedWorld(entityslime);
+            slimeMob.xd = (float) random.nextGaussian() * f3;
+            slimeMob.yd = (float) random.nextGaussian() * f3 + 0.2F;
+            slimeMob.zd = (float) random.nextGaussian() * f3;
+            if (worldObj != null) {
+                slimeMob.moveTo(x + (double)f, y + 1D, z + (double)f1, random.nextFloat() * 360F, 0.0F);
+                worldObj.entityJoinedWorld(slimeMob);
+            } else if (carriedBlock != null) {
+                slimeMob.moveTo(carriedBlock.holder.x + (double)f, carriedBlock.holder.y + 1D, carriedBlock.holder.z + (double)f1, random.nextFloat() * 360F, 0.0F);
+                carriedBlock.world.entityJoinedWorld(slimeMob);
+            }
         }
     }
 
     private ItemStack getItemResult(ItemStack slotItem)
     {
-        if(rand.nextInt(2) != 0)
+        if(random.nextInt(2) != 0)
             return null;
         List<RecipeEntryTrommel> list = Registries.RECIPES.getAllTrommelRecipes();
         for (RecipeEntryTrommel recipe : list) {
@@ -380,6 +400,44 @@ public class TrommelBlockEntity extends BlockEntity
         // Do nothing
     }
 
+    @Override
+    public void dropContents(World world, int x, int y, int z) {
+        super.dropContents(world, x, y, z);
+        if (!TrommelBlock.keepTrommelInventory)
+        {
+            if(world.getBlockEntity(x, y, z) != null)
+            {
+                label0:
+                for (int l = 0; l < getContainerSize(); l++)
+                {
+                    ItemStack itemstack = getItem(l);
+                    if (itemstack == null) {
+                        continue;
+                    }
+                    float f = random.nextFloat() * 0.8F + 0.1F;
+                    float f1 = random.nextFloat() * 0.8F + 0.1F;
+                    float f2 = random.nextFloat() * 0.8F + 0.1F;
+                    do {
+                        if (itemstack.stackSize <= 0) {
+                            continue label0;
+                        }
+                        int i1 = random.nextInt(21) + 10;
+                        if (i1 > itemstack.stackSize) {
+                            i1 = itemstack.stackSize;
+                        }
+                        itemstack.stackSize -= i1;
+                        ItemEntity item = new ItemEntity(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata()));
+                        float f3 = 0.05F;
+                        item.xd = (float) random.nextGaussian() * f3;
+                        item.yd = (float) random.nextGaussian() * f3 + 0.2F;
+                        item.zd = (float) random.nextGaussian() * f3;
+                        world.entityJoinedWorld(item);
+                    } while (true);
+                }
+            }
+        }
+    }
+
     private void simulateTrommelDrops(int passes, ItemStack blockToTest){
         Map<Object, Integer> trommelDropMap = new HashMap<>();
         System.out.println();
@@ -442,6 +500,21 @@ public class TrommelBlockEntity extends BlockEntity
         trommel.simulateTrommelDrops(10000, Blocks.DIRT_SCORCHED_RICH.getDefaultStack());
     }
 
+    @Override
+    public void heldTick(World world, Entity holder) {
+        tick();
+    }
+
+    @Override
+    public boolean canBeCarried(World world, Entity potentialHolder) {
+        return true;
+    }
+
+    @Override
+    public CarriedBlock getCarriedEntry(World world, Entity holder, Block currentBlock, int currentMeta) {
+        return super.getCarriedEntry(world, holder, currentBlock, (currentMeta & ~0b111) | 0b010 /*Reset rotation, primarily to make it render in hand properly*/);
+    }
+
     private static final Logger LOGGER = LogUtils.getLogger();
     private ItemStack[] itemStacks;
 
@@ -450,5 +523,5 @@ public class TrommelBlockEntity extends BlockEntity
     public int itemPopTime;
     private final int maxBurnTime;
     private int nextToSieve;
-    private final Random rand;
+    private final Random random;
 }
diff --git a/src/main/java/net/minecraft/core/block/piston/BasePistonBlock.java b/src/main/java/net/minecraft/core/block/piston/BasePistonBlock.java
index 05b2a0555..42e14c874 100644
--- a/src/main/java/net/minecraft/core/block/piston/BasePistonBlock.java
+++ b/src/main/java/net/minecraft/core/block/piston/BasePistonBlock.java
@@ -84,40 +84,40 @@ public class BasePistonBlock extends Block
     }
 
     private boolean getNeighborSignal(World world, int x, int y, int z, int direction) {
-        if(direction != 0 && world.isBlockIndirectlyProvidingPowerTo(x, y - 1, z, Side.BOTTOM)) {
+        if(direction != 0 && world.getSignal(x, y - 1, z, Side.BOTTOM)) {
             return true;
         }
-        if(direction != 1 && world.isBlockIndirectlyProvidingPowerTo(x, y + 1, z, Side.TOP)) {
+        if(direction != 1 && world.getSignal(x, y + 1, z, Side.TOP)) {
             return true;
         }
-        if(direction != 2 && world.isBlockIndirectlyProvidingPowerTo(x, y, z - 1, Side.NORTH)) {
+        if(direction != 2 && world.getSignal(x, y, z - 1, Side.NORTH)) {
             return true;
         }
-        if(direction != 3 && world.isBlockIndirectlyProvidingPowerTo(x, y, z + 1, Side.SOUTH)) {
+        if(direction != 3 && world.getSignal(x, y, z + 1, Side.SOUTH)) {
             return true;
         }
-        if(direction != 5 && world.isBlockIndirectlyProvidingPowerTo(x + 1, y, z, Side.EAST)) {
+        if(direction != 5 && world.getSignal(x + 1, y, z, Side.EAST)) {
             return true;
         }
-        if(direction != 4 && world.isBlockIndirectlyProvidingPowerTo(x - 1, y, z, Side.WEST)) {
+        if(direction != 4 && world.getSignal(x - 1, y, z, Side.WEST)) {
             return true;
         }
-        if(world.isBlockIndirectlyProvidingPowerTo(x, y, z, Side.BOTTOM)) {
+        if(world.getSignal(x, y, z, Side.BOTTOM)) {
             return true;
         }
-        if(world.isBlockIndirectlyProvidingPowerTo(x, y + 2, z, Side.TOP)) {
+        if(world.getSignal(x, y + 2, z, Side.TOP)) {
             return true;
         }
-        if(world.isBlockIndirectlyProvidingPowerTo(x, y + 1, z - 1, Side.NORTH)) {
+        if(world.getSignal(x, y + 1, z - 1, Side.NORTH)) {
             return true;
         }
-        if(world.isBlockIndirectlyProvidingPowerTo(x, y + 1, z + 1, Side.SOUTH)) {
+        if(world.getSignal(x, y + 1, z + 1, Side.SOUTH)) {
             return true;
         }
-        if(world.isBlockIndirectlyProvidingPowerTo(x - 1, y + 1, z, Side.WEST)) {
+        if(world.getSignal(x - 1, y + 1, z, Side.WEST)) {
             return true;
         }
-        return world.isBlockIndirectlyProvidingPowerTo(x + 1, y + 1, z, Side.EAST);
+        return world.getSignal(x + 1, y + 1, z, Side.EAST);
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/core/block/piston/MovingPistonBlockEntity.java b/src/main/java/net/minecraft/core/block/piston/MovingPistonBlockEntity.java
index 60f1f042e..e03fe5436 100644
--- a/src/main/java/net/minecraft/core/block/piston/MovingPistonBlockEntity.java
+++ b/src/main/java/net/minecraft/core/block/piston/MovingPistonBlockEntity.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.phys.AABB;
 import com.mojang.nbt.CompoundTag;
 import net.minecraft.core.block.logic.PistonDirections;
+import net.minecraft.core.world.World;
 
 import java.util.*;
 
@@ -185,6 +186,11 @@ public class MovingPistonBlockEntity extends BlockEntity
         tag.putBoolean("extending", extending);
     }
 
+    @Override
+    public boolean canBeCarried(World world, Entity potentialHolder) {
+        return false;
+    }
+
     private int movedId;
     private int movedData;
     private int direction;
diff --git a/src/main/java/net/minecraft/core/entity/Entity.java b/src/main/java/net/minecraft/core/entity/Entity.java
index 20f667b75..62350c855 100644
--- a/src/main/java/net/minecraft/core/entity/Entity.java
+++ b/src/main/java/net/minecraft/core/entity/Entity.java
@@ -3,6 +3,7 @@ package net.minecraft.core.entity;
 import java.util.List;
 import java.util.Random;
 
+import net.minecraft.core.world.ICarriable;
 import org.jetbrains.annotations.Nullable;
 
 import com.mojang.nbt.CompoundTag;
@@ -1293,10 +1294,14 @@ public abstract class Entity
     {
     }
 
-    public void setEquippedSlot(int i, int j, int k, CompoundTag tag)
+    public void setEquippedSlot(int slot, int itemID, int itemMeta, CompoundTag tag)
     {
     }
 
+    public void setHeldObject(@Nullable ICarriable heldObject) {
+
+    }
+
     public boolean isOnFire()
     {
         return !fireImmune && remainingFireTicks > 0 || getSharedFlag(FLAG_ONFIRE);
diff --git a/src/main/java/net/minecraft/core/entity/PaintingEntity.java b/src/main/java/net/minecraft/core/entity/PaintingEntity.java
index 66ebccf92..af730d430 100644
--- a/src/main/java/net/minecraft/core/entity/PaintingEntity.java
+++ b/src/main/java/net/minecraft/core/entity/PaintingEntity.java
@@ -313,7 +313,7 @@ public class PaintingEntity extends Entity
             setStack(new ItemStack(stack.getItem(), 1, stack.getMetadata()));
             stack.consumeItem(player);
             if (stack.stackSize <= 0) {
-                player.inventory.setItem(player.inventory.currentItem, null);
+                player.inventory.setItem(player.inventory.getCurrentItemIndex(), null);
             }
             if (paintingStack != null && player.getGamemode().consumeBlocks()){
                 player.inventory.insertItem(paintingStack, true);
diff --git a/src/main/java/net/minecraft/core/entity/animal/WolfMob.java b/src/main/java/net/minecraft/core/entity/animal/WolfMob.java
index eef1e84b7..6165bd753 100644
--- a/src/main/java/net/minecraft/core/entity/animal/WolfMob.java
+++ b/src/main/java/net/minecraft/core/entity/animal/WolfMob.java
@@ -665,7 +665,7 @@ public class WolfMob extends Animal
                 itemstack.consumeItem(entityplayer);
                 if(itemstack.stackSize <= 0)
                 {
-                    entityplayer.inventory.setItem(entityplayer.inventory.currentItem, null);
+                    entityplayer.inventory.setItem(entityplayer.inventory.getCurrentItemIndex(), null);
                 }
                 if(!world.isClientSide)
                 {
@@ -698,7 +698,7 @@ public class WolfMob extends Animal
                 		itemstack.stackSize--;
                 		if(itemstack.stackSize <= 0)
                 		{
-                			entityplayer.inventory.setItem(entityplayer.inventory.currentItem, null);
+                			entityplayer.inventory.setItem(entityplayer.inventory.getCurrentItemIndex(), null);
                 		}                		
                 	}
                     heal(((FoodItem)Items.FOOD_PORKCHOP_RAW).getHealAmount());
@@ -716,7 +716,7 @@ public class WolfMob extends Animal
                     if (entityplayer.getGamemode().consumeBlocks()) {
                         itemstack.stackSize--;
                         if (itemstack.stackSize <= 0) {
-                            entityplayer.inventory.setItem(entityplayer.inventory.currentItem, null);
+                            entityplayer.inventory.setItem(entityplayer.inventory.getCurrentItemIndex(), null);
                         }
                     }
                     return true;
diff --git a/src/main/java/net/minecraft/core/entity/player/Player.java b/src/main/java/net/minecraft/core/entity/player/Player.java
index b580af12f..af732e9aa 100644
--- a/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -61,11 +61,13 @@ import net.minecraft.core.util.helper.DamageType;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.ICarriable;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
 import net.minecraft.core.world.chunk.provider.IChunkProvider;
 import net.minecraft.core.world.weather.Weathers;
 import net.minecraft.server.entity.player.ServerPlayer;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -108,7 +110,8 @@ public abstract class Player extends Mob
     public float timeInPortal;
     public float prevTimeInPortal;
     private final int damageRemainder;
-    public FishingBobberEntity bobberEntity;
+    public @Nullable FishingBobberEntity bobberEntity;
+    protected @Nullable ICarriable heldObject;
     public volatile String skinURL;
     public volatile String capeURL;
     public boolean slimModel = false;
@@ -236,6 +239,9 @@ public abstract class Player extends Mob
             }
         }
         super.tick();
+        if (heldObject != null) {
+            heldObject.heldTick(world, this);
+        }
 
         if(!world.isClientSide && craftingInventory != null && !craftingInventory.stillValid(this))
         {
@@ -413,11 +419,17 @@ public abstract class Player extends Mob
         {
             dropPlayerItemWithRandomChoice(new ItemStack(Items.SIGN, 1), true);
         }
+
         if (!world.getGameRuleValue(GameRules.KEEP_INVENTORY))
         {
             craftingInventory.onCraftGuiClosed(this);
             inventory.dropAllItems();
         }
+        if (heldObject != null) { // TODO consider whether making the held object kept with keep inventory is a good idea
+            heldObject.drop(world, this);
+            heldObject = null;
+        }
+
         if(entityKilledBy != null)
         {
             xd = -MathHelper.cos(((attackedAtYaw + yRot) * MathHelper.PI) / 180F) * 0.1F;
@@ -596,7 +608,7 @@ public abstract class Player extends Mob
 
     public void dropCurrentItem(boolean dropFullStack)
     {
-        dropPlayerItemWithRandomChoice(inventory.removeItem(inventory.currentItem, dropFullStack ? 64 : 1), false);
+        dropPlayerItemWithRandomChoice(inventory.removeItem(inventory.getCurrentItemIndex(), dropFullStack ? 64 : 1), false);
     }
 
     public void dropPlayerItem(ItemStack itemstack)
@@ -606,8 +618,18 @@ public abstract class Player extends Mob
 
     public void setHotbarOffset(int offset)
     {
-        inventory.hotbarOffset = offset;
+        inventory.setHotbarOffset(offset, false);
     }
+
+    @Override
+    public void setHeldObject(@Nullable ICarriable heldObject) {
+        this.heldObject = heldObject;
+    }
+
+    public @Nullable ICarriable getHeldObject() {
+        return heldObject;
+    }
+
     @Override
     public boolean isPickable() {
         if (getGamemode().canInteract()){
@@ -706,6 +728,8 @@ public abstract class Player extends Mob
         super.readAdditionalSaveData(tag);
         ListTag nbttaglist = tag.getList("Inventory");
         inventory.readFromNBT(nbttaglist);
+        inventory.setCurrentItemIndex(tag.getIntegerOrDefault("CurrentItem", inventory.getCurrentItemIndex()), true);
+        inventory.setHotbarOffset(tag.getIntegerOrDefault("HotbarOffset", inventory.getHotbarOffset()), true);
         int dim = tag.getInteger("Dimension");
         if (dim == -1) dim = 1;
         dimension = dim;
@@ -726,6 +750,10 @@ public abstract class Player extends Mob
         {
             lastDeathCoordinate = new ChunkCoordinates(tag.getInteger("LastDeathX"), tag.getInteger("LastDeathY"), tag.getInteger("LastDeathZ"));
         }
+        if (tag.containsKey("HeldObject")) {
+            CompoundTag heldTag = tag.getCompound("HeldObject");
+            heldObject = ICarriable.createAndLoadCarriable(this, heldTag);
+        }
     }
 
     @Override
@@ -733,6 +761,8 @@ public abstract class Player extends Mob
     {
         super.addAdditionalSaveData(tag);
         tag.put("Inventory", inventory.writeToNBT(new ListTag()));
+        tag.putInt("CurrentItem", inventory.getCurrentItemIndex());
+        tag.putInt("HotbarOffset", inventory.getHotbarOffset());
         tag.putInt("Dimension", dimension);
         tag.putBoolean("Sleeping", sleeping);
         tag.putShort("SleepTimer", (short)sleepTimer);
@@ -751,6 +781,12 @@ public abstract class Player extends Mob
             tag.putInt("LastDeathY", lastDeathCoordinate.y);
             tag.putInt("LastDeathZ", lastDeathCoordinate.z);
         }
+
+        if (heldObject != null) {
+            CompoundTag heldTag = new CompoundTag();
+            heldObject.writeToNBT(heldTag);
+            tag.put("HeldObject", heldTag);
+        }
     }
 
     @Override
@@ -978,7 +1014,7 @@ public abstract class Player extends Mob
 
     public void destroyCurrentEquippedItem()
     {
-        inventory.setItem(inventory.currentItem, null);
+        inventory.setItem(inventory.getCurrentItemIndex(), null);
     }
 
     @Override
@@ -1492,20 +1528,20 @@ public abstract class Player extends Mob
     	
 		//Find item in hotbar, and select it
 		for(int i=0; i < 9; i++) {
-			ItemStack stack = inventory.getItem(i + inventory.hotbarOffset);
+			ItemStack stack = inventory.getItem(i + inventory.getHotbarOffset());
 			if(stack != null && stack.itemID == selectItem.itemID && stack.getMetadata() == selectItem.getMetadata()) {
-				setCurrentItem(i + inventory.hotbarOffset);
+				setCurrentItem(i + inventory.getHotbarOffset());
 				return;
 			}
 		}
 		
 		//Find empty hotbar slot
 		int emptyHotbarSlot = -1;
-		int slot = inventory.currentItem;
+		int slot = inventory.getCurrentItemIndex();
 		for(int i=0; i < 9; i++) {
-			if(inventory.getItem(i + inventory.hotbarOffset) == null) {
-				emptyHotbarSlot = i + inventory.hotbarOffset;
-				slot = i + inventory.hotbarOffset;
+			if(inventory.getItem(i + inventory.getHotbarOffset()) == null) {
+				emptyHotbarSlot = i + inventory.getHotbarOffset();
+				slot = i + inventory.getHotbarOffset();
 				break;
 			}
 		}
@@ -1533,7 +1569,7 @@ public abstract class Player extends Mob
 					}
 				}
 				
-				int createItemInsertSlot = emptyHotbarSlot != -1 ? emptyHotbarSlot : inventory.currentItem;
+				int createItemInsertSlot = emptyHotbarSlot != -1 ? emptyHotbarSlot : inventory.getCurrentItemIndex();
 				selectItem.stackSize = 1;
 				if(emptySlot != -1) {
 					swapItems(emptySlot, createItemInsertSlot);
@@ -1550,7 +1586,7 @@ public abstract class Player extends Mob
     }
     
     public void setCurrentItem(int i) {
-        inventory.currentItem = i;
+        inventory.setCurrentItemIndex(i, false);
     }
     
     public void swapItems(int slot1, int slot2) {
diff --git a/src/main/java/net/minecraft/core/entity/vehicle/BoatEntity.java b/src/main/java/net/minecraft/core/entity/vehicle/BoatEntity.java
index c5639823a..bcdba4599 100644
--- a/src/main/java/net/minecraft/core/entity/vehicle/BoatEntity.java
+++ b/src/main/java/net/minecraft/core/entity/vehicle/BoatEntity.java
@@ -494,7 +494,7 @@ public class BoatEntity extends Entity
             if (entityplayer.getHeldItem() != null && entityplayer.getHeldItem().itemID == Items.FLAG.id && flag == null)
             {
                 this.flag = entityplayer.getHeldItem().copy();
-                entityplayer.inventory.setItem(entityplayer.inventory.currentItem, null);
+                entityplayer.inventory.setItem(entityplayer.inventory.getCurrentItemIndex(), null);
                 createTileEntity();
                 world.sendTrackedEntityDataPacket(this);
                 return true;
diff --git a/src/main/java/net/minecraft/core/entity/vehicle/MinecartEntity.java b/src/main/java/net/minecraft/core/entity/vehicle/MinecartEntity.java
index f4e610050..934ca02ee 100644
--- a/src/main/java/net/minecraft/core/entity/vehicle/MinecartEntity.java
+++ b/src/main/java/net/minecraft/core/entity/vehicle/MinecartEntity.java
@@ -5,6 +5,8 @@ import com.mojang.nbt.ListTag;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.RailBlock;
 import net.minecraft.core.block.Blocks;
+import net.minecraft.core.block.entity.BlockEntity;
+import net.minecraft.core.block.entity.ChestBlockEntity;
 import net.minecraft.core.block.logic.RailDirection;
 import net.minecraft.core.crafting.LookupFuelFurnace;
 import net.minecraft.core.entity.Entity;
@@ -692,6 +694,19 @@ public class MinecartEntity extends Entity implements Container {
 	public boolean interact(Player player) {
         switch (type){
             case PASSENGER_CART:
+                if (!world.isClientSide && passenger == null && player.isSneaking() && player.getHeldObject() instanceof BlockEntity.CarriedBlock) {
+                    BlockEntity.CarriedBlock carriedBlock = (BlockEntity.CarriedBlock) player.getHeldObject();
+                    if (carriedBlock.entity instanceof ChestBlockEntity) {
+                        ChestBlockEntity chest = (ChestBlockEntity) carriedBlock.entity;
+                        this.type = CHEST_CART;
+                        for (int i = 0; i < this.getContainerSize(); i++) {
+                            this.setItem(i, chest.getItem(i));
+                            chest.setItem(i, null);
+                        }
+                        player.setHeldObject(null);
+                        return true;
+                    }
+                }
                 if(passenger != null && (passenger instanceof Player) && passenger != player) {
                     return true;
                 }
@@ -701,7 +716,19 @@ public class MinecartEntity extends Entity implements Container {
                 break;
             case CHEST_CART:
                 if(!world.isClientSide) {
-                    player.displayContainerScreen(this);
+                    if (player.isSneaking()) {
+                        ChestBlockEntity blockEntity = new ChestBlockEntity();
+                        for (int i = 0; i < this.getContainerSize(); i++) {
+                            blockEntity.setItem(i, this.getItem(i));
+                            this.setItem(i, null);
+                        }
+                        blockEntity.worldObj = null;
+                        blockEntity.carriedBlock = blockEntity.getCarriedEntry(world, player, Blocks.CHEST_PLANKS_OAK, 0);
+                        player.setHeldObject(blockEntity.carriedBlock);
+                        this.type = PASSENGER_CART;
+                    } else {
+                        player.displayContainerScreen(this);
+                    }
                 }
                 break;
             case FURNACE_CART:
@@ -709,7 +736,7 @@ public class MinecartEntity extends Entity implements Container {
                 if(itemstack != null && LookupFuelFurnace.instance.getFuelYield(itemstack.itemID) > 0) {
                     if(--itemstack.stackSize <= 0)
                     {
-                        player.inventory.setItem(player.inventory.currentItem, null);
+                        player.inventory.setItem(player.inventory.getCurrentItemIndex(), null);
                     }
                     fuel += (int) ((LookupFuelFurnace.instance.getFuelYield(itemstack.itemID)/1600F) * 1200);
                 }
diff --git a/src/main/java/net/minecraft/core/item/DoorItem.java b/src/main/java/net/minecraft/core/item/DoorItem.java
index 1f09354a2..24df706cd 100644
--- a/src/main/java/net/minecraft/core/item/DoorItem.java
+++ b/src/main/java/net/minecraft/core/item/DoorItem.java
@@ -58,13 +58,15 @@ public class DoorItem extends Item {
 			meta |= 0x8;
 		}
 		
-		world.editingBlocks = true;
+		world.noNeighborUpdate = true;
 		world.setBlockAndMetadataWithNotify(blockX, blockY, blockZ, doorBlockBottom.id, meta);
 		world.setBlockAndMetadataWithNotify(blockX, blockY + 1, blockZ, doorBlockTop.id, meta);
-		world.editingBlocks = false;
+		world.noNeighborUpdate = false;
 		world.notifyBlocksOfNeighborChange(blockX, blockY, blockZ, doorBlockBottom.id);
 		world.notifyBlocksOfNeighborChange(blockX, blockY + 1, blockZ, doorBlockTop.id);
 		world.playBlockSoundEffect(entityplayer, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, doorBlockBottom, EnumBlockSoundEffectType.PLACE);
+		doorBlockBottom.onBlockPlacedByMob(world, blockX, blockY, blockZ, side, entityplayer, yPlaced);
+		doorBlockTop.onBlockPlacedByMob(world, blockX, blockY + 1, blockZ, side, entityplayer, yPlaced);
 		itemstack.consumeItem(entityplayer);
 		return true;
 	}
diff --git a/src/main/java/net/minecraft/core/item/EmptyBucketItem.java b/src/main/java/net/minecraft/core/item/EmptyBucketItem.java
index db4931281..f0ad17c3c 100644
--- a/src/main/java/net/minecraft/core/item/EmptyBucketItem.java
+++ b/src/main/java/net/minecraft/core/item/EmptyBucketItem.java
@@ -77,7 +77,7 @@ public class EmptyBucketItem extends Item
 
     public static boolean useBucket(Player player, ItemStack itemToGive) {
         if(player.inventory.getCurrentItem().stackSize <= 1) {
-            player.inventory.setItem(player.inventory.currentItem, itemToGive);
+            player.inventory.setItem(player.inventory.getCurrentItemIndex(), itemToGive);
             return true;
         } else {
         	player.inventory.insertItem(itemToGive, true);
diff --git a/src/main/java/net/minecraft/core/item/JarItem.java b/src/main/java/net/minecraft/core/item/JarItem.java
index 55eb7b9fc..6ec22d8b3 100644
--- a/src/main/java/net/minecraft/core/item/JarItem.java
+++ b/src/main/java/net/minecraft/core/item/JarItem.java
@@ -74,7 +74,7 @@ public class JarItem extends PlaceableItem {
 
     public static boolean fillJar(Player player, ItemStack itemToGive){
         if(player.inventory.getCurrentItem().stackSize <= 1) {
-            player.inventory.setItem(player.inventory.currentItem, itemToGive);
+            player.inventory.setItem(player.inventory.getCurrentItemIndex(), itemToGive);
         } else {
         	player.inventory.insertItem(itemToGive, true);
         }
diff --git a/src/main/java/net/minecraft/core/item/PaintedDoorItem.java b/src/main/java/net/minecraft/core/item/PaintedDoorItem.java
index 3219b1b5a..2d451cb76 100644
--- a/src/main/java/net/minecraft/core/item/PaintedDoorItem.java
+++ b/src/main/java/net/minecraft/core/item/PaintedDoorItem.java
@@ -47,10 +47,10 @@ public class PaintedDoorItem extends DoorItem {
         }
         meta |= (15 - itemstack.getMetadata()) << 4 &0xF0;
 
-        world.editingBlocks = true;
+        world.noNeighborUpdate = true;
         world.setBlockAndMetadataWithNotify(blockX, blockY, blockZ, doorBlockBottom.id, meta);
         world.setBlockAndMetadataWithNotify(blockX, blockY + 1, blockZ, doorBlockTop.id, meta);
-        world.editingBlocks = false;
+        world.noNeighborUpdate = false;
         world.notifyBlocksOfNeighborChange(blockX, blockY, blockZ, doorBlockBottom.id);
         world.notifyBlocksOfNeighborChange(blockX, blockY + 1, blockZ, doorBlockTop.id);
         world.playBlockSoundEffect(entityplayer,blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, doorBlockBottom, EnumBlockSoundEffectType.PLACE);
diff --git a/src/main/java/net/minecraft/core/net/command/commands/CloneCommand.java b/src/main/java/net/minecraft/core/net/command/commands/CloneCommand.java
index c5d1a7170..1ca536007 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/CloneCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/CloneCommand.java
@@ -144,7 +144,7 @@ public class CloneCommand {
             throw INSIDE_CLONED_AREA.create();
         }
 
-        start.getWorld().editingBlocks = true;
+        start.getWorld().noNeighborUpdate = true;
         Map<IntegerCoordinates, ClonedBlock> map = new HashMap<>();
         for (int x = minX; x <= maxX; x++) {
             for (int y = minY; y <= maxY; y++) {
@@ -161,10 +161,10 @@ public class CloneCommand {
             }
         }
         if (!destination.getWorld().isBlockLoaded(destinationX, destinationY, destinationZ)) throw DESTINATION_NOT_LOADED.create();
-        start.getWorld().editingBlocks = false;
+        start.getWorld().noNeighborUpdate = false;
 
         int clonedBlocks = 0;
-        destination.getWorld().editingBlocks = true;
+        destination.getWorld().noNeighborUpdate = true;
         for (Map.Entry<IntegerCoordinates, ClonedBlock> entry : map.entrySet()) {
             int offsetDestinationX = destinationX + entry.getKey().getX(source);
             int offsetDestinationY = destinationY + entry.getKey().getY(source, true);
@@ -179,7 +179,7 @@ public class CloneCommand {
                 CommandHelper.setBlockEntity(destination.getWorld(), offsetDestinationX, offsetDestinationY, offsetDestinationZ, entry.getValue().getBlockEntity());
             }
         }
-        destination.getWorld().editingBlocks = false;
+        destination.getWorld().noNeighborUpdate = false;
         source.sendTranslatableMessage(clonedBlocks == 1 ? "command.commands.clone.success_single" : "command.commands.clone.success_multiple", clonedBlocks);
         return clonedBlocks;
     }
diff --git a/src/main/java/net/minecraft/core/net/command/commands/FillCommand.java b/src/main/java/net/minecraft/core/net/command/commands/FillCommand.java
index 0ef81bbe1..30490476a 100644
--- a/src/main/java/net/minecraft/core/net/command/commands/FillCommand.java
+++ b/src/main/java/net/minecraft/core/net/command/commands/FillCommand.java
@@ -112,7 +112,7 @@ public class FillCommand {
     }
 
     public static int fillReplace(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block, @Nullable BlockInput filter, boolean destroy) throws CommandSyntaxException {
-        world.editingBlocks = true;
+        world.noNeighborUpdate = true;
         int minX = Math.min(first.getX(source), second.getX(source));
         int minY = Math.min(first.getY(source, true), second.getY(source, true));
         int minZ = Math.min(first.getZ(source), second.getZ(source));
@@ -140,13 +140,13 @@ public class FillCommand {
                 }
             }
         }
-        world.editingBlocks = false;
+        world.noNeighborUpdate = false;
 
         return blocksFilled;
     }
 
     public static int fillHollow(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block) throws CommandSyntaxException {
-        world.editingBlocks = true;
+        world.noNeighborUpdate = true;
         int minX = Math.min(first.getX(source), second.getX(source));
         int minY = Math.min(first.getY(source, true), second.getY(source, true));
         int minZ = Math.min(first.getZ(source), second.getZ(source));
@@ -170,13 +170,13 @@ public class FillCommand {
                 }
             }
         }
-        world.editingBlocks = false;
+        world.noNeighborUpdate = false;
 
         return blocksFilled;
     }
 
     public static int fillOutline(CommandSource source, World world, IntegerCoordinates first, IntegerCoordinates second, BlockInput block) throws CommandSyntaxException {
-        world.editingBlocks = true;
+        world.noNeighborUpdate = true;
         int minX = Math.min(first.getX(source), second.getX(source));
         int minY = Math.min(first.getY(source, true), second.getY(source, true));
         int minZ = Math.min(first.getZ(source), second.getZ(source));
@@ -199,7 +199,7 @@ public class FillCommand {
                 }
             }
         }
-        world.editingBlocks = false;
+        world.noNeighborUpdate = false;
 
         return blocksFilled;
     }
diff --git a/src/main/java/net/minecraft/core/net/handler/PacketHandler.java b/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
index cffa6be0f..0d5d9d04c 100644
--- a/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
+++ b/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
@@ -243,6 +243,10 @@ public abstract class PacketHandler
         handleInvalidPacket(setEquippedItemPacket5Playerinventory);
     }
 
+    public void handlePlayerHeldObject(SetHeldObjectPacket setHeldObjectPacket) {
+        handleInvalidPacket(setHeldObjectPacket);
+    }
+
     public void handleTransaction(ContainerAckPacket containerAckPacket)
     {
         handleInvalidPacket(containerAckPacket);
diff --git a/src/main/java/net/minecraft/core/net/packet/AddPlayerPacket.java b/src/main/java/net/minecraft/core/net/packet/AddPlayerPacket.java
index 0e875ab74..91e537c1c 100644
--- a/src/main/java/net/minecraft/core/net/packet/AddPlayerPacket.java
+++ b/src/main/java/net/minecraft/core/net/packet/AddPlayerPacket.java
@@ -1,9 +1,11 @@
 package net.minecraft.core.net.packet;
 
+import com.mojang.nbt.CompoundTag;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.handler.PacketHandler;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.*;
 import java.util.UUID;
@@ -33,6 +35,13 @@ public class AddPlayerPacket extends Packet
         currentItem = itemstack != null ? itemstack.itemID : 0;
         nickname = entityplayer.getDisplayName();
         chatColor = entityplayer.chatColor;
+        if (entityplayer.getHeldObject() == null) {
+            heldObjectTag = null;
+        } else {
+            CompoundTag tag = new CompoundTag();
+            entityplayer.getHeldObject().writeToNBT(tag);
+            heldObjectTag = tag;
+        }
     }
 
     @Override
@@ -50,6 +59,12 @@ public class AddPlayerPacket extends Packet
         currentItem = dis.readShort();
         nickname = readString(dis, 32);
         chatColor = dis.readByte();
+
+        if (dis.readByte() == 1) {
+            heldObjectTag = readCompressedCompoundTag(dis);
+        } else {
+            heldObjectTag = null;
+        }
     }
 
     @Override
@@ -67,6 +82,13 @@ public class AddPlayerPacket extends Packet
         dos.writeShort(currentItem);
         writeString(nickname, dos);
         dos.writeByte(chatColor);
+
+        if (heldObjectTag != null) {
+            dos.writeByte(1);
+            writeCompressedCompoundTag(heldObjectTag, dos);
+        } else {
+            dos.writeByte(0);
+        }
     }
 
     @Override
@@ -90,6 +112,7 @@ public class AddPlayerPacket extends Packet
     public byte rotation;
     public byte pitch;
     public int currentItem;
+    public @Nullable CompoundTag heldObjectTag;
     public String nickname;
     public byte chatColor;
 }
diff --git a/src/main/java/net/minecraft/core/net/packet/Packet.java b/src/main/java/net/minecraft/core/net/packet/Packet.java
index f771af942..bb5b4a064 100644
--- a/src/main/java/net/minecraft/core/net/packet/Packet.java
+++ b/src/main/java/net/minecraft/core/net/packet/Packet.java
@@ -273,6 +273,7 @@ public abstract class Packet
         addMapping(24, true, false, AddMobPacket.class);
         addMapping(25, true, false, AddPaintingPacket.class);
         addMapping(26, true, true, BoatControlPacket.class);
+        addMapping(27, true, true, SetHeldObjectPacket.class);
         addMapping(28, true, false, SetEntityMotionPacket.class);
         addMapping(29, true, false, RemoveEntityPacket.class);
         addMapping(30, true, false, MoveEntityPacket.class);
@@ -309,7 +310,7 @@ public abstract class Packet
         addMapping(105, true, false, ContainerSetDataPacket.class);
         addMapping(106, true, true, ContainerAckPacket.class);
         addMapping(107, false, true, UpdateCreativeInventoryPacket.class);
-        addMapping(108, false, true, SetHotbarOffsetPacket.class);
+        addMapping(108, true, true, SetHotbarOffsetPacket.class);
         addMapping(120, true, false, CommandManagerPacket.class);
         addMapping(121, false, true, RequestCommandManagerPacket.class);
         addMapping(130, false, true, SignUpdatePacket.class);
diff --git a/src/main/java/net/minecraft/core/net/packet/SetHeldObjectPacket.java b/src/main/java/net/minecraft/core/net/packet/SetHeldObjectPacket.java
new file mode 100644
index 000000000..f65a465e3
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/packet/SetHeldObjectPacket.java
@@ -0,0 +1,57 @@
+package net.minecraft.core.net.packet;
+
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.net.handler.PacketHandler;
+import net.minecraft.core.world.ICarriable;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class SetHeldObjectPacket extends Packet{
+    public int entityID;
+    public @Nullable CompoundTag objectTag;
+    public SetHeldObjectPacket() {
+
+    }
+
+    public SetHeldObjectPacket(int entityID, @Nullable ICarriable object) {
+        this.entityID = entityID;
+        if (object != null) {
+            CompoundTag tag = new CompoundTag();
+            object.writeToNBT(tag);
+            objectTag = tag;
+        }
+    }
+    @Override
+    public void read(DataInputStream dis) throws IOException {
+        entityID = dis.readInt();
+        if (dis.readByte() == 1) {
+            objectTag = readCompressedCompoundTag(dis);
+        } else {
+            objectTag = null;
+        }
+    }
+
+    @Override
+    public void write(DataOutputStream dos) throws IOException {
+        dos.writeInt(entityID);
+        if (objectTag != null) {
+            dos.writeByte(1);
+            writeCompressedCompoundTag(objectTag, dos);
+        } else {
+            dos.writeByte(0);
+        }
+    }
+
+    @Override
+    public void handlePacket(PacketHandler packetHandler) {
+        packetHandler.handlePlayerHeldObject(this);
+    }
+
+    @Override
+    public int getEstimatedSize() {
+        return 0;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/player/inventory/container/Container.java b/src/main/java/net/minecraft/core/player/inventory/container/Container.java
index e88398b1a..b4068a044 100644
--- a/src/main/java/net/minecraft/core/player/inventory/container/Container.java
+++ b/src/main/java/net/minecraft/core/player/inventory/container/Container.java
@@ -27,4 +27,8 @@ public interface Container
     boolean stillValid(Player entityplayer);
 
     void sortContainer();
+
+    default boolean locked(int index) {
+        return false;
+    }
 }
diff --git a/src/main/java/net/minecraft/core/player/inventory/container/Inventory.java b/src/main/java/net/minecraft/core/player/inventory/container/Inventory.java
index 53abeeead..541a829bd 100644
--- a/src/main/java/net/minecraft/core/player/inventory/container/Inventory.java
+++ b/src/main/java/net/minecraft/core/player/inventory/container/Inventory.java
@@ -26,6 +26,13 @@ import org.jetbrains.annotations.Nullable;
 public class Inventory
     implements Container
 {
+    protected int hotbarOffset = 0;
+    public ItemStack[] mainInventory;
+    public ItemStack[] armorInventory;
+    protected int currentItem;
+    public Player player;
+    private ItemStack heldItem;
+    public boolean inventoryChanged;
 
     public Inventory(Player player)
     {
@@ -36,6 +43,15 @@ public class Inventory
         this.player = player;
     }
 
+    public int getHotbarOffset() {
+        return hotbarOffset;
+    }
+
+    public void setHotbarOffset(int offset, boolean overrideLock) {
+        if (!overrideLock && currentItemLocked()) return;
+        hotbarOffset = offset;
+    }
+
     @Nullable
     public ItemStack getCurrentItem()
     {
@@ -47,6 +63,15 @@ public class Inventory
             return null;
         }
     }
+
+    public int getCurrentItemIndex() {
+        return currentItem;
+    }
+
+    public void setCurrentItemIndex(int index, boolean overrideLock) {
+        if (!overrideLock && currentItemLocked()) return;
+        currentItem = index;
+    }
     
     public static int func_25054_e()
     {
@@ -96,7 +121,9 @@ public class Inventory
     	for(int stage = 0; stage < 2; stage++) {
         	for(int i=0; i < mainInventory.length; i++) {
         		int slotId = useHotbarOffset ? (i + hotbarOffset) % mainInventory.length : i;
-        		
+
+                if (locked(slotId)) continue;
+
         		ItemStack stackInSlot = mainInventory[slotId];
         		
         		if(stage == 0) {
@@ -133,6 +160,7 @@ public class Inventory
 
     public int setCurrentItem(ItemStack itemstack, boolean flag)
     {
+        if (currentItemLocked()) return currentItem;
     	if (!flag) return currentItem;
     	
     	if (itemstack.itemID < Block.blocksList.length)
@@ -160,6 +188,7 @@ public class Inventory
 
     public void changeCurrentItem(int i)
     {
+        if (currentItemLocked()) return;
         if(i > 0)
         {
             i = 1;
@@ -201,7 +230,16 @@ public class Inventory
         }
         return true;
     }
-    
+
+    public boolean currentItemLocked() {
+        return player.getHeldObject() != null;
+    }
+
+    @Override
+    public boolean locked(int index) {
+        return currentItemLocked() && index == currentItem;
+    }
+
     @Override
 	public ItemStack removeItem(int index, int takeAmount)
     {
@@ -519,12 +557,4 @@ public class Inventory
 			inventory.armorInventory[i] = null;
 		}
 	}
-
-    public int hotbarOffset = 0;
-    public ItemStack[] mainInventory;
-    public ItemStack[] armorInventory;
-    public int currentItem;
-    public Player player;
-    private ItemStack heldItem;
-    public boolean inventoryChanged;
 }
diff --git a/src/main/java/net/minecraft/core/player/inventory/slot/Slot.java b/src/main/java/net/minecraft/core/player/inventory/slot/Slot.java
index 75beacaa6..490c9ef3d 100644
--- a/src/main/java/net/minecraft/core/player/inventory/slot/Slot.java
+++ b/src/main/java/net/minecraft/core/player/inventory/slot/Slot.java
@@ -36,6 +36,7 @@ public class Slot
 
 	public ItemStack remove(final int i)
 	{
+		if (container.locked(slot)) return null;
 		return container.removeItem(slot, i);
 	}
 
@@ -66,7 +67,7 @@ public class Slot
 
 	public boolean mayPlace(final ItemStack itemstack)
 	{
-		return true;
+		return container != null && !container.locked(slot);
 	}
 
 	public void onTake(final ItemStack itemstack)
@@ -99,11 +100,11 @@ public class Slot
 	}
 	
 	public boolean enableDragAndPickup() {
-		return true;
+		return !container.locked(slot);
 	}
 	
 	public boolean allowItemInteraction() {
-		return true;
+		return !container.locked(slot);
 	}
 
 	public boolean getIsDiscovered(Player player){
diff --git a/src/main/java/net/minecraft/core/world/BlocksContainer.java b/src/main/java/net/minecraft/core/world/BlocksContainer.java
new file mode 100644
index 000000000..be3934c8a
--- /dev/null
+++ b/src/main/java/net/minecraft/core/world/BlocksContainer.java
@@ -0,0 +1,156 @@
+package net.minecraft.core.world;
+
+import net.minecraft.client.render.LightmapHelper;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.BlockEntity;
+import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.enums.LightLayer;
+import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.chunk.ChunkCoordinates;
+import net.minecraft.core.world.season.SeasonManager;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class BlocksContainer implements WorldSource {
+    public final World world;
+    private final Map<ChunkCoordinates, BlockEntry> blockEntryMap = new HashMap<>();
+    private Entity lightRefEntity = null;
+    public BlocksContainer(World world) {
+        this.world = world;
+    }
+
+    public void setLightReferenceEntity(Entity entity) {
+        this.lightRefEntity = entity;
+    }
+
+
+    public void setBlock(int x, int y, int z, int blockID, int blockMeta, BlockEntity entity) {
+        blockEntryMap.put(new ChunkCoordinates(x, y, z), new BlockEntry(blockID, blockMeta, entity, x, y, z));
+    }
+
+    public BlockEntry getEntry(int x, int y, int z) {
+        return blockEntryMap.get(new ChunkCoordinates(x, y, z));
+    }
+
+    public Collection<BlockEntry> getEntries() {
+        return blockEntryMap.values();
+    }
+
+    public void clear() {
+        blockEntryMap.clear();
+    }
+
+
+    @Override
+    public int getBlockId(int x, int y, int z) {
+        ChunkCoordinates c = new ChunkCoordinates(x, y, z);
+        if (blockEntryMap.containsKey(c)){
+            return blockEntryMap.get(c).blockID;
+        }
+        return world.getBlockId(x, y, z);
+    }
+
+    @Override
+    public Block getBlock(int x, int y, int z) {
+        return Block.getBlock(getBlockId(x, y, z));
+    }
+
+    @Override
+    public BlockEntity getBlockEntity(int x, int y, int z) {
+        ChunkCoordinates c = new ChunkCoordinates(x, y, z);
+        if (blockEntryMap.containsKey(c)){
+            return blockEntryMap.get(c).blockEntity;
+        }
+        return world.getBlockEntity(x, y, z);
+    }
+
+    @Override
+    public float getBrightness(int x, int y, int z, int blockLightValue) {
+        if (lightRefEntity != null) return lightRefEntity.getBrightness(1f);
+        return world.getBrightness(x, y, z, blockLightValue);
+    }
+
+    @Override
+    public int getLightmapCoord(int x, int y, int z, int blockLightValue) {
+        if (lightRefEntity != null) return lightRefEntity.getLightmapCoord(1f);
+        return world.getLightmapCoord(x, y, z, blockLightValue);
+    }
+
+    @Override
+    public float getLightBrightness(int x, int y, int z) {
+        return world.getLightBrightness(x, y, z);
+    }
+
+    @Override
+    public int getBlockMetadata(int x, int y, int z) {
+        ChunkCoordinates c = new ChunkCoordinates(x, y, z);
+        if (blockEntryMap.containsKey(c)){
+            return blockEntryMap.get(c).blockMeta;
+        }
+        return world.getBlockMetadata(x, y, z);
+    }
+
+    @Override
+    public Material getBlockMaterial(int x, int y, int z) {
+        Block b = getBlock(x, y, z);
+        return b == null ? Material.air : b.blockMaterial;
+    }
+
+    @Override
+    public boolean isBlockOpaqueCube(int x, int y, int z) {
+        Block b = getBlock(x, y, z);
+        return b != null && b.isSolidRender();
+    }
+
+    @Override
+    public boolean isBlockNormalCube(int x, int y, int z) {
+        Block b = getBlock(x, y, z);
+        return b != null && b.blockMaterial.isSolidBlocking() && b.renderAsNormalBlockOnCondition(this, x, y, z);
+    }
+
+    @Override
+    public double getBlockTemperature(int x, int z) {
+        return world.getBlockTemperature(x, z);
+    }
+
+    @Override
+    public double getBlockHumidity(int x, int z) {
+        return world.getBlockHumidity(x, z);
+    }
+
+    @Override
+    public SeasonManager getSeasonManager() {
+        return world.getSeasonManager();
+    }
+
+    @Override
+    public Biome getBlockBiome(int x, int y, int z) {
+        return world.getBlockBiome(x, y, z);
+    }
+
+    @Override
+    public int getSavedLightValue(LightLayer layer, int x, int y, int z) {
+        return world.getSavedLightValue(layer, x, y, z);
+    }
+    public static class BlockEntry {
+        public final int blockID;
+        public final int blockMeta;
+        @Nullable
+        public final BlockEntity blockEntity;
+        public final int x;
+        public final int y;
+        public final int z;
+        public BlockEntry(int blockID, int blockMeta, @Nullable BlockEntity blockEntity, int x, int y, int z){
+            this.blockID = blockID;
+            this.blockMeta = blockMeta;
+            this.blockEntity = blockEntity;
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/core/world/Dimension.java b/src/main/java/net/minecraft/core/world/Dimension.java
index 45cdd1625..633b815a6 100644
--- a/src/main/java/net/minecraft/core/world/Dimension.java
+++ b/src/main/java/net/minecraft/core/world/Dimension.java
@@ -88,7 +88,7 @@ public class Dimension
 	{
 		if (dimensionList.containsKey(id))
 		{
-			throw new IllegalArgumentException("Dimension with ID " + dimension.id + " is already registered!");
+			throw new IllegalArgumentException("Dimension with ID " + id + " is already registered!");
 		}
 
 		dimension.id = id;
diff --git a/src/main/java/net/minecraft/core/world/ICarriable.java b/src/main/java/net/minecraft/core/world/ICarriable.java
new file mode 100644
index 000000000..f8d6873ba
--- /dev/null
+++ b/src/main/java/net/minecraft/core/world/ICarriable.java
@@ -0,0 +1,50 @@
+package net.minecraft.core.world;
+
+import com.mojang.logging.LogUtils;
+import com.mojang.nbt.CompoundTag;
+import net.minecraft.core.block.entity.BlockEntity;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.util.helper.Side;
+import org.slf4j.Logger;
+
+public interface ICarriable {
+    Logger LOGGER = LogUtils.getLogger();
+    /**
+     * Called every tick an entity holds this object
+     */
+    void heldTick(World world, Entity holder);
+
+    /**
+     * Called by the entity when trying to place the held object at some position
+     * @return True if carried object could place, false otherwise
+     */
+    boolean tryPlace(World world, Entity holder, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced);
+
+    /**
+     * Called when entity stops holding the object from some external, non placement method (such as death)
+     */
+    void drop(World world, Entity holder);
+
+    /**
+     * Called before an entity tries to pick up the object
+     */
+    boolean canBeCarried(World world, Entity potentialHolder);
+
+    /**
+     * Called by an entity when attempting to pick up the object
+     */
+    ICarriable pickup(World world, Entity holder);
+
+    void writeToNBT(CompoundTag tag);
+
+    void readFromNBT(CompoundTag tag);
+
+    static ICarriable createAndLoadCarriable(Entity holder, CompoundTag tag) {
+        String type = tag.getString("type");
+        if (type.equalsIgnoreCase("blockEntity")) {
+            return BlockEntity.CarriedBlock.createAndLoadCarriedBlock(holder, tag);
+        }
+        LOGGER.warn("Could not identify carriable for type {}!", type);
+        return null;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/world/PortalHandler.java b/src/main/java/net/minecraft/core/world/PortalHandler.java
index 951f79909..3d70844e4 100644
--- a/src/main/java/net/minecraft/core/world/PortalHandler.java
+++ b/src/main/java/net/minecraft/core/world/PortalHandler.java
@@ -310,7 +310,7 @@ label1:
         }
         for(int j5 = 0; j5 < 4; j5++)
         {
-            world.editingBlocks = true;
+            world.noNeighborUpdate = true;
             for(int xzOffset = 0; xzOffset < 4; xzOffset++)
             {
                 for(int yOffset = -1; yOffset < 4; yOffset++)
@@ -326,7 +326,7 @@ label1:
             
             ((PortalBlock)Block.blocksList[targetPortalId]).tryToCreatePortal(world, portalX,  portalY,  portalZ);
 
-            world.editingBlocks = false;
+            world.noNeighborUpdate = false;
             for(int k6 = 0; k6 < 4; k6++)
             {
                 for(int l7 = -1; l7 < 4; l7++)
diff --git a/src/main/java/net/minecraft/core/world/World.java b/src/main/java/net/minecraft/core/world/World.java
index 3771e770b..be9cae290 100644
--- a/src/main/java/net/minecraft/core/world/World.java
+++ b/src/main/java/net/minecraft/core/world/World.java
@@ -16,7 +16,6 @@ import java.util.UUID;
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.CompoundTag;
 
-import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.enums.Difficulty;
 import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.camera.ICamera;
@@ -106,7 +105,7 @@ public class World implements WorldSource {
     public int rainbowTicks = 0;
     public int startingRainbowTicks = 0;
     public boolean dayCanHaveRainbow = true;
-    public boolean editingBlocks = false;
+    public boolean noNeighborUpdate = false;
     private long lockTimestamp = System.currentTimeMillis();
     //protected int autosavePeriod = 40;
     public Random rand = new Random();
@@ -906,7 +905,7 @@ public class World implements WorldSource {
 
     private void notifyBlockOfNeighborChange(int x, int y, int z, int blockId)
     {
-        if(editingBlocks || isClientSide)
+        if(noNeighborUpdate || isClientSide)
         {
             return;
         }
@@ -2841,15 +2840,15 @@ public class World implements WorldSource {
         return (new PathFinder(chunkcache)).findPath(entity, i, j, k, f);
     }
 
-    public boolean isBlockProvidingPowerTo(int x, int y, int z, Side side) {
+    public boolean getDirectSignal(int x, int y, int z, Side side) {
         Block block = getBlock(x, y, z);
         if (block == null) return false;
         return block.getDirectSignal(this, x, y, z, side);
     }
 
-    public boolean isBlockGettingPowered(int x, int y, int z) {
+    public boolean hasDirectSignal(int x, int y, int z) {
         for (Side side : Side.sides){
-            if (isBlockProvidingPowerTo(
+            if (getDirectSignal(
                 x + side.getOffsetX(),
                 y + side.getOffsetY(),
                 z + side.getOffsetZ(),
@@ -2861,10 +2860,10 @@ public class World implements WorldSource {
         return false;
     }
 
-    public boolean isBlockIndirectlyProvidingPowerTo(int x, int y, int z, Side side) {
+    public boolean getSignal(int x, int y, int z, Side side) {
         Block block = getBlock(x, y, z);
         if(isBlockNormalCube(x, y, z) && block != Blocks.BLOCK_REDSTONE && block != Blocks.PUMPKIN_REDSTONE) {
-            return isBlockGettingPowered(x, y, z);
+            return hasDirectSignal(x, y, z);
         }
         if(block == null) {
             return false;
@@ -2873,9 +2872,9 @@ public class World implements WorldSource {
         return block.getSignal(this, x, y, z, side);
     }
 
-    public boolean isBlockIndirectlyGettingPowered(int x, int y, int z) {
+    public boolean hasNeighborSignal(int x, int y, int z) {
         for (Side side : Side.sides){
-            if (isBlockIndirectlyProvidingPowerTo(
+            if (getSignal(
                 x + side.getOffsetX(),
                 y + side.getOffsetY(),
                 z + side.getOffsetZ(),
diff --git a/src/main/java/net/minecraft/core/world/chunk/Chunk.java b/src/main/java/net/minecraft/core/world/chunk/Chunk.java
index fdbdec6eb..e6b4d617d 100644
--- a/src/main/java/net/minecraft/core/world/chunk/Chunk.java
+++ b/src/main/java/net/minecraft/core/world/chunk/Chunk.java
@@ -333,6 +333,7 @@ public class Chunk
         int worldZ = zPosition * CHUNK_SIZE_Z + z;
 
         world.scheduleLightingUpdate(LightLayer.Block, worldX, y, worldZ, worldX, y, worldZ);
+        world.scheduleLightingUpdate(LightLayer.Sky, worldX, y, worldZ, worldX, y, worldZ);
         lightGaps(x, z);
 
         isModified = true;
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTree.java b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTree.java
index b0d23c6a8..b232adf65 100644
--- a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTree.java
+++ b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTree.java
@@ -73,7 +73,7 @@ public class WorldFeatureTree extends WorldFeature
                 for(int iz = z - i3; iz <= z + i3; iz++)
                 {
                     int j4 = iz - z;
-                    if((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0 && j2 != 0) && !Block.solid[world.getBlockId(ix, iy, iz)])
+                    if((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0 && j2 != 0) && WorldFeatureTree.canLeavesReplace(world, ix, iy, iz))
                     {
                     	placeLeaves(world, ix, iy, iz, random);
                     }
@@ -121,4 +121,9 @@ public class WorldFeatureTree extends WorldFeature
     	}
     	return null;
     }
+
+    public static boolean canLeavesReplace(World world, int x, int y, int z) {
+        Block b = world.getBlock(x, y, z);
+        return b == null || b.hasTag(BlockTags.PLACE_OVERWRITES);
+    }
 }
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeCaatinga.java b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeCaatinga.java
index 8504417f2..c80615e7f 100644
--- a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeCaatinga.java
+++ b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeCaatinga.java
@@ -140,7 +140,7 @@ public class WorldFeatureTreeCaatinga extends WorldFeature
                     int l3 = k3 - x;
                     for (int i4 = z - i3; i4 <= z + i3; i4++) {
                         int j4 = i4 - z;
-                        if ((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0 && j2 != 0) && !Block.solid[world.getBlockId(k3, k1, i4)]) {
+                        if ((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0 && j2 != 0) && WorldFeatureTree.canLeavesReplace(world, k3, k1, i4)) {
                             placeLeaves(world, k3+ modX, k1 + modY, i4+ modZ, random);
                         }
                     }
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeShapeSwamp.java b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeShapeSwamp.java
index ab52ab5ad..3f817920c 100644
--- a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeShapeSwamp.java
+++ b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeShapeSwamp.java
@@ -98,7 +98,7 @@ public class WorldFeatureTreeShapeSwamp extends WorldFeature
                 for(int i4 = z - i3; i4 <= z + i3; i4++)
                 {
                     int j4 = i4 - z;
-                    if((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0 && j2 != 0) && !Block.solid[world.getBlockId(k3, k1, i4)])
+                    if((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0 && j2 != 0) && WorldFeatureTree.canLeavesReplace(world, k3, k1, i4))
                     {
                         world.setBlockWithNotify(k3, k1, i4, leavesID);
                         if (treeRand.nextInt(5) == 0)
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeShrub.java b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeShrub.java
index 19969007d..4f1e981ab 100644
--- a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeShrub.java
+++ b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeShrub.java
@@ -80,7 +80,7 @@ public class WorldFeatureTreeShrub extends WorldFeature
                 for(int i4 = z - i3; i4 <= z + i3; i4++)
                 {
                     int j4 = i4 - z;
-                    if((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0) && !Block.solid[world.getBlockId(k3, k1, i4)])
+                    if((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0) && WorldFeatureTree.canLeavesReplace(world, k3, k1, i4))
                     {
                         if((k3 != x -i3 && k3 != x +i3) || (i4 != z -i3 && i4 != z +i3))
                             world.setBlockWithNotify(k3, k1, i4, leavesID);
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTaigaBushy.java b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTaigaBushy.java
index 69498f366..fde431808 100644
--- a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTaigaBushy.java
+++ b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTaigaBushy.java
@@ -91,7 +91,7 @@ public class WorldFeatureTreeTaigaBushy extends WorldFeature
                 for(int k5 = z - k2; k5 <= z + k2; k5++)
                 {
                     int l5 = k5 - z;
-                    if((Math.abs(j5) != k2 || Math.abs(l5) != k2 || k2 <= 0) && !Block.solid[world.getBlockId(l4, j4, k5)])
+                    if((Math.abs(j5) != k2 || Math.abs(l5) != k2 || k2 <= 0) && WorldFeatureTree.canLeavesReplace(world, l4, j4, k5))
                     {
                         world.setBlockWithNotify(l4, j4, k5, leavesID);
                     }
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTaigaTall.java b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTaigaTall.java
index a226aed51..d1ddbb3ba 100644
--- a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTaigaTall.java
+++ b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTaigaTall.java
@@ -86,7 +86,7 @@ public class WorldFeatureTreeTaigaTall extends WorldFeature
                 for(int l4 = z - k2; l4 <= z + k2; l4++)
                 {
                     int i5 = l4 - z;
-                    if((Math.abs(k4) != k2 || Math.abs(i5) != k2 || k2 <= 0) && !Block.solid[world.getBlockId(l3, i3, l4)])
+                    if((Math.abs(k4) != k2 || Math.abs(i5) != k2 || k2 <= 0) && WorldFeatureTree.canLeavesReplace(world, l3, i3, l4))
                     {
                         world.setBlockWithNotify(l3, i3, l4, leavesID);
                     }
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTall.java b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTall.java
index 7f5e71352..5f1966761 100644
--- a/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTall.java
+++ b/src/main/java/net/minecraft/core/world/generate/feature/tree/WorldFeatureTreeTall.java
@@ -86,7 +86,7 @@ public class WorldFeatureTreeTall extends WorldFeature
                 for(int i4 = z - i3; i4 <= z + i3; i4++)
                 {
                     int j4 = i4 - z;
-                    if((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0 && j2 != 0) && !Block.solid[world.getBlockId(k3, k1, i4)])
+                    if((Math.abs(l3) != i3 || Math.abs(j4) != i3 || random.nextInt(2) != 0 && j2 != 0) && WorldFeatureTree.canLeavesReplace(world, k3, k1, i4))
                     {
                         world.setBlockWithNotify(k3, k1, i4, leavesID);
                     }
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/tree/spooner/WorldFeatureSpoonerTree.java b/src/main/java/net/minecraft/core/world/generate/feature/tree/spooner/WorldFeatureSpoonerTree.java
index 7fabb3cb3..4caefbe22 100644
--- a/src/main/java/net/minecraft/core/world/generate/feature/tree/spooner/WorldFeatureSpoonerTree.java
+++ b/src/main/java/net/minecraft/core/world/generate/feature/tree/spooner/WorldFeatureSpoonerTree.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.generate.feature.MethodParametersAnnotation;
 import net.minecraft.core.world.generate.feature.WorldFeature;
+import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 
 import java.util.List;
 import java.util.Random;
@@ -45,7 +46,7 @@ public abstract class WorldFeatureSpoonerTree
 
     protected boolean assignValue(int x, int y, int z, int id, int meta, World world) {
         if (id == leavesId) {
-            if (!Block.solid[world.getBlockId(x, y, z)]) {
+            if (WorldFeatureTree.canLeavesReplace(world, x, y, z)) {
                 return world.setBlockAndMetadataWithNotify(x, y, z, id, meta);
             }
             return false;
diff --git a/src/main/java/net/minecraft/core/world/save/LevelData.java b/src/main/java/net/minecraft/core/world/save/LevelData.java
index 3f1f53b8f..14e4a405f 100644
--- a/src/main/java/net/minecraft/core/world/save/LevelData.java
+++ b/src/main/java/net/minecraft/core/world/save/LevelData.java
@@ -40,14 +40,15 @@ public class LevelData
         readFromCompoundTag(tag);
     }
 
-    public LevelData(long seed, @NotNull String name)
+    //do *not* add @NotNull to name here, breaks modding for some abstract reason
+    public LevelData(long seed, String name)
     {
         randomSeed = seed;
         levelName = name;
         gameRules = new GameRuleCollection();
     }
 
-    public LevelData(long seed, @NotNull String name, GameRuleCollection gameRules)
+    public LevelData(long seed, String name, GameRuleCollection gameRules)
     {
         randomSeed = seed;
         levelName = name;
diff --git a/src/main/java/net/minecraft/server/entity/player/ServerPlayer.java b/src/main/java/net/minecraft/server/entity/player/ServerPlayer.java
index 4cf409877..4c834ba45 100644
--- a/src/main/java/net/minecraft/server/entity/player/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/entity/player/ServerPlayer.java
@@ -18,6 +18,7 @@ import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.player.inventory.container.Container;
 import net.minecraft.core.player.inventory.menu.*;
 import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.ICarriable;
 import net.minecraft.core.world.IVehicle;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.chunk.ChunkSection;
@@ -724,7 +725,17 @@ public class ServerPlayer extends Player implements ContainerListener {
     	playerNetServerHandler.sendPacket(new SetCarriedItemPacket(i));
     }
 
-	@Override
+    @Override
+    public void setHeldObject(@Nullable ICarriable heldObject) {
+        super.setHeldObject(heldObject);
+        mcServer.getEntityTracker(dimension).sendPacketToTrackedPlayers(this, new SetHeldObjectPacket(id, heldObject));
+
+        // Ensure slot is definitely synced
+        playerNetServerHandler.sendPacket(new SetHotbarOffsetPacket(inventory.getHotbarOffset()));
+        playerNetServerHandler.sendPacket(new SetCarriedItemPacket(inventory.getCurrentItemIndex()));
+    }
+
+    @Override
 	public void sendMessage(String message) {
 		playerNetServerHandler.sendPacket(new ChatPacket(message, 0, AES.keyChain.get(username)));
 	}
diff --git a/src/main/java/net/minecraft/server/net/PlayerList.java b/src/main/java/net/minecraft/server/net/PlayerList.java
index 69c088d56..9db306f4b 100644
--- a/src/main/java/net/minecraft/server/net/PlayerList.java
+++ b/src/main/java/net/minecraft/server/net/PlayerList.java
@@ -107,7 +107,7 @@ public class PlayerList
         playerIo = aworldserver[0].getSaveHandler().getPlayerFileData();
     }
 
-    public void func_28172_a(ServerPlayer player)
+    public void syncPlayerDimension(ServerPlayer player)
     {
         for (PlayerManager playerManager : playerManagers) {
             playerManager.removePlayer(player);
@@ -291,7 +291,7 @@ public class PlayerList
                 worldserver1.chunkProviderServer.chunkLoadOverride = false;
             }
         }
-        func_28172_a(serverPlayer);
+        syncPlayerDimension(serverPlayer);
         serverPlayer.playerNetServerHandler.teleportAndRotate(serverPlayer.x, serverPlayer.y, serverPlayer.z, serverPlayer.yRot, serverPlayer.xRot);
         server.playerList.sendPacketToAllPlayers(new PlayerGamemodePacket(serverPlayer.id, serverPlayer.gamemode.getId()));
         serverPlayer.setWorld(worldserver1);
diff --git a/src/main/java/net/minecraft/server/net/handler/LoginPacketHandler.java b/src/main/java/net/minecraft/server/net/handler/LoginPacketHandler.java
index 0429c77f2..192eed88d 100644
--- a/src/main/java/net/minecraft/server/net/handler/LoginPacketHandler.java
+++ b/src/main/java/net/minecraft/server/net/handler/LoginPacketHandler.java
@@ -213,6 +213,9 @@ public class LoginPacketHandler extends PacketHandler
             player.playerNetServerHandler.sendPacket(new PhotoModePacket(mcServer.disablePhotoMode));
             player.playerNetServerHandler.sendPacket(new GameRulePacket(mcServer.getDimensionWorld(0).getLevelData().getGameRules()));
             player.playerNetServerHandler.sendPacket(new CommandManagerPacket(this.mcServer.getDimensionWorld(player.dimension).getCommandManager().getDispatcher(), new ServerCommandSource(this.mcServer, player), "", 0));
+            player.playerNetServerHandler.sendPacket(new SetHeldObjectPacket(player.id, player.getHeldObject()));
+            player.playerNetServerHandler.sendPacket(new SetHotbarOffsetPacket(player.inventory.getHotbarOffset()));
+            player.playerNetServerHandler.sendPacket(new SetCarriedItemPacket(player.inventory.getCurrentItemIndex()));
 
             for (RecipeEntryBase<?, ?, ?> recipe : Registries.RECIPES.getAllSerializableRecipes()) {
                 player.playerNetServerHandler.sendPacket(new RecipeSyncPacket(recipe,Registries.RECIPES.getAllSerializableRecipes().size()));
diff --git a/src/main/java/net/minecraft/server/net/handler/ServerPacketHandler.java b/src/main/java/net/minecraft/server/net/handler/ServerPacketHandler.java
index 471820fca..c698a8480 100644
--- a/src/main/java/net/minecraft/server/net/handler/ServerPacketHandler.java
+++ b/src/main/java/net/minecraft/server/net/handler/ServerPacketHandler.java
@@ -247,7 +247,7 @@ public class ServerPacketHandler extends PacketHandler
                 LOGGER.warn("Expected {}, {}, {}", playerEntity.x, playerEntity.y, playerEntity.z);
             }
             playerEntity.absMoveTo(newPosX, newPosY, newPosZ, f2, f3);
-            boolean flag2 = worldserver.getCubes(playerEntity, playerEntity.bb.copy().getInsetBoundingBox(f4, f4, f4)).size() == 0;
+            boolean flag2 = worldserver.getCubes(playerEntity, playerEntity.bb.copy().getInsetBoundingBox(f4, f4, f4)).isEmpty();
             if (!playerEntity.getGamemode().canPlayerFly() && flag && (flag1 || !flag2) && !playerEntity.isPlayerSleeping())
             {
                 teleportAndRotate(lastPosX, lastPosY, lastPosZ, f2, f3);
@@ -304,7 +304,7 @@ public class ServerPacketHandler extends PacketHandler
         final int y = packet.yPosition;
         final int z = packet.zPosition;
 
-        if (!playerEntity.getGamemode().canInteract() || !playerEntity.isAlive()) return;
+        if (!playerEntity.getGamemode().canInteract() || !playerEntity.isAlive() || playerEntity.getHeldObject() != null /*Forbid digging while holding object*/) return;
         WorldServer world = mcServer.getDimensionWorld(playerEntity.dimension);
         if(packet.status == 4) {
             // Drop single item
@@ -378,7 +378,7 @@ public class ServerPacketHandler extends PacketHandler
             {
                 return;
             }
-            playerEntity.playerController.func_6154_a(playerEntity, worldserver, itemstack);
+            playerEntity.playerController.useItemOnNothing(playerEntity, worldserver, itemstack);
         }
         else
         {
@@ -408,11 +408,11 @@ public class ServerPacketHandler extends PacketHandler
         itemstack = playerEntity.inventory.getCurrentItem();
         if (itemstack != null && itemstack.stackSize <= 0)
         {
-            playerEntity.inventory.mainInventory[playerEntity.inventory.currentItem] = null;
+            playerEntity.inventory.mainInventory[playerEntity.inventory.getCurrentItemIndex()] = null;
         }
         playerEntity.isChangingQuantityOnly = true;
-        playerEntity.inventory.mainInventory[playerEntity.inventory.currentItem] = ItemStack.copyItemStack(playerEntity.inventory.mainInventory[playerEntity.inventory.currentItem]);
-        Slot slot = playerEntity.craftingInventory.getSlotFor(playerEntity.inventory, playerEntity.inventory.currentItem);
+        playerEntity.inventory.mainInventory[playerEntity.inventory.getCurrentItemIndex()] = ItemStack.copyItemStack(playerEntity.inventory.mainInventory[playerEntity.inventory.getCurrentItemIndex()]);
+        Slot slot = playerEntity.craftingInventory.getSlotFor(playerEntity.inventory, playerEntity.inventory.getCurrentItemIndex());
         playerEntity.craftingInventory.broadcastChanges();
         playerEntity.isChangingQuantityOnly = false;
         if (!ItemStack.areItemStacksEqual(playerEntity.inventory.getCurrentItem(), packet.itemStack))
@@ -440,7 +440,7 @@ public class ServerPacketHandler extends PacketHandler
     @Override
     public void handleInvalidPacket(Packet packet)
     {
-        LOGGER.warn(getClass() + " wasn't prepared to deal with a " + packet.getClass());
+        LOGGER.warn("{} wasn't prepared to deal with a {}", getClass(), packet.getClass());
         kickPlayer("Protocol error, unexpected packet");
     }
 
@@ -455,12 +455,15 @@ public class ServerPacketHandler extends PacketHandler
     {
         if (packet.id < 0 || packet.id > Inventory.func_25054_e())
         {
-            LOGGER.warn(playerEntity.username + " tried to set an invalid carried item");
+            LOGGER.warn("{} tried to set an invalid carried item", playerEntity.username);
             return;
         }
         else
         {
-            playerEntity.inventory.currentItem = packet.id;
+            playerEntity.inventory.setCurrentItemIndex(packet.id, false);
+            if (packet.id != playerEntity.inventory.getCurrentItemIndex()) { // If client tried to set current item while locked then send a packet back attempting to resync them
+                sendPacket(new SetCarriedItemPacket(packet.id));
+            }
             return;
         }
     }
@@ -579,7 +582,7 @@ public class ServerPacketHandler extends PacketHandler
     @Override
     public void handleUseEntity(InteractPacket packet)
     {
-        if (!playerEntity.getGamemode().canInteract() || !playerEntity.isAlive()) return;
+        if (!playerEntity.getGamemode().canInteract() || !playerEntity.isAlive() || playerEntity.getHeldObject() != null /*TODO consider adding entity interactions while holding object*/) return;
         WorldServer worldserver = mcServer.getDimensionWorld(playerEntity.dimension);
         Entity targetEntity = worldserver.getEntityFromId(packet.targetEntityID);
         if (targetEntity != null && playerEntity.distanceToSqr(targetEntity) < 36D)
@@ -753,7 +756,11 @@ public class ServerPacketHandler extends PacketHandler
     @Override
     public void handleSetHotbarOffset(SetHotbarOffsetPacket packet)
     {
-        playerEntity.inventory.hotbarOffset = packet.hotbarOffset;
+
+        playerEntity.inventory.setHotbarOffset(packet.hotbarOffset, false);
+        if (packet.hotbarOffset != playerEntity.inventory.getHotbarOffset()) { // If player tries to set hotbar offset while locked resync the clients offset
+            sendPacket(new SetHotbarOffsetPacket(packet.hotbarOffset));
+        }
     }
     
     @Override
diff --git a/src/main/java/net/minecraft/server/world/ServerPlayerController.java b/src/main/java/net/minecraft/server/world/ServerPlayerController.java
index 56ee1b149..7bfd0f723 100644
--- a/src/main/java/net/minecraft/server/world/ServerPlayerController.java
+++ b/src/main/java/net/minecraft/server/world/ServerPlayerController.java
@@ -145,17 +145,17 @@ public class ServerPlayerController
         return flag;
     }
 
-    public boolean func_6154_a(Player entityplayer, World world, ItemStack itemstack)
+    public boolean useItemOnNothing(Player entityplayer, World world, ItemStack itemstack)
     {
         if (!entityplayer.getGamemode().canInteract()) return false;
         int i = itemstack.stackSize;
         ItemStack itemstack1 = itemstack.useItemRightClick(world, entityplayer);
         if(itemstack1 != itemstack || itemstack1 != null && itemstack1.stackSize != i)
         {
-            entityplayer.inventory.mainInventory[entityplayer.inventory.currentItem] = itemstack1;
+            entityplayer.inventory.mainInventory[entityplayer.inventory.getCurrentItemIndex()] = itemstack1;
             if(itemstack1.stackSize <= 0)
             {
-                entityplayer.inventory.mainInventory[entityplayer.inventory.currentItem] = null;
+                entityplayer.inventory.mainInventory[entityplayer.inventory.getCurrentItemIndex()] = null;
             }
             return true;
         } else
@@ -164,24 +164,39 @@ public class ServerPlayerController
         }
     }
 
-    public boolean activateBlockOrUseItem(Player entityplayer, World world, ItemStack itemstack, int i, int j, int k, Side side, double xPlaced, double yPlaced)
+    public boolean activateBlockOrUseItem(Player entityplayer, World world, ItemStack itemstack, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced)
     {
         if (!entityplayer.getGamemode().canInteract()) return false;
-        int i1 = world.getBlockId(i, j, k);
-        if ((entityplayer.isSneaking() && entityplayer.getCurrentEquippedItem() == null) || (!entityplayer.isSneaking()))
-        {
-            if (i1 > 0 && Block.blocksList[i1].onBlockRightClicked(world, i, j, k, entityplayer, side, xPlaced, yPlaced))
-            {
-                return true;
+        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
+                BlockEntity blockEntity = world.getBlockEntity(blockX, blockY, blockZ);
+                if (blockEntity != null && blockEntity.canBeCarried(world, player)) {
+                    player.setHeldObject(blockEntity.pickup(world, player));
+                    return true;
+                }
             }
-        }
-        if(itemstack == null)
-        {
-            return false;
-        }
-        else
-        {
-            return itemstack.useItem(entityplayer, world, i, j, k, side, xPlaced, yPlaced);
+            if (!player.isSneaking() || itemstack == null) {  // If standing or hand empty perform block right click method
+                if (blockId > 0 && Block.blocksList[blockId].onBlockRightClicked(world, blockX, blockY, blockZ, player, side, xPlaced, yPlaced)) {
+                    return true;
+                }
+            }
+            if (itemstack == null) { // No stack do nothing
+                return false;
+            } else { // Use itemstack
+                return itemstack.useItem(player, world, blockX, blockY, blockZ, side, xPlaced, yPlaced);
+            }
+        } else {
+            if (!player.isSneaking()) {  // If standing or hand empty perform block right click method
+                if (blockId > 0 && Block.blocksList[blockId].onBlockRightClicked(world, blockX, blockY, blockZ, player, side, xPlaced, yPlaced)) {
+                    return true;
+                }
+            }
+            boolean didPlace = player.getHeldObject().tryPlace(world, player, blockX, blockY, blockZ, side, xPlaced, yPlaced);
+            if (didPlace) {
+                player.setHeldObject(null);
+            }
+            return didPlace;
         }
     }
 
diff --git a/src/main/java/org/lwjgl/opengl/Display.java b/src/main/java/org/lwjgl/opengl/Display.java
deleted file mode 100644
index 04ab5dc8c..000000000
--- a/src/main/java/org/lwjgl/opengl/Display.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.lwjgl.opengl;
-
-import net.minecraft.client.render.window.GameWindow;
-import net.minecraft.client.render.window.GameWindowGLFW;
-
-public abstract class Display {
-	
-	private static GameWindowGLFW window;
-	
-	public static void setWindow(GameWindowGLFW window) {
-		Display.window = window;
-	}
-	
-	public static GameWindow getWindow() {
-		return window;
-	}
-	
-	// These are used in legacy-lwjgl's input implementation
-	
-	public static int getWidth() {
-		return window.getWidthScreenCoords();
-	}
-	
-	public static int getHeight() {
-		return window.getHeightScreenCoords();
-	}
-	
-	public static long getHandle() {
-		return window.window;
-	}
-}
diff --git a/src/main/resources/assets/minecraft/textures/gui/hud/doom.png b/src/main/resources/assets/minecraft/textures/gui/hud/doom.png
index eef992a55..6ec20d5f3 100644
Binary files a/src/main/resources/assets/minecraft/textures/gui/hud/doom.png and b/src/main/resources/assets/minecraft/textures/gui/hud/doom.png differ
diff --git a/src/main/resources/assets/minecraft/textures/gui/sprites/hud/hotbar_selection_locked.png b/src/main/resources/assets/minecraft/textures/gui/sprites/hud/hotbar_selection_locked.png
new file mode 100644
index 000000000..ca94e868d
Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/gui/sprites/hud/hotbar_selection_locked.png differ
diff --git a/src/main/resources/assets/minecraft/textures/gui/sprites/slot_locked.png b/src/main/resources/assets/minecraft/textures/gui/sprites/slot_locked.png
new file mode 100644
index 000000000..a5c5e144f
Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/gui/sprites/slot_locked.png differ
diff --git a/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/majonk.png b/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/majonk.png
new file mode 100644
index 000000000..9c90e9f89
Binary files /dev/null and b/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/majonk.png differ
diff --git a/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/mclogo.png b/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/mclogo.png
new file mode 100644
index 000000000..9bbd1c708
Binary files /dev/null and b/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/mclogo.png differ
diff --git a/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/mojang.png b/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/mojang.png
new file mode 100644
index 000000000..12435f1af
Binary files /dev/null and b/src/main/resources/holidays/halloween/assets/minecraft/textures/gui/title/mojang.png differ
