diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java
index 3c24eb1be..bd0ea8cdb 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -1121,7 +1121,6 @@ public class Minecraft
                         }
                     }
                     sndManager.setMuted(gameSettings.muteOnLostFocus.value && !gameWindow.isFocused());
-                    guiToasts.render(timer.partialTicks);
 
                     switch (downloadResourcesThread.downloading) {
                         case DOWNLOADING: {
@@ -1657,6 +1656,7 @@ public class Minecraft
                         }
                     }
                 }
+                thePlayer.input.keyEvent(-1, Mouse.getEventButton(), Mouse.getEventButtonState());
             }
             if (toggleFlyPressed && !gameSettings.keyFly.isPressed())
             {
@@ -1681,7 +1681,7 @@ public class Minecraft
                 //Fix your keyboard Mak you broke the overlay toggle
                 boolean control = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL) /* || Keyboard.isKeyDown(Keyboard.KEY_F4)*/;
                 if(!(Keyboard.getEventKeyState() && gameSettings.keyToggleDebug.isPressed())) {
-                	thePlayer.input.keyEvent(Keyboard.getEventKey(), Keyboard.getEventKeyState());
+                	thePlayer.input.keyEvent(Keyboard.getEventKey(), -1, Keyboard.getEventKeyState());
                 }
                 
                 if(gameSettings.keyToggleDebug.isPressEvent()) {
@@ -2716,8 +2716,10 @@ public class Minecraft
         Minecraft mc = new Minecraft(mcDataDir == null ? getAppDir("minecraft-bta"): mcDataDir, gameWindow,false);
         mc.minecraftUri = "www.minecraft.net";
 
+        username = username == null ? "Player" + System.currentTimeMillis() % 1000L : username;
+
         sessionId = sessionId == null ? "" : sessionId;
-        if (uuid == null) {
+        if (uuid == null || !UUIDHelper.isUUID(uuid)) {
             if (username != null) {
                 UUID nameUUID = UUIDHelper.getUUIDFromName(username);
                 if (nameUUID != null) {
@@ -2728,7 +2730,6 @@ public class Minecraft
                 uuid = "00000000-0000-0000-0000-000000000000";
             }
         }
-        username = username == null ? "Player" + System.currentTimeMillis() % 1000L : username;
 
         mc.session = new Session(username, uuid, sessionId);
         if (server != null) {
diff --git a/game/client/src/main/java/net/minecraft/client/enums/MusicFrequency.java b/game/client/src/main/java/net/minecraft/client/enums/MusicFrequency.java
new file mode 100644
index 000000000..f10ae9c1f
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/enums/MusicFrequency.java
@@ -0,0 +1,24 @@
+package net.minecraft.client.enums;
+
+import net.minecraft.core.util.helper.ITranslatable;
+
+public enum MusicFrequency
+    implements ITranslatable
+{
+    CONTINUOUS(0),
+    FREQUENT(3000),
+    DEFAULT(6000),
+    UNUSUAL(12000),
+    RARE(24000);
+
+    public final int interval;
+
+    MusicFrequency(final int interval) {
+        this.interval = interval;
+    }
+
+    @Override
+    public String getTranslationKey() {
+        return name().toLowerCase();
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
index a32f30efb..a3936a5b1 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
@@ -20,11 +20,13 @@ import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.gui.hud.HudIngameDoom;
 import net.minecraft.client.holiday.Holidays;
 import net.minecraft.client.render.Lighting;
+import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.util.helper.UrlHelper;
 import net.minecraft.core.Version;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.util.glu.GLU;
@@ -369,9 +371,9 @@ public class ScreenMainMenu extends Screen
         if(this.logoBlocks == null) {
             this.logoBlocks = new LogoBlock[logoBlockLayers[0].length()][logoBlockLayers.length];
 
-            for(int var2 = 0; var2 < this.logoBlocks.length; ++var2) {
-                for(var3 = 0; var3 < this.logoBlocks[var2].length; ++var3) {
-                    this.logoBlocks[var2][var3] = new LogoBlock(var2, var3);
+            for(int x = 0; x < this.logoBlocks.length; ++x) {
+                for(int y = 0; y < this.logoBlocks[x].length; ++y) {
+                    this.logoBlocks[x][y] = new LogoBlock(x, y);
                 }
             }
         }
@@ -527,8 +529,8 @@ public class ScreenMainMenu extends Screen
         public double prevHeight;
         public double dropSpeed;
 
-        public LogoBlock(int var2, int var3) {
-            this.height = this.prevHeight = (double)(10 + var3) + rand.nextDouble() * 32.0D + (double)var2;
+        public LogoBlock(int x, int y) {
+            this.height = this.prevHeight = (double)(10 + y) + rand.nextDouble() * 32.0D + (double)x;
         }
 
         public void updateLogoEffects() {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
index 00c69d41a..3bccdbba2 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
@@ -14,13 +14,14 @@ import net.minecraft.core.enums.EnumSignPicture;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.packet.PacketSignUpdate;
 import net.minecraft.core.util.helper.ChatAllowedCharacters;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
 public class ScreenSignEditor extends Screen
 {
     private boolean inKeyboard = false;
-    public ScreenSignEditor(TileEntitySign sign)
+    public ScreenSignEditor(@NotNull TileEntitySign sign)
     {
         screenTitle = I18n.getInstance().translateKey("gui.edit_sign.label.title");
         editLine = 0;
@@ -44,7 +45,10 @@ public class ScreenSignEditor extends Screen
         buttons.add(new ButtonElement(1, width / 2 - 20, 120 + 50 + yOffset, 20, 20, "<"));
         buttons.add(new ButtonElement(2, width / 2, 120 + 50 + yOffset, 20, 20, ">"));
 
-        boolean wallSign = !((BlockLogicSign) block.getLogic()).isFreeStanding;
+        boolean wallSign = false;
+        if (Block.hasLogicClass(block, BlockLogicSign.class)) {
+            wallSign = !((BlockLogicSign) block.getLogic()).isFreeStanding;
+        }
 
         add(new ListenerButtonElement(30, width/2 - 50, 12 * 0 + 67 + (wallSign ? 31 : 0), 100, 12, "")
             .setActionListener(() -> {editLine = 0; inKeyboard = true;})).mute().hide();
@@ -161,30 +165,34 @@ public class ScreenSignEditor extends Screen
         GL11.glScalef(-scale, -scale, -scale);
         GL11.glRotatef(180F, 0.0F, 1.0F, 0.0F);
         Block<?> block = entitySign.getBlock();
-        if(((BlockLogicSign) block.getLogic()).isFreeStanding)
-        {
-            float signAngle = (float)((entitySign.getBlockMeta() & BlockLogicSign.MASK_SIDE) * 360) / 16F;
-            GL11.glRotatef(signAngle, 0.0F, 1.0F, 0.0F);
-            GL11.glTranslatef(0.0F, -1.0625F, 0.0F);
-        } else
-        {
-            int meta = entitySign.getBlockMeta() & BlockLogicSign.MASK_SIDE;
-            float signAngle = 0.0F;
-            if(meta == 2)
+        if (Block.hasLogicClass(block, BlockLogicSign.class)) {
+            BlockLogicSign sign = (BlockLogicSign) block.getLogic();
+            if(sign.isFreeStanding)
             {
-                signAngle = 180F;
-            }
-            if(meta == 4)
+                float signAngle = (float)((entitySign.getBlockMeta() & BlockLogicSign.MASK_SIDE) * 360) / 16F;
+                GL11.glRotatef(signAngle, 0.0F, 1.0F, 0.0F);
+                GL11.glTranslatef(0.0F, -1.0625F, 0.0F);
+            } else
             {
-                signAngle = 90F;
+                int meta = entitySign.getBlockMeta() & BlockLogicSign.MASK_SIDE;
+                float signAngle = 0.0F;
+                if(meta == 2)
+                {
+                    signAngle = 180F;
+                }
+                if(meta == 4)
+                {
+                    signAngle = 90F;
+                }
+                if(meta == 5)
+                {
+                    signAngle = -90F;
+                }
+                GL11.glRotatef(signAngle, 0.0F, 1.0F, 0.0F);
+                GL11.glTranslatef(0.0F, -1.0625F, 0.0F);
             }
-            if(meta == 5)
-            {
-                signAngle = -90F;
-            }
-            GL11.glRotatef(signAngle, 0.0F, 1.0F, 0.0F);
-            GL11.glTranslatef(0.0F, -1.0625F, 0.0F);
         }
+
         if((updateCounter / 6) % 2 == 0)
         {
             entitySign.lineBeingEdited = editLine;
@@ -212,7 +220,7 @@ public class ScreenSignEditor extends Screen
     }
 
     protected String screenTitle;
-    private TileEntitySign entitySign;
+    private final @NotNull TileEntitySign entitySign;
     private int updateCounter;
     private int editLine;
     private int yOffset = 0;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
index ab11bcba0..1591c2e7c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
@@ -157,13 +157,23 @@ public abstract class ScreenContainerAbstract extends Screen
 	@Override
 	public void keyPressed(final char eventCharacter, final int eventKey, int mx, int my)
 	{
-		if (eventKey == Keyboard.KEY_ESCAPE || mc.gameSettings.keyInventory.isKeyboardKey(eventKey) || eventKey == Keyboard.KEY_BACK)
+		if (eventKey == Keyboard.KEY_ESCAPE || eventKey == Keyboard.KEY_BACK)
 		{
 			mc.thePlayer.closeScreen();
 		}
 		int slotId = getSlotId(mx, my);
+		checkKeybind(slotId, eventKey, -1);
+	}
+
+	public boolean checkKeybind(int slotId, int key, int mouseButton) {
+		boolean cancelClick = false;
+		if (mc.gameSettings.keyInventory.isKeyOrMouse(key, mouseButton))
+		{
+			mc.thePlayer.closeScreen();
+			cancelClick = true;
+		}
 		if(slotId >= 0) {
-			if(mc.gameSettings.keyShowRecipe.isKeyboardKey(eventKey)){
+			if(mc.gameSettings.keyShowRecipe.isKeyOrMouse(key, mouseButton)){
 				Slot slot = inventorySlots.slots.get(slotId);
 				if(slot.hasItem()){
 					String query = "r:"+slot.getItemStack().getDisplayName()+"!";
@@ -172,9 +182,9 @@ public abstract class ScreenContainerAbstract extends Screen
 					GuidebookPageManager.searchQuery = SearchQuery.resolve(query);
 					GuidebookPageSearch.searchField.setText(query);
 					ScreenGuidebook.getPageManager().updatePages();
-                    if (!((SearchableGuidebookSection) GuidebookSections.CRAFTING).searchPages(GuidebookPageManager.searchQuery).isEmpty()) {
+					if (!((SearchableGuidebookSection) GuidebookSections.CRAFTING).searchPages(GuidebookPageManager.searchQuery).isEmpty()) {
 						ScreenGuidebook.getPageManager().setCurrentPage(ScreenGuidebook.getPageManager().getSectionIndex(GuidebookSections.CRAFTING), true);
-                    } else if (!((SearchableGuidebookSection) GuidebookSections.FURNACE).searchPages(GuidebookPageManager.searchQuery).isEmpty()) {
+					} else if (!((SearchableGuidebookSection) GuidebookSections.FURNACE).searchPages(GuidebookPageManager.searchQuery).isEmpty()) {
 						ScreenGuidebook.getPageManager().setCurrentPage(ScreenGuidebook.getPageManager().getSectionIndex(GuidebookSections.FURNACE), true);
 					} else if (!((SearchableGuidebookSection) GuidebookSections.BLAST_FURNACE).searchPages(GuidebookPageManager.searchQuery).isEmpty()) {
 						ScreenGuidebook.getPageManager().setCurrentPage(ScreenGuidebook.getPageManager().getSectionIndex(GuidebookSections.BLAST_FURNACE), true);
@@ -183,8 +193,9 @@ public abstract class ScreenContainerAbstract extends Screen
 					}
 					mc.thePlayer.displayGuidebookScreen();
 				}
+				cancelClick = true;
 			}
-			if(mc.gameSettings.keyShowUsage.isKeyboardKey(eventKey)){
+			if(mc.gameSettings.keyShowUsage.isKeyOrMouse(key, mouseButton)){
 				Slot slot = inventorySlots.slots.get(slotId);
 				if(slot.hasItem()) {
 					String query = "u:" + slot.getItemStack().getDisplayName() + "!";
@@ -204,54 +215,69 @@ public abstract class ScreenContainerAbstract extends Screen
 					}
 					mc.thePlayer.displayGuidebookScreen();
 				}
+				cancelClick = true;
 			}
-			if(mc.gameSettings.keyDrop.isKeyboardKey(eventKey)) {
+			if(mc.gameSettings.keyDrop.isKeyOrMouse(key, mouseButton)) {
 				boolean ctrl = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL);
 				int amount = 1;
 				if(ctrl) amount = 64;
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.DROP, new int[] {slotId, amount}, mc.thePlayer);
+				cancelClick = true;
 			}
 			// Horrifying
-			if (mc.gameSettings.keyHotBarSlot1.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot1.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 1}, mc.thePlayer);
+				cancelClick = true;
 			}
-			if (mc.gameSettings.keyHotBarSlot2.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot2.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 2}, mc.thePlayer);
+				cancelClick = true;
 			}
-			if (mc.gameSettings.keyHotBarSlot3.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot3.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 3}, mc.thePlayer);
+				cancelClick = true;
 			}
-			if (mc.gameSettings.keyHotBarSlot4.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot4.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 4}, mc.thePlayer);
+				cancelClick = true;
 			}
-			if (mc.gameSettings.keyHotBarSlot5.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot5.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 5}, mc.thePlayer);
+				cancelClick = true;
 			}
-			if (mc.gameSettings.keyHotBarSlot6.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot6.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 6}, mc.thePlayer);
+				cancelClick = true;
 			}
-			if (mc.gameSettings.keyHotBarSlot7.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot7.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 7}, mc.thePlayer);
+				cancelClick = true;
 			}
-			if (mc.gameSettings.keyHotBarSlot8.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot8.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 8}, mc.thePlayer);
+				cancelClick = true;
 			}
-			if (mc.gameSettings.keyHotBarSlot9.isKeyboardKey(eventKey)){
+			if (mc.gameSettings.keyHotBarSlot9.isKeyOrMouse(key, mouseButton)){
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.HOTBAR_ITEM_SWAP, new int[] {slotId, 9}, mc.thePlayer);
+				cancelClick = true;
 			}
 
-			if(mc.gameSettings.keySortInventory.isKeyboardKey(eventKey)) {
+			if(mc.gameSettings.keySortInventory.isKeyOrMouse(key, mouseButton)) {
 				mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, InventoryAction.SORT, new int[] {slotId}, mc.thePlayer);
+				cancelClick = true;
 			}
 		}
-		if (mc.currentScreen == this && mc.gameSettings.keyGuidebook.isKeyboardKey(eventKey)) {
+		if (mc.currentScreen == this && mc.gameSettings.keyGuidebook.isKeyOrMouse(key, mouseButton)) {
 			mc.thePlayer.displayGuidebookScreen();
+			cancelClick = true;
 		}
+		return cancelClick;
 	}
 
 	@Override
 	public void mouseClicked(final int mx, final int my, int buttonNum)
 	{
+		if (checkKeybind(getSlotId(mx, my), -1, buttonNum)) return;
 		super.mouseClicked(mx, my, buttonNum);
 		if(mc.gameSettings.enableItemDragging.value) {
 			itemDragHandler.mouseEvent(mx, my, buttonNum, true);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/crafting/displays/DisplayAdapterMapDuplication.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/crafting/displays/DisplayAdapterMapDuplication.java
index 7b5e6951f..8c1353073 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/crafting/displays/DisplayAdapterMapDuplication.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/crafting/displays/DisplayAdapterMapDuplication.java
@@ -18,7 +18,7 @@ public class DisplayAdapterMapDuplication implements RecipeDisplayAdapter<Recipe
         initMap.getData().putBoolean("initialized", true);
         ItemStack initMapX2 = new ItemStack(initMap);
         initMapX2.stackSize = 2;
-        RecipeSymbol[] symbols = {new RecipeSymbol(initMap), new RecipeSymbol(Items.MAP.getDefaultStack()), null, null, new RecipeSymbol(initMapX2)};
+        RecipeSymbol[] symbols = {new RecipeSymbol(initMap), new RecipeSymbol(Items.PAPER.getDefaultStack()), null, null, new RecipeSymbol(initMapX2)};
 
         for (int i = 0; i < 4; i++) {
             int x = 13 + 18 * (i % 2) + xOffset;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentFireBar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentFireBar.java
index 0bcc236f2..b1736f267 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentFireBar.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentFireBar.java
@@ -15,7 +15,7 @@ public class HudComponentFireBar
 
     @Override
     public boolean isVisible(Minecraft mc) {
-        return mc.playerController.canHurtPlayer() && !mc.thePlayer.getGamemode().isPlayerInvulnerable() && mc.thePlayer.remainingFireTicks > 0;
+        return mc.gameSettings.immersiveMode.drawHotbar() && mc.playerController.canHurtPlayer() && !mc.thePlayer.getGamemode().isPlayerInvulnerable() && mc.thePlayer.remainingFireTicks > 0;
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java
index 34b9ebb2b..0264d808b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java
@@ -138,7 +138,10 @@ public class HudComponentHotbar
         // Render selector
         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);
+        GL11.glPushMatrix();
+        GL11.glTranslatef(0, 0, 1f);
+        hud.heldItemTooltipElement.updateAndRender(mc, x + 5 + 182/2, y - 29);
+        GL11.glPopMatrix();
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java b/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
index 1edd03465..aac134037 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
@@ -130,6 +130,10 @@ public class ScreenOptions
     private void drawPagesListItems(int x, int y, int width, int mouseX, int mouseY) {
         int y2 = y;
         for(OptionsPage page : OptionsPageRegistry.getInstance().getPages()) {
+            if (!page.isVisible(this.mc)) {
+                continue;
+            }
+
             String translated = I18n.getInstance().translateKey(page.getTranslationKey());
             int textColor = 0xFF7F7F7F;
             if (page == selectedPage) {
@@ -212,7 +216,15 @@ public class ScreenOptions
     }
 
     private int getTotalPagesListHeight() {
-        return PAGE_BUTTON_HEIGHT * OptionsPageRegistry.getInstance().getPages().size();
+        int acc = 0;
+        for(OptionsPage page : OptionsPageRegistry.getInstance().getPages()) {
+            if (!page.isVisible(this.mc)) {
+                continue;
+            }
+            acc++;
+        }
+
+        return PAGE_BUTTON_HEIGHT * acc;
     }
 
     @Override
@@ -468,6 +480,10 @@ public class ScreenOptions
                 pagesListY = top + (bottom - top - pagesListHeight) / 2;
             }
             for(OptionsPage page : OptionsPageRegistry.getInstance().getPages()) {
+                if (!page.isVisible(this.mc)) {
+                    continue;
+                }
+
                 if (mx >= 0 && mx <= pagesListWidth && my >= pagesListY && my <= pagesListY + PAGE_BUTTON_HEIGHT) {
                     for (OptionsComponent component : selectedPage.getComponents()) {
                         component.onClose();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/SearchFieldComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/SearchFieldComponent.java
index e6f0bd19b..9c1200fc3 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/SearchFieldComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/SearchFieldComponent.java
@@ -152,6 +152,9 @@ public class SearchFieldComponent
             return;
         }
         for (OptionsPage page : OptionsPageRegistry.getInstance().getPages()) {
+            if (!page.isVisible(mc)) {
+                continue;
+            }
             OptionsCategory pageCategory = new OptionsCategory(page.getTranslationKey(), page.getIcon());
             boolean hasComponents = false;
             for (OptionsComponent component : page.getComponents()) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPage.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPage.java
index 6c4f1d2e3..77be18ae0 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPage.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPage.java
@@ -3,6 +3,7 @@ package net.minecraft.client.gui.options.data;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.options.components.OptionsComponent;
 import net.minecraft.core.item.ItemStack;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -19,6 +20,10 @@ public class OptionsPage
         this.icon = icon;
     }
 
+    public boolean isVisible(final @NotNull Minecraft mc) {
+        return true;
+    }
+
     public OptionsPage withComponent(OptionsComponent component)
     {
         components.add(component);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPageDebug.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPageDebug.java
new file mode 100644
index 000000000..e0ed7502c
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPageDebug.java
@@ -0,0 +1,18 @@
+package net.minecraft.client.gui.options.data;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.core.item.ItemStack;
+import org.jetbrains.annotations.NotNull;
+
+public class OptionsPageDebug
+    extends OptionsPage
+{
+    public OptionsPageDebug(String translationKey, ItemStack icon) {
+        super(translationKey, icon);
+    }
+
+    @Override
+    public boolean isVisible(@NotNull Minecraft mc) {
+        return mc.gameSettings.developerMode.value;
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
index 70873e586..6e8836a25 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
@@ -87,6 +87,7 @@ public abstract class OptionsPages
                 .withComponent(new ToggleableOptionComponent(mc.gameSettings.itemDescriptions))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.hideUndiscoveredItems))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.dynamicCursor))
+                .withComponent(new BooleanOptionComponent(mc.gameSettings.musicToasts))
             )
             .withComponent(new OptionsCategory("gui.options.page.general.category.miscellaneous")
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.discordRichPresence))
@@ -118,6 +119,7 @@ public abstract class OptionsPages
         AUDIO = register(new OptionsPage("gui.options.page.audio.title", new ItemStack(Items.RECORD_CAT))
             .withComponent(new OptionsCategory("gui.options.page.audio.category.audio")
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.subtitles))
+                .withComponent(new ToggleableOptionComponent<>(mc.gameSettings.musicFrequency))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.muteOnLostFocus))
                 .withComponent(new FloatOptionComponent(mc.gameSettings.masterVolume))
                 .withComponent(new FloatOptionComponent(mc.gameSettings.musicVolume))
@@ -313,7 +315,7 @@ public abstract class OptionsPages
         SEARCH = register(new OptionsPage("gui.options.page.search.title", new ItemStack(Blocks.GLASS))
             .withComponent(new SearchFieldComponent())
         );
-        DEBUG = new OptionsPage("gui.options.page.debug.title", Blocks.BEDROCK.getDefaultStack())
+        DEBUG = register(new OptionsPageDebug("gui.options.page.debug.title", Blocks.BEDROCK.getDefaultStack())
             .withComponent(new OptionsCategory("gui.options.page.debug.category.controls")
                 .withComponent(new KeyBindingComponent(mc.gameSettings.keyToggleTextureAtlas))
                 .withComponent(new KeyBindingComponent(mc.gameSettings.keyToggleDebug))
@@ -434,6 +436,6 @@ public abstract class OptionsPages
                     throw new Error();
                 }))
                 .withComponent(new ShortcutComponent("gui.options.page.debug.button.garbage_collect", System::gc))
-            );
+            ));
     }
 }
\ No newline at end of file
diff --git a/game/client/src/main/java/net/minecraft/client/gui/toasts/AchievementToast.java b/game/client/src/main/java/net/minecraft/client/gui/toasts/AchievementToast.java
index 6e25d68db..3b4610a6d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/toasts/AchievementToast.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/toasts/AchievementToast.java
@@ -32,7 +32,7 @@ public class AchievementToast implements IToastable {
     }
 
     @Override
-    public int nameColor(long runtime) {
+    public int titleColor(long runtime) {
         return 0xffffff00;
     }
 
@@ -42,7 +42,7 @@ public class AchievementToast implements IToastable {
     }
 
     @Override
-    public int descriptionColor(long runtime) {
+    public int messageColor(long runtime) {
         return 0xffffffff;
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java b/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
index dce1e1dbe..8ff9ba60e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
@@ -168,10 +168,10 @@ public class GuiElementToastsHud extends Gui {
 
         drawGuiIcon(x, y, TOAST_WIDTH, TOAST_HEIGHT, TextureRegistry.getTexture(toast.getTexture(duration)));
         if(toast.messageOnly(duration)) {
-            drawStringConstrained(mc.font, toast.getMessage(duration), x + 30, y + 7, 120, toast.descriptionColor(duration));
+            drawStringConstrained(mc.font, toast.getMessage(duration), x + 30, y + 7, 120, toast.messageColor(duration));
         } else {
-            drawStringNoShadow(mc.font, toast.getTitle(duration), x + 30, y + 7, toast.nameColor(duration));
-            drawStringNoShadow(mc.font, toast.getMessage(duration), x + 30, y + 18, toast.descriptionColor(duration));
+            drawStringNoShadow(mc.font, toast.getTitle(duration), x + 30, y + 7, toast.titleColor(duration));
+            drawStringNoShadow(mc.font, toast.getMessage(duration), x + 30, y + 18, toast.messageColor(duration));
         }
 
         GL11.glDepthMask(true);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/toasts/IToastable.java b/game/client/src/main/java/net/minecraft/client/gui/toasts/IToastable.java
index 48ee651b1..4574ff953 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/toasts/IToastable.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/toasts/IToastable.java
@@ -9,11 +9,11 @@ public interface IToastable {
 
     String getTitle(long runtime);
 
-    int nameColor(long runtime);
+    int titleColor(long runtime);
 
     String getMessage(long runtime);
 
-    int descriptionColor(long runtime);
+    int messageColor(long runtime);
 
     double getAnimationProgress(long runtime);
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/toasts/MusicToast.java b/game/client/src/main/java/net/minecraft/client/gui/toasts/MusicToast.java
new file mode 100644
index 000000000..fad74c07b
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/toasts/MusicToast.java
@@ -0,0 +1,85 @@
+package net.minecraft.client.gui.toasts;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.item.Items;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class MusicToast
+    implements IToastable
+{
+    private static final double ANIMATION_DURATION_MILLIS = 6000L;
+    private long startTime;
+    private final @NotNull String title;
+    private final @Nullable String author;
+
+    public MusicToast(final @NotNull String title, final @Nullable String author) {
+        this.title = title;
+        this.author = author;
+    }
+
+    @Override
+    public boolean messageOnly(long runtime) {
+        return this.author == null;
+    }
+
+    @Override
+    public String getTitle(long runtime) {
+        return this.title;
+    }
+
+    @Override
+    public int titleColor(long runtime) {
+        return 0xFFFFFFFF;
+    }
+
+    @Override
+    public String getMessage(long runtime) {
+        if (this.author == null) {
+            return this.title;
+        } else {
+            return this.author;
+        }
+    }
+
+    @Override
+    public int messageColor(long runtime) {
+        if (this.author == null) {
+            return 0xFFFFFFFF;
+        } else {
+            return 0xFFAFAFAF;
+        }
+    }
+
+    @Override
+    public double getAnimationProgress(long runtime) {
+        runtime = System.currentTimeMillis() - startTime;
+        return runtime / ANIMATION_DURATION_MILLIS;
+    }
+
+    @Override
+    public String getTexture(long runtime) {
+        return "minecraft:gui/toast_music";
+    }
+
+    @Override
+    public void onToastStart() {
+        startTime = System.currentTimeMillis();
+    }
+
+    @Override
+    public void onToastEnd() {
+        // Do nothing
+    }
+
+    @Override
+    public boolean isEquivalentToast(@NotNull IToastable toast) {
+        return toast instanceof MusicToast;
+    }
+
+    @Override
+    public @Nullable ItemStack getIcon(long runtime) {
+        return Items.RECORD_CAT.getDefaultStack();
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/input/PlayerInput.java b/game/client/src/main/java/net/minecraft/client/input/PlayerInput.java
index 700a1a729..0a3e3ccc9 100644
--- a/game/client/src/main/java/net/minecraft/client/input/PlayerInput.java
+++ b/game/client/src/main/java/net/minecraft/client/input/PlayerInput.java
@@ -2,6 +2,7 @@ package net.minecraft.client.input;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.option.GameSettings;
+import net.minecraft.client.option.KeyBinding;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.util.helper.MathHelper;
 
@@ -33,12 +34,12 @@ public class PlayerInput {
 		this.gameSettings = mc.gameSettings;
 	}
 
-	public void keyEvent(int keyCode, boolean pressed) {
+	public void keyEvent(int keyCode, int mouseCode, boolean pressed) {
 		if(mc.currentScreen != null) {
 			return;
 		}
 		
-		if(gameSettings.keySneak.isKeyboardKey(keyCode)) {
+		if(gameSettings.keySneak.isKeyOrMouse(keyCode, mouseCode)) {
 			if(gameSettings.sneakToggle.value && !mc.thePlayer.noPhysics) {
 				if(pressed) {
 					sneak = !sneak;
@@ -48,29 +49,29 @@ public class PlayerInput {
 			}
 		}
 		
-		if(gameSettings.keyForward.isKeyboardKey(keyCode)) {
+		if(gameSettings.keyForward.isKeyOrMouse(keyCode, mouseCode) ) {
 			pressedForward = pressed;
 			isAutoWalkOn = false;
 		}
-		if(gameSettings.keyBack.isKeyboardKey(keyCode)) {
+		if(gameSettings.keyBack.isKeyOrMouse(keyCode, mouseCode)) {
 			pressedBackward = pressed;
 			isAutoWalkOn = false;
 		}
-		if(gameSettings.keyLeft.isKeyboardKey(keyCode)) {
+		if(gameSettings.keyLeft.isKeyOrMouse(keyCode, mouseCode)) {
 			pressedLeft = pressed;
 		}
-		if(gameSettings.keyRight.isKeyboardKey(keyCode)) {
+		if(gameSettings.keyRight.isKeyOrMouse(keyCode, mouseCode)) {
 			pressedRight = pressed;
 		}
-		if(gameSettings.keyJump.isKeyboardKey(keyCode)) {
+		if(gameSettings.keyJump.isKeyOrMouse(keyCode, mouseCode)) {
 			pressedJump = pressed;
 		}
 
-		if(gameSettings.keyAutoWalk.isKeyboardKey(keyCode) && pressed) {
+		if(gameSettings.keyAutoWalk.isKeyOrMouse(keyCode, mouseCode) && pressed) {
 			isAutoWalkOn = true;
 		}
 
-		if(gameSettings.keyEasyBridge.isKeyboardKey(keyCode) && pressed) {
+		if(gameSettings.keyEasyBridge.isKeyOrMouse(keyCode, mouseCode) && pressed) {
 			gameSettings.easyBridge.toggle();
 			mc.hudIngame.heldItemTooltipElement.setOptionNameAndValueString(gameSettings.easyBridge);
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
index ddd128978..9d8490f35 100644
--- a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
+++ b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
@@ -14,6 +14,7 @@ import com.mojang.logging.LogUtils;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.discord.RichPresenceHandlerThread;
+import net.minecraft.client.enums.MusicFrequency;
 import net.minecraft.client.gui.TooltipElement;
 import net.minecraft.client.gui.hud.component.HudComponents;
 import net.minecraft.client.gui.options.ScreenOptions;
@@ -136,6 +137,8 @@ public class GameSettings {
 	public OptionBoolean turnWithVehicle = new OptionBoolean(this, "turnWithVehicle", true);
 	public OptionBoolean disableCrashHandler = new OptionBoolean(this, "disableCrashHandler", false);
 	public OptionBoolean enableMultiDrawRendering = new OptionBoolean(this, "enableMultiDrawRendering", true);
+	public OptionBoolean musicToasts = new OptionBoolean(this, "musicToasts", true);
+	public OptionEnum<MusicFrequency> musicFrequency = new OptionEnum<>(this, "musicFrequency", MusicFrequency.class, MusicFrequency.DEFAULT);
 
 	public OptionBoolean enableDevResourceLoading = new OptionBoolean(this, "enableDevResourceLoading", false);
 	public OptionBoolean downloadSoundfiles = new OptionBoolean(this, "downloadSoundfiles", true);
@@ -538,6 +541,9 @@ public class GameSettings {
 			mc.textureManager.refreshTexturesAndDisplayErrors();
 			mc.renderGlobal.allChanged();
 		}
+		if(option == musicFrequency) {
+			mc.sndManager.resetMusicTicks();
+		}
 	}
 
 	public void loadOptions() {
diff --git a/game/client/src/main/java/net/minecraft/client/option/KeyBinding.java b/game/client/src/main/java/net/minecraft/client/option/KeyBinding.java
index 6d5f29970..f38de4f2f 100644
--- a/game/client/src/main/java/net/minecraft/client/option/KeyBinding.java
+++ b/game/client/src/main/java/net/minecraft/client/option/KeyBinding.java
@@ -178,6 +178,10 @@ public class KeyBinding {
 		}
 		return false;
 	}
+
+	public boolean isKeyOrMouse(int key, int button) {
+		return isKeyboardKey(key) || isMouseButton(button);
+	}
 	
 	public boolean isBound() {
 		return inputDevice != null;
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionVolume.java b/game/client/src/main/java/net/minecraft/client/option/OptionVolume.java
index 9bfb1b8d0..159567b38 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionVolume.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionVolume.java
@@ -1,11 +1,14 @@
 package net.minecraft.client.option;
 
+import com.mojang.logging.LogUtils;
 import net.minecraft.client.sound.SoundCategoryHelper;
 import net.minecraft.client.sound.SoundEngine;
 import net.minecraft.core.sound.SoundCategory;
+import org.slf4j.Logger;
 import paulscode.sound.SoundSystem;
 
 public class OptionVolume extends OptionFloat {
+	private static final Logger LOGGER = LogUtils.getLogger();
 	public final SoundCategory soundCategory;
 
 	//do *not* add @NotNull to gameSettings here, breaks modding for some abstract reason
@@ -19,12 +22,16 @@ public class OptionVolume extends OptionFloat {
 		super.onUpdate();
 		gameSettings.mc.sndManager.updateOptions();
 		SoundSystem soundSystem = SoundEngine.getSoundSystem();
-		if (soundSystem != null) {
-			if (soundCategory != SoundCategory.GUI_SOUNDS && !soundSystem.playing("sound_audio_options")) {
-				gameSettings.mc.sndManager.playSoundWithID(soundCategory.changedSound, soundCategory, 1f, 1f, "sound_audio_options");
-			} else if (soundCategory != SoundCategory.GUI_SOUNDS) {
-				soundSystem.setVolume("sound_audio_options", SoundCategoryHelper.getEffectiveVolume(soundCategory, gameSettings));
+		try {
+			if (soundSystem != null) {
+				if (soundCategory != SoundCategory.GUI_SOUNDS && !soundSystem.playing("sound_audio_options")) {
+					gameSettings.mc.sndManager.playSoundWithID(soundCategory.changedSound, soundCategory, 1f, 1f, "sound_audio_options");
+				} else if (soundCategory != SoundCategory.GUI_SOUNDS) {
+					soundSystem.setVolume("sound_audio_options", SoundCategoryHelper.getEffectiveVolume(soundCategory, gameSettings));
+				}
 			}
+		} catch (Exception e) { // Not sure why but this block of code, specifically the `soundSystem.playing("sound_audio_options")` line seems to be able to through an NPE *sometimes* for *some* users.
+			LOGGER.error("Unexpected error occurred while trying to preview sounds! This is a poorly known issue please report!", e);
 		}
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/TextureManager.java b/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
index 738044ccb..27ef2c4b5 100644
--- a/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
+++ b/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
@@ -96,7 +96,7 @@ public class TextureManager {
 		addNativeDynamicTextures(this.mc.gameSettings.animations.value);
 		if (this.mc.gameSettings.customAnimations.value && this.mc.gameSettings.animations.value == ANIMATIONS_CUSTOM) {
 			try {
-				loadCustomAnimations();
+				loadCustomAnimations(errors);
 			}catch (final TexturePackException e) {
 				errors.add(e);
 			}
@@ -144,16 +144,20 @@ public class TextureManager {
 		dynamicTextures.put(texture.targetTexture.namespaceId.namespace() + ":" + TextureRegistry.stitcherMapReverse.get(texture.targetTexture.parentAtlas) + "/" + texture.targetTexture.namespaceId.value(), texture);
 	}
 
-	private void loadCustomAnimations() {
+	private void loadCustomAnimations(final Collection<? super Throwable> errors) {
 		if(!this.mc.gameSettings.customAnimations.value) {
 			return;
 		}
 
 		for (final AtlasStitcher stitcher : TextureRegistry.stitcherMap.values()){
 			for (final IconCoordinate c : stitcher.textureMap.values()) {
-				if (c.hasMeta("animation")) {
-                    LOGGER.debug("Icon '{}' has 'animation' meta!", c.namespaceId);
-					addDynamicTextureOverride(new DynamicTextureCustom(c, c.getMeta("animation", AnimationProperties.class)), true);
+				try {
+					if (c.hasMeta("animation")) {
+						LOGGER.debug("Icon '{}' has 'animation' meta!", c.namespaceId);
+						addDynamicTextureOverride(new DynamicTextureCustom(c, c.getMeta("animation", AnimationProperties.class)), true);
+					}
+				} catch (final TexturePackException e) {
+					errors.add(e);
 				}
 			}
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
index 1de314f21..67d096a7a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
@@ -574,6 +574,10 @@ public class WorldRenderer
             }
             systemTime = System.nanoTime();
         }
+
+        // Render toasts
+        mc.guiToasts.render(partialTick);
+
         if(mc.currentScreen != null)
         {
             Debug.change("gui");
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java b/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
index 73c7317a7..2cfc6e101 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java
@@ -4,6 +4,8 @@ import net.minecraft.client.render.LightingCache;
 import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.util.phys.AABB;
+import org.jetbrains.annotations.NotNull;
+import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
diff --git a/game/client/src/main/java/net/minecraft/client/sound/NamedSoundRepository.java b/game/client/src/main/java/net/minecraft/client/sound/NamedSoundRepository.java
index 401c47fe8..019e7433e 100644
--- a/game/client/src/main/java/net/minecraft/client/sound/NamedSoundRepository.java
+++ b/game/client/src/main/java/net/minecraft/client/sound/NamedSoundRepository.java
@@ -10,6 +10,7 @@ import com.google.gson.JsonParser;
 import net.minecraft.client.render.texturepack.TexturePack;
 import net.minecraft.core.data.registry.Registry;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
 import java.io.InputStream;
@@ -161,6 +162,8 @@ public class NamedSoundRepository extends Registry<SoundEvent> {
                 event,
                 pack,
                 path,
+                null,
+                null,
                 1f,
                 1f,
                 1,
@@ -173,6 +176,16 @@ public class NamedSoundRepository extends Registry<SoundEvent> {
     public SoundEntry getSoundEntry(SoundEvent event, TexturePack pack, JsonObject jObj) throws JsonParseException {
         String name = jObj.get("name").getAsString(); // Required
 
+        @Nullable String title = null;
+        if (jObj.has("title")) {
+            title = jObj.get("title").getAsString();
+        }
+
+        @Nullable String author = null;
+        if (jObj.has("author")) {
+            author = jObj.get("author").getAsString();
+        }
+
         float volume = 1;
         if (jObj.has("volume")) {
             volume = jObj.get("volume").getAsFloat();
@@ -213,6 +226,8 @@ public class NamedSoundRepository extends Registry<SoundEvent> {
                 event,
                 pack,
                 name,
+                title,
+                author,
                 volume,
                 pitch,
                 weight,
diff --git a/game/client/src/main/java/net/minecraft/client/sound/SoundEngine.java b/game/client/src/main/java/net/minecraft/client/sound/SoundEngine.java
index 4d478c4bb..e49746bff 100644
--- a/game/client/src/main/java/net/minecraft/client/sound/SoundEngine.java
+++ b/game/client/src/main/java/net/minecraft/client/sound/SoundEngine.java
@@ -8,6 +8,7 @@ import java.util.concurrent.locks.ReentrantLock;
 import com.mojang.logging.LogUtils;
 import net.betterthanadventure.sound.LibraryLWJGL3OpenAL;
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.toasts.MusicToast;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.MathHelper;
@@ -22,7 +23,6 @@ import paulscode.sound.codecs.CodecWav;
 public class SoundEngine
 {
 	private static final Logger LOGGER = LogUtils.getLogger();
-	private static final int MUSIC_INTERVAL = 6000;
 	private static @Nullable SoundSystem soundSystem;
 	private static Lock lock = new ReentrantLock();
 	private static boolean loaded = false;
@@ -40,9 +40,12 @@ public class SoundEngine
 	public SoundEngine() {
         this.idCounter = 0;
         this.random = new Random();
-        this.ticksBeforeMusic = this.random.nextInt(MUSIC_INTERVAL);
     }
 
+	public void resetMusicTicks() {
+		this.ticksBeforeMusic = this.options.musicFrequency.value.interval == 0 ? 0 : this.random.nextInt(this.options.musicFrequency.value.interval);
+	}
+
 	public void destroy() {
 		try {
 			lock.lock();
@@ -102,6 +105,7 @@ public class SoundEngine
 		try {
 			lock.lock();
 			this.options = gamesettings;
+			this.resetMusicTicks();
 			if (!isLoaded() && SoundCategoryHelper.isAnyEnabled(gamesettings)) {
 				loadLibrary();
 			}
@@ -152,11 +156,16 @@ public class SoundEngine
 				if (event == null) return;
 				final SoundEntry entry = event.getRandomEntry();
 				if (entry != null) {
-					this.ticksBeforeMusic = this.random.nextInt(MUSIC_INTERVAL) + MUSIC_INTERVAL;
+					this.resetMusicTicks();
+					this.ticksBeforeMusic += this.options.musicFrequency.value.interval;
 					soundSystem.backgroundMusic(BG_MUSIC, entry.getURL(), entry.name, false);
 					soundSystem.setPitch(BG_MUSIC, entry.pitch);
 					soundSystem.setVolume(BG_MUSIC, SoundCategoryHelper.getEffectiveVolume(SoundCategory.MUSIC, this.options) * entry.volume);
 					soundSystem.play(BG_MUSIC);
+
+					if (this.options.musicToasts.value && entry.title != null) {
+						mc.guiToasts.addToast(new MusicToast(entry.title, entry.author));
+					}
 				}
 			}
 		} catch (Exception e) {
diff --git a/game/client/src/main/java/net/minecraft/client/sound/SoundEntry.java b/game/client/src/main/java/net/minecraft/client/sound/SoundEntry.java
index a0f905a64..7a175cf74 100644
--- a/game/client/src/main/java/net/minecraft/client/sound/SoundEntry.java
+++ b/game/client/src/main/java/net/minecraft/client/sound/SoundEntry.java
@@ -14,6 +14,9 @@ public class SoundEntry {
 
     public final @NotNull String name;
 
+    public final @Nullable String title;
+    public final @Nullable String author;
+
     /**
      * Weight of entry in random bag
      */
@@ -50,6 +53,8 @@ public class SoundEntry {
         (
         @NotNull SoundEvent parentEvent, @NotNull TexturePack pack,
         @NotNull String name,
+        @Nullable String title,
+        @Nullable String author,
         float volume,
         float pitch,
         int weight,
@@ -61,6 +66,8 @@ public class SoundEntry {
         this.parent = parentEvent;
         this.pack = pack;
         this.name = name;
+        this.title = title;
+        this.author = author;
         this.volume = volume;
         this.pitch = pitch;
         this.weight = weight;
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/sapling/cherry.png b/game/client/src/main/resources/assets/minecraft/textures/block/sapling/cherry.png
index 69c9a46c6..4572b2b97 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/sapling/cherry.png and b/game/client/src/main/resources/assets/minecraft/textures/block/sapling/cherry.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/toast_music.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/toast_music.png
new file mode 100644
index 000000000..442d87540
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/toast_music.png differ
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMoss.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMoss.java
index 9e19c4a8f..5cb8453d7 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMoss.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMoss.java
@@ -2,12 +2,14 @@ package net.minecraft.core.block;
 
 import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
 import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.item.IBonemealable;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.world.generate.feature.WorldFeatureOre;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.HashMap;
@@ -30,52 +32,37 @@ public class BlockLogicMoss extends BlockLogic implements IBonemealable {
 		}
 		
 		if (world.areBlocksLoaded(x, y, z, 16)) {
-			if (canMossSpread(world, x, y, z) && rand.nextInt(20) == 0) {
-				spreadMossRandomly(world, x, y, z, rand, false);
-			}
-		}
-	}
-	
-	public boolean spreadMossRandomly(World world, int x, int y, int z, Random random, boolean ignoreLight) {
-		int mossX = x, mossY = y, mossZ = z;
-//		{
-//			//Moss grows in a 3x5x3
-//			x1 = (x + random.nextInt(3)) - 1;
-//			y1 = (y + random.nextInt(5)) - 3;
-//			z1 = (z + random.nextInt(3)) - 1;
-//		}
-		{
-			//Moss only grows to neighbor blocks
-			int side = random.nextInt(6);
-			if(side == 0) mossZ--; //North
-			if(side == 1) mossX++; //East
-			if(side == 2) mossZ++; //South
-			if(side == 3) mossX--; //West
-			if(side == 4) mossY++; //Up
-			if(side == 5) mossY--; //Down
-		}
-		
-		if (ignoreLight || !Block.isBuried(world, mossX, mossY, mossZ)) {
-			Block<?> mossStone = getMossBlock(world.getBlockId(mossX, mossY, mossZ));
-			if (mossStone != null) {
-				world.setBlockWithNotify(mossX, mossY, mossZ, mossStone.id());
-				return true;
+			if (rand.nextInt(20) == 0 && airExposed(world, x, y, z)) {
+				Side randomSide = Side.getSideById(rand.nextInt(6));
+				int rX = x + randomSide.getOffsetX();
+				int rY = y + randomSide.getOffsetY();
+				int rZ = z + randomSide.getOffsetZ();
+				if (canMossSpread(world, rX, rY, rZ)) {
+					Block<?> mossStone = getMossBlock(world.getBlockId(rX, rY, rZ));
+					if (mossStone != null) {
+						world.setBlockWithNotify(rX, rY, rZ, mossStone.id());
+					}
+				}
 			}
 		}
-		
-		return false;
 	}
+
 	
 	public boolean canMossSpread(World world, int x, int y, int z) {
-		for (int i = 0; i < 6; i++) {
-			Side side = Side.getSideById(i);
-			if (world.getBlockLightValue(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ()) <= 5 && world.isBlockLoaded(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ())) continue;
-			return false;
+		if (!world.isBlockLoaded(x, y, z)) return false;
+		int maxBlockLight = 0;
+		int maxSkyLight = 0;
+		for (int i = 0; i < Side.sides.length; i++) {
+			Side s = Side.sides[i];
+			int blockLight = world.getBlockLightValue(x + s.getOffsetX(), y + s.getOffsetY(), z + s.getOffsetZ());
+			int skyLight = world.getSavedLightValue(LightLayer.Sky, x + s.getOffsetX(), y + s.getOffsetY(), z + s.getOffsetZ());
+			if (blockLight > maxBlockLight) { maxBlockLight = blockLight; }
+			if (skyLight > maxSkyLight) { maxSkyLight = skyLight; }
 		}
-		return true;
+		return maxBlockLight == 0 && maxSkyLight == 0;
 	}
 
-	public static Block<?> getMossBlock(int blockId) {
+	public static @Nullable Block<?> getMossBlock(int blockId) {
 		if (blockId == 0)
 			return null;
 		return getMossBlock(Blocks.blocksList[blockId]);
@@ -119,56 +106,47 @@ public class BlockLogicMoss extends BlockLogic implements IBonemealable {
 	public boolean onBonemealUsed(ItemStack itemstack, @Nullable Player player, World world, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced) {
 		if(!world.isClientSide)
 		{
+			if (!canMossSpread(world, blockX, blockY, blockZ) || !airExposed(world, blockX, blockY, blockZ)) return false;
 			if (player == null || player.getGamemode().consumeBlocks())
 			{
 				itemstack.stackSize--;
 			}
 			for(int j1 = 0; j1 < 32; j1++)
 			{
-				int k1 = blockX;
-				int l1 = blockY;
-				int i2 = blockZ;
+				int randomBlockX = blockX;
+				int randomBlockY = blockY;
+				int randomBlockZ = blockZ;
 				for(int j2 = 0; j2 < j1 / 16; j2++)
 				{
-					k1 += world.rand.nextInt(3) - 1;
-					l1 += ((world.rand.nextInt(3) - 1) * world.rand.nextInt(3)) / 2;
-					i2 += world.rand.nextInt(3) - 1;
+					randomBlockX += world.rand.nextInt(3) - 1;
+					randomBlockY += ((world.rand.nextInt(3) - 1) * world.rand.nextInt(3)) / 2;
+					randomBlockZ += world.rand.nextInt(3) - 1;
 				}
 
-				if(Block.isBuried(world, k1, l1, i2))
+				if(!airExposed(world, randomBlockX, randomBlockY, randomBlockZ))
 				{
 					continue;
 				}
 
-				if(world.getBlockLightValue(k1, l1 + 1, i2) > 5 ||
-						world.getBlockLightValue(k1, l1 - 1, i2)  > 5 ||
-						world.getBlockLightValue(k1 + 1, l1 , i2)  > 5 ||
-						world.getBlockLightValue(k1 - 1, l1 , i2)  > 5 ||
-						world.getBlockLightValue(k1, l1 , i2 - 1)  > 5 ||
-						world.getBlockLightValue(k1, l1 , i2 + 1)  > 5)
-				{
+				if(!canMossSpread(world,randomBlockX, randomBlockY, randomBlockZ)) {
 					continue;
 				}
 
-				int blockId = world.getBlockId(k1, l1, i2);
-				if(blockId == Blocks.STONE.id())
-					world.setBlockWithNotify(k1, l1, i2, Blocks.MOSS_STONE.id());
-				else if(blockId == Blocks.LIMESTONE.id())
-					world.setBlockWithNotify(k1, l1, i2, Blocks.MOSS_LIMESTONE.id());
-				else if(blockId == Blocks.GRANITE.id())
-					world.setBlockWithNotify(k1, l1, i2, Blocks.MOSS_GRANITE.id());
-				else if(blockId == Blocks.BASALT.id())
-					world.setBlockWithNotify(k1, l1, i2, Blocks.MOSS_BASALT.id());
-				else if(blockId == Blocks.COBBLE_STONE.id())
-					world.setBlockWithNotify(k1, l1, i2, Blocks.COBBLE_STONE_MOSSY.id());
-				else if(blockId == Blocks.BRICK_STONE_POLISHED.id())
-					world.setBlockWithNotify(k1, l1, i2, Blocks.BRICK_STONE_POLISHED_MOSSY.id());
-				else if(blockId == Blocks.LOG_OAK.id())
-					world.setBlockWithNotify(k1, l1, i2, Blocks.LOG_OAK_MOSSY.id());
-
+				Block block = getMossBlock(world.getBlockId(randomBlockX, randomBlockY, randomBlockZ));
+				if (block != null) {
+					world.setBlockWithNotify(randomBlockX, randomBlockY, randomBlockZ, block.id());
+				}
 			}
 
 		}
 		return true;
 	}
+
+	public boolean airExposed(@NotNull World world, int x, int y, int z) {
+		for (int i = 0; i < Side.sides.length; i++) {
+			Side s = Side.sides[i];
+			if (world.isAirBlock(x + s.getOffsetX(), y + s.getOffsetY(), z + s.getOffsetZ())) return true;
+		}
+		return false;
+	}
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java
index 0ae26536f..e39c3cbff 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java
@@ -4,6 +4,7 @@ package net.minecraft.core.block.entity;
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.tags.ListTag;
+import net.minecraft.core.block.BlockLogicRotatable;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.BlockLogicChest;
 import net.minecraft.core.block.BlockLogicTrommel;
@@ -21,6 +22,7 @@ import net.minecraft.core.item.Item;
 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.Direction;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
@@ -35,6 +37,7 @@ import java.util.Random;
 public class TileEntityTrommel extends TileEntity
         implements Container
 {
+    public static final int FUEL_SLOT_INDEX = 4;
 
     public TileEntityTrommel()
     {
@@ -118,7 +121,7 @@ public class TileEntityTrommel extends TileEntity
 
         burnTime = compoundTag.getShort("BurnTime");
         itemPopTime = compoundTag.getShort("CookTime");
-        currentItemBurnTime = getItemBurnTime(itemStacks[1]);
+        currentItemBurnTime = getItemBurnTime(itemStacks[FUEL_SLOT_INDEX]);
     }
 
     @Override
@@ -181,10 +184,10 @@ public class TileEntityTrommel extends TileEntity
         if(!isClient)
         {
         	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.COBBLE_NETHERRACK.id()) {
-            			itemStacks[4].stackSize--;
-            			if(itemStacks[4].stackSize <= 0) itemStacks[4] = null;
+            	if(currentItemBurnTime == 0 && itemStacks[0] == null && itemStacks[1] == null && itemStacks[2] == null && itemStacks[3] == null) {
+            		if(itemStacks[FUEL_SLOT_INDEX] != null && itemStacks[FUEL_SLOT_INDEX].itemID == Blocks.COBBLE_NETHERRACK.id()) {
+            			itemStacks[FUEL_SLOT_INDEX].stackSize--;
+            			if(itemStacks[FUEL_SLOT_INDEX].stackSize <= 0) itemStacks[FUEL_SLOT_INDEX] = null;
             			if (worldObj != null) {
                             BlockLogicTrommel.updateTrommelBlockState(true, worldObj, x, y, z);
                         } else if (carriedBlock != null) {
@@ -198,19 +201,19 @@ public class TileEntityTrommel extends TileEntity
                 nextToSieve = (nextToSieve+1)%4;
             if(burnTime == 0 && canProduce(nextToSieve))
             {
-                currentItemBurnTime = burnTime = getItemBurnTime(itemStacks[4]);
+                currentItemBurnTime = burnTime = getItemBurnTime(itemStacks[FUEL_SLOT_INDEX]);
                 if(burnTime > 0)
                 {
                     flag1 = true;
-                    if(itemStacks[4] != null)
+                    if(itemStacks[FUEL_SLOT_INDEX] != null)
                     {
-                    	if(itemStacks[4].getItem() == Items.BUCKET_LAVA) {
-                    		itemStacks[4] = new ItemStack(Items.BUCKET);
+                    	if(itemStacks[FUEL_SLOT_INDEX].getItem() == Items.BUCKET_LAVA) {
+                    		itemStacks[FUEL_SLOT_INDEX] = new ItemStack(Items.BUCKET);
                     	}else {
-                            itemStacks[4].stackSize--;
-                            if(itemStacks[4].stackSize <= 0)
+                            itemStacks[FUEL_SLOT_INDEX].stackSize--;
+                            if(itemStacks[FUEL_SLOT_INDEX].stackSize <= 0)
                             {
-                                itemStacks[4] = null;
+                                itemStacks[FUEL_SLOT_INDEX] = null;
                             }
                     	}
                     }
@@ -267,62 +270,59 @@ public class TileEntityTrommel extends TileEntity
         if(itemResult!=null)
         {
         	// Check if chest is adjacent
-        	int xOffset = 0;
-        	int zOffset = 0;
+            Direction direction = Direction.NONE;
         	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;
+                // 90-degree rotation CCW around the y-axis to get the direction of the output slot
+                switch (BlockLogicRotatable.getDirectionFromMeta(worldObj.getBlockMetadata(x, y, z))) {
+                    case NORTH: {
+                        direction = Direction.WEST;
+                        break;
+                    }
+                    case SOUTH: {
+                        direction = Direction.EAST;
+                        break;
+                    }
+                    case WEST: {
+                        direction = Direction.SOUTH;
+                        break;
+                    }
+                    case EAST: {
+                        direction = Direction.NORTH;
+                        break;
+                    }
                 }
             }
-        	int adjacentId = worldObj != null ? worldObj.getBlockId(x + xOffset, y, z + zOffset) : 0;
-        	
-        	Container chest = null;
-        	if (Block.hasLogicClass(Blocks.blocksList[adjacentId], BlockLogicChest.class)) {
-                assert worldObj != null;
-                chest = BlockLogicChest.getInventory(worldObj, x + xOffset, y, z + zOffset);
-        	}
-        	
-        	if (chest != null)
-        	{
-        		for (int i = 0; i < chest.getContainerSize(); i++)
-        		{
-        			ItemStack slot = chest.getItem(i);
-        			if (slot != null && slot.itemID == itemResult.itemID && slot.getMetadata() == itemResult.getMetadata())
-        			{
+        	int adjacentId = worldObj != null ? worldObj.getBlockId(x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ()) : 0;
+
+        	if (worldObj != null && Block.hasLogicClass(Blocks.blocksList[adjacentId], BlockLogicChest.class)) {
+                Container chest = BlockLogicChest.getInventory(worldObj, x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ());
+
+                for (int i = 0; i < chest.getContainerSize(); i++)
+                {
+                    ItemStack slot = chest.getItem(i);
+                    if (slot != null && slot.itemID == itemResult.itemID && slot.getMetadata() == itemResult.getMetadata())
+                    {
                         for(; slot.stackSize + 1 <= slot.getMaxStackSize(); itemResult.stackSize--){
                             slot.stackSize ++;
                             chest.setItem(i, slot);
                             if(itemResult.stackSize <= 0)
                                 return;
                         }
-        			}
-        		}
+                    }
+                }
                 if(itemResult.stackSize <= 0)
                     return;
-        		for (int i = 0; i < chest.getContainerSize(); i++)
-        		{
-        			ItemStack slot = chest.getItem(i);
-        			if (slot == null)
-        			{
-        				chest.setItem(i, itemResult);
-        				return;
-        			}
-        		}
+                for (int i = 0; i < chest.getContainerSize(); i++)
+                {
+                    ItemStack slot = chest.getItem(i);
+                    if (slot == null)
+                    {
+                        chest.setItem(i, itemResult);
+                        return;
+                    }
+                }
         	}
+
             if(itemResult.stackSize > 0) {
                 if (worldObj != null) {
                     worldObj.dropItem(x, y, z, itemResult);
diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCraftingWithTool.java b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCraftingWithTool.java
index c8f46f4b9..1f78ec708 100644
--- a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCraftingWithTool.java
+++ b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCraftingWithTool.java
@@ -36,9 +36,9 @@ public class RecipeEntryCraftingWithTool extends RecipeEntryCraftingDynamic impl
             for (int y = 0; y < 3; y++) {
                 ItemStack stack = containerCrafting.getItemStackAt(x, y);
                 if (stack == null) continue;
-                if (toolToUse.matches(stack)) {
+                if (toolToUse.matches(stack) && !toolMatch) {
                     toolMatch = true;
-                } else if (inputSymbol.matches(stack)) {
+                } else if (inputSymbol.matches(stack) && !itemMatch) {
                     itemMatch = true;
                 } else {
                     return false;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Entity.java b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
index ae747c612..659f3516a 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Entity.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
@@ -1241,7 +1241,7 @@ public abstract class Entity
         if (vehicle == null) {
             return;
         }
-        if(vehicle.isRemoved() || isSneaking())
+        if(vehicle.isRemoved() || isSneaking() || (vehicle instanceof Entity && !((Entity) vehicle).isAlive()))
         {
             vehicle.ejectRider();
             return;
@@ -1317,6 +1317,10 @@ public abstract class Entity
         }
         this.vehicle = vehicle;
         vehicle.setPassenger(this);
+        if (vehicle instanceof Entity) {
+            ((Entity) vehicle).fallDistance += this.fallDistance;
+            this.fallDistance = 0;
+        }
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Mob.java b/game/core/src/main/java/net/minecraft/core/entity/Mob.java
index 2d5bf8b3e..c4de84b39 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Mob.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Mob.java
@@ -715,7 +715,9 @@ public abstract class Mob extends Entity
         int i = (int) java.lang.Math.ceil(distance - 3F);
         if(i > 0)
         {
-            hurt(null, i, DamageType.FALL);
+            if (vehicle == null) {
+                hurt(null, i, DamageType.FALL);
+            }
             int j = world.getBlockId(MathHelper.floor(x), MathHelper.floor(y - 0.2D - (double) heightOffset), MathHelper.floor(z));
             if(j > 0)
             {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java
index a4d546a7a..93292301d 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java
@@ -104,6 +104,11 @@ public class MobPig
         }
     }
 
+    @Override
+    protected boolean canDespawn() {
+        return super.canDespawn() && !getSaddled();
+    }
+
     @Override
 	protected void dropDeathItems()
     {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
index 1ee88b1c0..2a0280a1b 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -80,6 +80,7 @@ public abstract class Player
     public static final int DATA_HELD_ARROW = 18;
     public static final TextFormatting deathMsgColor = TextFormatting.RED;
     public ContainerInventory inventory;
+    public final @Nullable ItemStack @NotNull [] oldArmorInventory = new ItemStack[4]; // Last tick's armor inventory, used for playing equip sounds at the right time.
     public MenuAbstract inventorySlots;
     public MenuAbstract craftingInventory;
     public Gamemode gamemode = Gamemode.survival;
@@ -261,6 +262,19 @@ public abstract class Player
         ydO = yd;
         zdO = zd;
 
+        boolean playEquipSound = false;
+        for (int i = 0; i < oldArmorInventory.length; i++) {
+            ItemStack armorOld = oldArmorInventory[i];
+            ItemStack armorCurrent = inventory.armorInventory[i];
+            if (armorOld != armorCurrent && (armorOld == null || armorCurrent == null || armorOld.itemID != armorCurrent.itemID)) {
+                playEquipSound = true;
+            }
+            oldArmorInventory[i] = armorCurrent;
+        }
+        if (playEquipSound) {
+            world.playSoundAtEntity(this, this, "random.equip", 2f, 1f);
+        }
+
         final boolean wSneak = wantSneak();
 
         if (wSneak || this.noPhysics) {
@@ -804,6 +818,11 @@ public abstract class Player
         nickname = nickname.replace(" ", "");
         ListTag nbttaglist = tag.getList("Inventory");
         inventory.readFromNBT(nbttaglist);
+
+        for (int i = 0; i < oldArmorInventory.length; i++) {
+            oldArmorInventory[i] = inventory.armorInventory[i];
+        }
+
         inventory.setCurrentItemIndex(tag.getIntegerOrDefault("CurrentItem", inventory.getCurrentItemIndex()), true);
         inventory.setHotbarOffset(tag.getIntegerOrDefault("HotbarOffset", inventory.getHotbarOffset()), true);
         int dim = tag.getInteger("Dimension");
diff --git a/game/core/src/main/java/net/minecraft/core/item/Item.java b/game/core/src/main/java/net/minecraft/core/item/Item.java
index 09b73dc9a..695cd14de 100644
--- a/game/core/src/main/java/net/minecraft/core/item/Item.java
+++ b/game/core/src/main/java/net/minecraft/core/item/Item.java
@@ -172,7 +172,7 @@ public class Item implements ITaggable<Item>, IItemConvertible
         return 1.0F;
     }
 
-    public ItemStack onUseItem(final ItemStack itemstack, final World world, final Player entityplayer)
+    public @Nullable ItemStack onUseItem(final @NotNull ItemStack itemstack, final @NotNull World world, final @NotNull Player entityplayer)
     {
         return itemstack;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemArmor.java b/game/core/src/main/java/net/minecraft/core/item/ItemArmor.java
index fca353a28..ce2682ecf 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemArmor.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemArmor.java
@@ -1,8 +1,12 @@
 package net.minecraft.core.item;
 
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.enums.IArmorShape;
 import net.minecraft.core.item.material.ArmorMaterial;
+import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemArmor<T extends IArmorShape>
 	extends Item
@@ -20,6 +24,17 @@ public class ItemArmor<T extends IArmorShape>
 		this.maxStackSize = 1;
 	}
 
+	@Override
+	public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer) {
+        if (!(armorShape instanceof HumanArmorShape)) {
+			return itemstack;
+        }
+		HumanArmorShape humanArmorShape = (HumanArmorShape) armorShape;
+		ItemStack currentArmorInSlot = entityplayer.getItemInArmorSlot(humanArmorShape);
+		entityplayer.setItemInArmorSlot(humanArmorShape, itemstack);
+		return currentArmorInSlot;
+	}
+
 	@Override
 	public ArmorMaterial getArmorMaterial() {
 		return this.material;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java b/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java
index 76896042d..96621c3d9 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java
@@ -9,6 +9,8 @@ import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
@@ -22,7 +24,7 @@ public class ItemBoat extends Item
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         float f = 1.0F;
         float f1 = entityplayer.xRotO + (entityplayer.xRot - entityplayer.xRotO) * f;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBow.java b/game/core/src/main/java/net/minecraft/core/item/ItemBow.java
index 753c3c630..f5b0dd600 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBow.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBow.java
@@ -7,6 +7,8 @@ import net.minecraft.core.entity.projectile.ProjectileArrowPurple;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemBow extends Item
 {
@@ -19,7 +21,7 @@ public class ItemBow extends Item
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         ItemStack quiverSlot = entityplayer.getItemInArmorSlot(HumanArmorShape.CHEST);
         if(quiverSlot != null && quiverSlot.itemID == Items.ARMOR_QUIVER.id && quiverSlot.getMetadata() < quiverSlot.getMaxDamage()){
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
index 0214ee54f..e1725df22 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java
@@ -11,6 +11,7 @@ import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
@@ -26,7 +27,7 @@ public class ItemBucket extends Item
     }
 
     @Override
-	public ItemStack onUseItem(ItemStack stack, World world, Player player) {
+	public @Nullable ItemStack onUseItem(@NotNull ItemStack stack, @NotNull World world, @NotNull Player player) {
 		if(blockToPlace == null) {
 			// Milk
 			return new ItemStack(Items.BUCKET);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java
index 73fa99245..e31ac5755 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java
@@ -8,6 +8,8 @@ import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
 import java.util.Random;
@@ -22,7 +24,7 @@ public class ItemBucketEmpty extends Item
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         double reachDistance = entityplayer.getGamemode().getBlockReachDistance();
         HitResult hitResult = entityplayer.rayTrace(reachDistance, 1f, true, false, false);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucketIceCream.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucketIceCream.java
index c4bfbf4a7..1e0627fcf 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBucketIceCream.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucketIceCream.java
@@ -2,6 +2,8 @@ package net.minecraft.core.item;
 
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemBucketIceCream extends ItemFood {
 
@@ -11,7 +13,7 @@ public class ItemBucketIceCream extends ItemFood {
         maxStackSize = 1;
     }
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         if (entityplayer.getHealth() < entityplayer.getMaxHealth()){
             super.onUseItem(itemstack, world, entityplayer);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemEgg.java b/game/core/src/main/java/net/minecraft/core/item/ItemEgg.java
index 93de7e207..878b8b6c2 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemEgg.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemEgg.java
@@ -5,6 +5,8 @@ import net.minecraft.core.entity.projectile.ProjectileEgg;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
@@ -19,7 +21,7 @@ public class ItemEgg
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         itemstack.consumeItem(entityplayer);
         world.playSoundAtEntity(entityplayer, entityplayer, "random.bow", 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemFishingRod.java b/game/core/src/main/java/net/minecraft/core/item/ItemFishingRod.java
index edf198122..614993d29 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemFishingRod.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemFishingRod.java
@@ -3,6 +3,8 @@ package net.minecraft.core.item;
 import net.minecraft.core.entity.EntityFishingBobber;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemFishingRod extends Item
 {
@@ -15,7 +17,7 @@ public class ItemFishingRod extends Item
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         if(entityplayer.bobberEntity != null)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemFood.java b/game/core/src/main/java/net/minecraft/core/item/ItemFood.java
index 7c655c4d7..2cbb2ab18 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemFood.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemFood.java
@@ -2,6 +2,8 @@ package net.minecraft.core.item;
 
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemFood extends Item
 {
@@ -20,7 +22,7 @@ public class ItemFood extends Item
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         if(entityplayer.getHealth() < entityplayer.getMaxHealth()
                 && entityplayer.getHealth() + entityplayer.getTotalHealingRemaining() < entityplayer.getMaxHealth()
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemHandCannonLoaded.java b/game/core/src/main/java/net/minecraft/core/item/ItemHandCannonLoaded.java
index 9b436007b..03e4405c8 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemHandCannonLoaded.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemHandCannonLoaded.java
@@ -3,6 +3,8 @@ package net.minecraft.core.item;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.projectile.ProjectileCannonball;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemHandCannonLoaded extends Item
 {
@@ -15,7 +17,7 @@ public class ItemHandCannonLoaded extends Item
     }
 
 	@Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
 		world.playSoundAtEntity(entityplayer, entityplayer, "random.bow", 0.3F, 1.0F / (itemRand.nextFloat() * -0.2F - 0.4F));
 
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemHandCannonUnloaded.java b/game/core/src/main/java/net/minecraft/core/item/ItemHandCannonUnloaded.java
index 8c6201eee..64c7464f3 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemHandCannonUnloaded.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemHandCannonUnloaded.java
@@ -2,6 +2,8 @@ package net.minecraft.core.item;
 
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemHandCannonUnloaded extends Item
 {
@@ -14,7 +16,7 @@ public class ItemHandCannonUnloaded extends Item
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         if (entityplayer.inventory.consumeInventoryItem(Items.AMMO_CHARGE_EXPLOSIVE.id))
         {
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemIceSkates.java b/game/core/src/main/java/net/minecraft/core/item/ItemIceSkates.java
index 7399d2bd2..da2847fc9 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemIceSkates.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemIceSkates.java
@@ -1,8 +1,10 @@
 package net.minecraft.core.item;
 
+import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.enums.IArmorShape;
 import net.minecraft.core.item.material.ArmorMaterial;
+import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -12,6 +14,14 @@ public class ItemIceSkates extends Item implements IArmorItem<HumanArmorShape> {
         setMaxStackSize(1);
     }
 
+    @Override
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer) {
+        HumanArmorShape humanArmorShape = getArmorShape();
+        ItemStack currentArmorInSlot = entityplayer.getItemInArmorSlot(humanArmorShape);
+        entityplayer.setItemInArmorSlot(humanArmorShape, itemstack);
+        return currentArmorInSlot;
+    }
+
     @Override
     public @Nullable ArmorMaterial getArmorMaterial() {
         return null;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemJar.java b/game/core/src/main/java/net/minecraft/core/item/ItemJar.java
index 8ab94936b..47204fcc3 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemJar.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemJar.java
@@ -37,7 +37,7 @@ public class ItemJar extends ItemPlaceable {
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, @NotNull Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         if (entityplayer.isSneaking()) {
             return itemstack;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemLabel.java b/game/core/src/main/java/net/minecraft/core/item/ItemLabel.java
index 2150ca357..937f09563 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemLabel.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemLabel.java
@@ -8,6 +8,8 @@ import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
 import java.util.Random;
@@ -20,7 +22,7 @@ public class ItemLabel extends Item
     }
 
 	@Override
-	public ItemStack onUseItem(final ItemStack stack, final World world, final Player player) {
+	public @Nullable ItemStack onUseItem(final @NotNull ItemStack stack, final @NotNull World world, final @NotNull Player player) {
 		if(stack.hasCustomName()) {
 			return stack;
 		}
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemMap.java b/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
index 0a31d74d1..45f9b5fa1 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
@@ -21,9 +21,6 @@ import net.minecraft.core.world.saveddata.maps.ItemMapSavedData;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.HashMap;
-import java.util.Map;
-
 
 public class ItemMap extends Item implements IComplexItem
 {
@@ -114,7 +111,7 @@ public class ItemMap extends Item implements IComplexItem
         return mapData;
     }
 	@Override
-	public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+	public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
 	{
 		if (!hasInitialized(itemstack)){
 			initMap(itemstack, world, entityplayer);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java b/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java
index 44edd94dc..deefb625a 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java
@@ -78,7 +78,7 @@ public class ItemPaintBrush extends Item {
             if (!entities.isEmpty()) {
                 MobSheep sheep = entities.get(0);
                 DyeColor woolColor = getColor(itemStack);
-                if(sheep.getFleeceColor() != woolColor)
+                if(woolColor != null && sheep.getFleeceColor() != woolColor)
                 {
                     sheep.setFleeceColor(woolColor);
                     consumePaint(itemStack, null);
@@ -103,7 +103,7 @@ public class ItemPaintBrush extends Item {
         {
             MobSheep mobSheep = (MobSheep)mob;
             DyeColor woolColor = getColor(itemstack);
-            if(mobSheep.getFleeceColor() != woolColor)
+            if(woolColor != null && mobSheep.getFleeceColor() != woolColor)
             {
                 mobSheep.setFleeceColor(woolColor);
                 consumePaint(itemstack, player);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPainting.java b/game/core/src/main/java/net/minecraft/core/item/ItemPainting.java
index 00fb3dfd2..bf0c11862 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemPainting.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemPainting.java
@@ -18,7 +18,7 @@ public class ItemPainting extends Item
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         if (!world.isClientSide && !entityplayer.isSneaking())
         {
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPebble.java b/game/core/src/main/java/net/minecraft/core/item/ItemPebble.java
index 1e4939b8b..0f64b3981 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemPebble.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemPebble.java
@@ -27,7 +27,7 @@ public class ItemPebble extends Item implements IDispensable
 
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         itemstack.consumeItem(entityplayer);
         world.playSoundAtEntity(entityplayer, entityplayer, "random.bow", 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemQuiver.java b/game/core/src/main/java/net/minecraft/core/item/ItemQuiver.java
index 9044fab12..07b5f30e1 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemQuiver.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemQuiver.java
@@ -5,6 +5,7 @@ import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.enums.IArmorShape;
 import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.player.inventory.slot.Slot;
+import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -83,6 +84,14 @@ public class ItemQuiver extends Item implements IArmorItem<HumanArmorShape>
     	
     	return stackInSlot;
     }
+
+	@Override
+	public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer) {
+		HumanArmorShape humanArmorShape = getArmorShape();
+		ItemStack currentArmorInSlot = entityplayer.getItemInArmorSlot(humanArmorShape);
+		entityplayer.setItemInArmorSlot(humanArmorShape, itemstack);
+		return currentArmorInSlot;
+	}
     
     private int getArrowCount(ItemStack stack) {
     	return stack.getMaxDamage() - stack.getMetadata();
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemQuiverEndless.java b/game/core/src/main/java/net/minecraft/core/item/ItemQuiverEndless.java
index 2d066f5cd..0c8f61831 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemQuiverEndless.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemQuiverEndless.java
@@ -1,8 +1,11 @@
 package net.minecraft.core.item;
 
+import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.item.material.ArmorMaterial;
+import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemQuiverEndless extends Item implements IArmorItem<HumanArmorShape>
 {
@@ -13,6 +16,14 @@ public class ItemQuiverEndless extends Item implements IArmorItem<HumanArmorShap
         setMaxStackSize(1);
     }
 
+    @Override
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer) {
+        HumanArmorShape humanArmorShape = getArmorShape();
+        ItemStack currentArmorInSlot = entityplayer.getItemInArmorSlot(humanArmorShape);
+        entityplayer.setItemInArmorSlot(humanArmorShape, itemstack);
+        return currentArmorInSlot;
+    }
+
     @Override
     public ArmorMaterial getArmorMaterial() {
         return null;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSnowball.java b/game/core/src/main/java/net/minecraft/core/item/ItemSnowball.java
index b689064ad..600c5a39c 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemSnowball.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemSnowball.java
@@ -5,6 +5,8 @@ import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.projectile.ProjectileSnowball;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
@@ -18,7 +20,7 @@ public class ItemSnowball extends Item implements IDispensable
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         itemstack.consumeItem(entityplayer);
         world.playSoundAtEntity(entityplayer, entityplayer, "random.bow", 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSoup.java b/game/core/src/main/java/net/minecraft/core/item/ItemSoup.java
index f15fda846..5025c43d1 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemSoup.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemSoup.java
@@ -2,6 +2,8 @@ package net.minecraft.core.item;
 
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ItemSoup extends ItemFood
 {
@@ -12,7 +14,7 @@ public class ItemSoup extends ItemFood
     }
 
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player entityplayer)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player entityplayer)
     {
         ItemStack stack = super.onUseItem(itemstack, world, entityplayer);
         return stack.stackSize <= 0 ? Items.BOWL.getDefaultStack() : stack;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemStack.java b/game/core/src/main/java/net/minecraft/core/item/ItemStack.java
index 63237381b..8baed9b49 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemStack.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemStack.java
@@ -375,9 +375,9 @@ public final class ItemStack {
         return metadata == itemstack.metadata;
     }
 
-    public boolean isItemEqual(@NotNull ItemStack itemstack)
+    public boolean isItemEqual(@Nullable ItemStack itemstack)
     {
-        return itemID == itemstack.itemID && metadata == itemstack.metadata;
+        return itemstack != null && itemID == itemstack.itemID && metadata == itemstack.metadata;
     }
 
     public String getItemKey()
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java b/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java
index fb1e30cdd..18a402a33 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java
@@ -9,6 +9,8 @@ import net.minecraft.core.entity.EntityDispatcher;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
@@ -18,7 +20,7 @@ public class ItemWandSpawner extends Item implements IDispensable
         super(name, namespaceId, id);
     }
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player player)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player player)
     {
         if (player.gamemode != Gamemode.creative){
             player.sendTranslatedChatMessage("wand.wrongmode");
diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockAlgae.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockAlgae.java
index 29b1454ae..484abe474 100644
--- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockAlgae.java
+++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockAlgae.java
@@ -34,7 +34,7 @@ public class ItemBlockAlgae<T extends BlockLogic> extends ItemBlock<T>
     }
     
     @Override
-    public ItemStack onUseItem(ItemStack itemstack, World world, Player player)
+    public @Nullable ItemStack onUseItem(@NotNull ItemStack itemstack, @NotNull World world, @NotNull Player player)
     {
         double reachDistance = player.getGamemode().getBlockReachDistance();
         HitResult rayTraceResult = player.rayTrace(reachDistance, 1f, true, false, false);
diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/container/ContainerInventory.java b/game/core/src/main/java/net/minecraft/core/player/inventory/container/ContainerInventory.java
index f1c473276..8d7a35bcc 100644
--- a/game/core/src/main/java/net/minecraft/core/player/inventory/container/ContainerInventory.java
+++ b/game/core/src/main/java/net/minecraft/core/player/inventory/container/ContainerInventory.java
@@ -17,14 +17,15 @@ import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.item.tag.ItemTags;
 import net.minecraft.core.player.inventory.InventorySorter;
 import net.minecraft.core.util.helper.DamageType;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class ContainerInventory
     implements Container
 {
     protected int hotbarOffset = 0;
-    public ItemStack[] mainInventory;
-    public ItemStack[] armorInventory;
+    public @Nullable ItemStack @NotNull [] mainInventory;
+    public @Nullable ItemStack @NotNull [] armorInventory;
     protected int currentItem;
     public Player player;
     private ItemStack heldItem;
@@ -398,7 +399,7 @@ public class ContainerInventory
         }
     }
 
-    public ItemStack armorItemInSlot(IArmorShape shape)
+    public @Nullable ItemStack armorItemInSlot(@NotNull IArmorShape shape)
     {
         return armorInventory[shape.getSlotIndex()];
     }
diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/slot/SlotArmor.java b/game/core/src/main/java/net/minecraft/core/player/inventory/slot/SlotArmor.java
index f0562c8fd..3c1333e38 100644
--- a/game/core/src/main/java/net/minecraft/core/player/inventory/slot/SlotArmor.java
+++ b/game/core/src/main/java/net/minecraft/core/player/inventory/slot/SlotArmor.java
@@ -85,11 +85,6 @@ public class SlotArmor extends Slot
         if (wornMaterials.size() >= 4) {
             menu.inventory.player.triggerAchievement(Achievements.ALL_ARMOR_TYPES);
         }
-        
-        if (getItemStack() != null && container instanceof ContainerInventory) {
-            Player player = ((ContainerInventory) container).player;
-            player.world.playSoundAtEntity(player, player, "random.equip", 2f, 1f);
-        }
     }
 
     public void set(final @Nullable ItemStack itemstack)
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
index f0228bf0d..7195f0743 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
@@ -229,7 +229,7 @@ public class ChunkDecoratorOverworld
             int j7 = x + rand.nextInt(16);
             int k10 = minY + rand.nextInt(rangeY / 2);
             int j13 = z + rand.nextInt(16);
-            (new WorldFeatureOre(BlockLogicMoss.variantMap, 32)).place(world, rand, j7, k10, j13);
+            (new WorldFeatureMoss(BlockLogicMoss.variantMap, 32)).place(world, rand, j7, k10, j13);
         }
 
         for (int j4 = 0; j4 < oreHeightModifier; j4++) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMoss.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMoss.java
new file mode 100644
index 000000000..5169d0125
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMoss.java
@@ -0,0 +1,111 @@
+package net.minecraft.core.world.generate.feature;
+
+import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
+import net.minecraft.core.block.Blocks;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public class WorldFeatureMoss extends WorldFeature
+{
+    private int minableBlockId;
+    private int numberOfBlocks;
+    private final Int2IntArrayMap variantMap;
+    @MethodParametersAnnotation(names = {"blockId", "numberOfBlocks"})
+    public WorldFeatureMoss(int blockId, int numberOfBlocks)
+    {
+        minableBlockId = blockId;
+        this.numberOfBlocks = numberOfBlocks;
+        this.variantMap = null;
+    }
+    @MethodParametersAnnotation(names = {"blockId", "numberOfBlocks", "variantMap"})
+    public WorldFeatureMoss(@NotNull Int2IntArrayMap variantMap, int numberOfBlocks)
+    {
+        this.numberOfBlocks = numberOfBlocks;
+        this.variantMap = variantMap;
+    }
+
+    @Override
+	public boolean place(World world, Random random, int xStart, int yStart, int zStart)
+    {
+        float f = random.nextFloat() * MathHelper.PI;
+        double xMax = (float)(xStart + 8) + MathHelper.sin(f) * (float)numberOfBlocks / 8F;
+        double xMin = (float)(xStart + 8) - MathHelper.sin(f) * (float)numberOfBlocks / 8F;
+        double zMax = (float)(zStart + 8) + MathHelper.cos(f) * (float)numberOfBlocks / 8F;
+        double zMin = (float)(zStart + 8) - MathHelper.cos(f) * (float)numberOfBlocks / 8F;
+        double yMax = yStart + random.nextInt(3) + 2;
+        double yMin = yStart - random.nextInt(3) + 2;
+        for(int l = 0; l <= numberOfBlocks; l++)
+        {
+            double d6 = xMax + (xMin - xMax) * (double)l / (double)numberOfBlocks;
+            double d7 = yMax + (yMin - yMax) * (double)l / (double)numberOfBlocks;
+            double d8 = zMax + (zMin - zMax) * (double)l / (double)numberOfBlocks;
+            double d9 = random.nextDouble() * (double)numberOfBlocks / 16D;
+            double d10 = (double)(MathHelper.sin((float)l * MathHelper.PI / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
+            double d11 = (double)(MathHelper.sin((float)l * MathHelper.PI / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
+            int xVeinStart = MathHelper.floor(d6 - d10 / 2D);
+            int yVeinStart = MathHelper.floor(d7 - d11 / 2D);
+            int zVeinStart = MathHelper.floor(d8 - d10 / 2D);
+            int xVeinEnd = MathHelper.floor(d6 + d10 / 2D);
+            int yVeinEnd = MathHelper.floor(d7 + d11 / 2D);
+            int zVeinEnd = MathHelper.floor(d8 + d10 / 2D);
+            for(int x = xVeinStart; x <= xVeinEnd; x++)
+            {
+                double d12 = (((double)x + 0.5D) - d6) / (d10 / 2D);
+                if(d12 * d12 >= 1.0D)
+                {
+                    continue;
+                }
+                for(int y = yVeinStart; y <= yVeinEnd; y++)
+                {
+                    double d13 = (((double)y + 0.5D) - d7) / (d11 / 2D);
+                    if(d12 * d12 + d13 * d13 >= 1.0D)
+                    {
+                        continue;
+                    }
+                    for(int z = zVeinStart; z <= zVeinEnd; z++)
+                    {
+                        double d14 = (((double)z + 0.5D) - d8) / (d10 / 2D);
+                        if(d12 * d12 + d13 * d13 + d14 * d14 < 1.0D && airExposed(world, x, y, z))
+                        {
+                        	if (variantMap != null)
+                        	{
+                                int blockId = world.getBlockId(x, y, z);
+                                if (blockId <= 0) continue;
+                                if (variantMap.containsKey(blockId)){
+                                    world.setBlock(x, y, z, variantMap.get(blockId));
+                                }
+                        	}
+                        	else
+                        	{
+                        		int id = world.getBlockId(x, y, z);
+                        		if (id == Blocks.STONE.id() || id == Blocks.COBBLE_NETHERRACK.id() ||
+                        				id == Blocks.BASALT.id() || id == Blocks.LIMESTONE.id() ||
+                        				id == Blocks.GRANITE.id())
+                        		{
+                        			world.setBlock(x, y, z, minableBlockId);
+                        		}
+                        	}
+                        }
+                    }
+
+                }
+
+            }
+
+        }
+
+        return true;
+    }
+
+    public boolean airExposed(@NotNull World world, int x, int y, int z) {
+        for (int i = 0; i < Side.sides.length; i++) {
+            Side s = Side.sides[i];
+            if (world.isAirBlock(x + s.getOffsetX(), y + s.getOffsetY(), z + s.getOffsetZ())) return true;
+        }
+        return false;
+    }
+}
diff --git a/game/core/src/main/resources/assets/minecraft/sounds/sounds.json b/game/core/src/main/resources/assets/minecraft/sounds/sounds.json
index c54fdb2cf..b7443c846 100644
--- a/game/core/src/main/resources/assets/minecraft/sounds/sounds.json
+++ b/game/core/src/main/resources/assets/minecraft/sounds/sounds.json
@@ -952,10 +952,14 @@
     "sounds": [
       {
         "name": "music/nuance1.ogg",
+        "title": "Key",
+        "author": "C418",
         "stream": true
       },
       {
         "name": "music/nuance2.ogg",
+        "title": "Oxygene",
+        "author": "C418",
         "stream": true
       }
     ]
@@ -964,18 +968,26 @@
     "sounds": [
       {
         "name": "music/hal1.ogg",
+        "title": "Subwoofer Lullaby",
+        "author": "C418",
         "stream": true
       },
       {
         "name": "music/hal2.ogg",
+        "title": "Living Mice",
+        "author": "C418",
         "stream": true
       },
       {
         "name": "music/hal3.ogg",
+        "title": "Haggstrom",
+        "author": "C418",
         "stream": true
       },
       {
         "name": "music/hal4.ogg",
+        "title": "Danny",
+        "author": "C418",
         "stream": true
       }
     ]
@@ -984,14 +996,20 @@
     "sounds": [
       {
         "name": "music/piano1.ogg",
+        "title": "Dry Hands",
+        "author": "C418",
         "stream": true
       },
       {
         "name": "music/piano2.ogg",
+        "title": "Wet Hands",
+        "author": "C418",
         "stream": true
       },
       {
         "name": "music/piano3.ogg",
+        "title": "Mice on Venus",
+        "author": "C418",
         "stream": true
       }
     ]
@@ -1000,14 +1018,20 @@
     "sounds": [
       {
         "name": "music/calm1.ogg",
+        "title": "Minecraft",
+        "author": "C418",
         "stream": true
       },
       {
         "name": "music/calm2.ogg",
+        "title": "Clark",
+        "author": "C418",
         "stream": true
       },
       {
         "name": "music/calm3.ogg",
+        "title": "Sweden",
+        "author": "C418",
         "stream": true
       }
     ]
diff --git a/game/core/src/main/resources/lang/en_US/options.lang b/game/core/src/main/resources/lang/en_US/options.lang
index fcc26648c..4cac9c938 100644
--- a/game/core/src/main/resources/lang/en_US/options.lang
+++ b/game/core/src/main/resources/lang/en_US/options.lang
@@ -186,6 +186,13 @@ options.dynamicCursor=Dynamic Cursor
 options.enableDevResourceLoading=Developer Resource Loading
 options.enableMultiDrawRendering=Enable Multi-Draw Renderer (experimental!)
 options.doJCECheck=Do JCE Check
+options.musicToasts=Music Toasts
+options.musicFrequency=Music Frequency
+options.musicFrequency.continuous=Continuous
+options.musicFrequency.frequent=Frequent
+options.musicFrequency.default=Default
+options.musicFrequency.unusual=Unusual
+options.musicFrequency.rare=Rare
 
 options.fov.modification=Contextual FOV Modification
 options.screen.motion.effects=Screen Motion Effects
