diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentOxygenBar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentOxygenBar.java
index e572bb875..652119648 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentOxygenBar.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentOxygenBar.java
@@ -55,7 +55,7 @@ public class HudComponentOxygenBar extends HudComponentMovable {
         }
         return GameSettings.IMMERSIVE_MODE.drawHotbar() &&
                 !mc.thePlayer.getGamemode().hasInvulnerablePlayer() &&
-                mc.thePlayer.isUnderLiquid(Materials.WATER) &&
+                mc.thePlayer.isUnderAcidOrWater() &&
                 !GameSettings.HIDE_OXYGEN_BAR.value;
     }
 
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 a7ea30810..5f66dfc27 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
@@ -1,6 +1,7 @@
 package net.minecraft.client.render;
 
 import com.mojang.logging.LogUtils;
+import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.option.enums.ParticlesQuality;
 import net.minecraft.client.render.culling.CameraFrustum;
 import net.minecraft.client.render.renderer.BlendFactor;
@@ -218,6 +219,9 @@ public class WorldRenderer {
             MathHelper.floor(this.mc.thePlayer.y - this.mc.thePlayer.heightOffset - 0.25),
             MathHelper.floor(this.mc.thePlayer.z)
         );
+        if (!this.mc.currentWorld.isAirBlock(this.mc.bridgePos)) {
+            this.mc.bridgePos.add(HudIngame.getFacingDirection(this.mc.thePlayer));
+        }
 
         if (!placeable.canPlaceDirectlyAtPosition(
             item, this.mc.currentWorld, this.mc.thePlayer, this.mc.bridgePos, Side.TOP, 
@@ -715,7 +719,7 @@ public class WorldRenderer {
             renderGlobal.drawTileSelectionBox(this.mc.activeCamera, this.mc.bridgePos, partialTicks);
         }
 
-        Debug.change("debugoverlays");
+        Debug.change("debugoverlays"); // Outline first pass (Will draw under water if applicable)
         if (GameSettings.SHOW_COLLISION_BOXES.value) {
             renderGlobal.drawDebugEntityOutlines(this.mc.activeCamera, partialTicks);
         }
@@ -742,6 +746,15 @@ public class WorldRenderer {
         this.lightmapHelper.disableLightmapRendering();
         Lighting.disable();
 
+        Debug.change("outline"); // Outline second pass (Will draw over water if applicable)
+        if (this.mc.objectMouseOver != null) {
+//            glDisable(GL_ALPHA_TEST);
+            renderGlobal.drawSelectionBox(this.mc.activeCamera, this.mc.objectMouseOver, partialTicks);
+//            glEnable(GL_ALPHA_TEST);
+        } else if (this.mc.canBridge) {
+            renderGlobal.drawTileSelectionBox(this.mc.activeCamera, this.mc.bridgePos, partialTicks);
+        }
+
         Debug.change("weather");
         GLRenderer.setDepthMask(true);
         GLRenderer.enableState(State.CULL_FACE);
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java
index 824facdb1..24a8d2b50 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java
@@ -52,28 +52,44 @@ public class EntityRendererArrow extends EntityRenderer<ProjectileArrow> {
 
         // Draw arrow tail
         tessellator.startDrawingQuads();
+        tessellator.setNormal(0, 1, 0);
+//        tessellator.setNormal(-1, 0, 0);
         tessellator.addVertexWithUV(-7D, -2D, -2D, tailMinU, tailMinV);
         tessellator.addVertexWithUV(-7D, -2D, 2D, tailMaxU, tailMinV);
         tessellator.addVertexWithUV(-7D, 2D, 2D, tailMaxU, tailMaxV);
         tessellator.addVertexWithUV(-7D, 2D, -2D, tailMinU, tailMaxV);
-        tessellator.draw();
-        tessellator.startDrawingQuads();
+
+//        tessellator.setNormal(1, 0, 0);
         tessellator.addVertexWithUV(-7D, 2D, -2D, tailMinU, tailMinV);
         tessellator.addVertexWithUV(-7D, 2D, 2D, tailMaxU, tailMinV);
         tessellator.addVertexWithUV(-7D, -2D, 2D, tailMaxU, tailMaxV);
         tessellator.addVertexWithUV(-7D, -2D, -2D, tailMinU, tailMaxV);
-        tessellator.draw();
 
         // Draw arrow body
-        for (int i = 0; i < 4; i++) {
-            GLRenderer.modelM4f().rotateX(Math.PI_OVER_2_f);
-            tessellator.startDrawingQuads();
-            tessellator.addVertexWithUV(-8D, -2D, 0.0D, bodyMinU, bodyMinV);
-            tessellator.addVertexWithUV(8D, -2D, 0.0D, bodyMaxU, bodyMinV);
-            tessellator.addVertexWithUV(8D, 2D, 0.0D, bodyMaxU, bodyMaxV);
-            tessellator.addVertexWithUV(-8D, 2D, 0.0D, bodyMinU, bodyMaxV);
-            tessellator.draw();
-        }
+//        tessellator.setNormal(0, 0, -1); // North
+        tessellator.addVertexWithUV(-8D, -2D, 0.0D, bodyMinU, bodyMinV);
+        tessellator.addVertexWithUV(-8D, 2D, 0.0D, bodyMinU, bodyMaxV);
+        tessellator.addVertexWithUV(8D, 2D, 0.0D, bodyMaxU, bodyMaxV);
+        tessellator.addVertexWithUV(8D, -2D, 0.0D, bodyMaxU, bodyMinV);
+
+//        tessellator.setNormal(0, 0, 1); // South
+        tessellator.addVertexWithUV(-8D, -2D, 0.0D, bodyMinU, bodyMinV);
+        tessellator.addVertexWithUV(8D, -2D, 0.0D, bodyMaxU, bodyMinV);
+        tessellator.addVertexWithUV(8D, 2D, 0.0D, bodyMaxU, bodyMaxV);
+        tessellator.addVertexWithUV(-8D, 2D, 0.0D, bodyMinU, bodyMaxV);
+
+//        tessellator.setNormal(0, 1, 0); // Up
+        tessellator.addVertexWithUV(-8D, 0.0D, -2D, bodyMinU, bodyMinV);
+        tessellator.addVertexWithUV(-8D, 0.0D, 2D, bodyMinU, bodyMaxV);
+        tessellator.addVertexWithUV(8D, 0.0D, 2D, bodyMaxU, bodyMaxV);
+        tessellator.addVertexWithUV(8D, 0.0D, -2D, bodyMaxU, bodyMinV);
+
+//        tessellator.setNormal(0, -1, 0); // Down
+        tessellator.addVertexWithUV(-8D, 0.0D, -2D, bodyMinU, bodyMinV);
+        tessellator.addVertexWithUV(8D, 0.0D, -2D, bodyMaxU, bodyMinV);
+        tessellator.addVertexWithUV(8D, 0.0D, 2D, bodyMaxU, bodyMaxV);
+        tessellator.addVertexWithUV(-8D, 0.0D, 2D, bodyMinU, bodyMaxV);
+        tessellator.draw();
 
         GLRenderer.popFrame();
     }
diff --git a/game/client/src/main/java/net/minecraft/client/util/helper/ItemDragHandler.java b/game/client/src/main/java/net/minecraft/client/util/helper/ItemDragHandler.java
index ccfd71fe4..e28df35d0 100644
--- a/game/client/src/main/java/net/minecraft/client/util/helper/ItemDragHandler.java
+++ b/game/client/src/main/java/net/minecraft/client/util/helper/ItemDragHandler.java
@@ -71,7 +71,7 @@ public class ItemDragHandler extends Gui {
 			if (this.dragOverBuffer.size() == 0) this.onDragOutsideOfSlots();
 			else for (final var slot : this.dragOverBuffer) onDragOverSlot(slot);
 
-			if (this.draggedSlots.size() == 0) return;
+			if (this.draggedSlots.size() <= 1) return;
 
 			this.renderItemStack = this.draggingItemStack.copy();
 			this.renderItemStack.stackSize = 1;
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/template_lantern_hanging.json b/game/client/src/main/resources/assets/minecraft/models/block/template_lantern_hanging.json
index e1020271e..684aeadfa 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/template_lantern_hanging.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/template_lantern_hanging.json
@@ -23,7 +23,7 @@
 				"south": {"uv": [0, 6, 6, 14], "texture": "#all"},
 				"west": {"uv": [0, 6, 6, 14], "texture": "#all"},
 				"up": {"uv": [0, 0, 6, 6], "texture": "#all"},
-				"down": {"uv": [6, 0, 12, 6], "texture": "#all", "cullface": "down"}
+				"down": {"uv": [6, 0, 12, 6], "texture": "#all"}
 			}
 		},
 		{
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 ef904d406..c37a5bb63 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
@@ -12,6 +12,7 @@ import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.material.Materials;
 import net.minecraft.core.block.piston.BlockLogicPistonHead;
 import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.entity.animal.MobPig;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.vehicle.EntityBoat;
@@ -26,7 +27,6 @@ import net.minecraft.core.world.IVehicle;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.data.SynchedEntityData;
 import net.minecraft.core.world.pos.TilePos;
-import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.type.tag.WorldTypeTags;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -132,6 +132,16 @@ public abstract class Entity
     protected boolean fireImmune;
     public Block<?> activeFireBlock = Blocks.FIRE;
 
+    // Acid
+    public static final int ACID_CYCLE_MAX = 10;
+    public static final int ACID_POST_EXIT_DRAIN_TICKS = 20;
+    public static final int ACID_EXIT_BUFFER = 2;
+
+    public int acidMeltTicks;
+    public int acidExitDelayLeft;
+    public int acidPostExitDrainTicksLeft;
+    public int acidPostExitPeak;
+
     // Visual
     public float entityBrightness = 0.0F;
     public boolean ignoreFrustumCheck;
@@ -327,6 +337,7 @@ public abstract class Entity
         if (isInWater()) {
             waterHurt();
         }
+        acidTick();
 
         if (this.y < -64D) {
             outOfWorld();
@@ -777,6 +788,75 @@ public abstract class Entity
         return this.world.isMaterialInBB(this.bb, Materials.ACID);
     }
 
+    public void acidTick() {
+        final boolean physicallyInAcid = isInAcid();
+        final int meltRate = Math.max(1, this.world.getGameRuleValue(GameRules.ACID_MELT_RATE));
+        final boolean shouldTickRate = (this.tickCount % meltRate == 0);
+
+        if (physicallyInAcid) {
+            this.acidExitDelayLeft = ACID_EXIT_BUFFER;
+            this.acidPostExitDrainTicksLeft = ACID_POST_EXIT_DRAIN_TICKS;
+            this.acidPostExitPeak = 0;
+        }
+
+        final boolean applyAcidMeltAndDamage = physicallyInAcid || this.acidExitDelayLeft > 0;
+
+        if (applyAcidMeltAndDamage) {
+            if (!physicallyInAcid) {
+                this.acidExitDelayLeft--;
+                if (this.acidExitDelayLeft == 0) {
+                    this.acidPostExitPeak = this.acidMeltTicks;
+                }
+            }
+
+            if (shouldTickRate) {
+                this.acidMeltTicks = Math.min(this.acidMeltTicks + 1, ACID_CYCLE_MAX);
+
+                if (!this.world.isClientSide && isAlive()) {
+                    processAcidDamageAndParticles();
+                }
+            }
+        } else if (this.acidMeltTicks > 0) {
+            if (this.acidPostExitDrainTicksLeft > 0) {
+                this.acidPostExitDrainTicksLeft--;
+                if (this.acidPostExitDrainTicksLeft <= 0) {
+                    this.acidMeltTicks = 0;
+                    this.acidPostExitPeak = 0;
+                }
+            }
+        }
+    }
+
+    /** True while physically in acid or during {@link #ACID_EXIT_BUFFER} post-exit melt/damage ticks. */
+    public boolean isEffectiveInAcid() {
+        return isInAcid() || this.acidExitDelayLeft > 0;
+    }
+
+    protected void processAcidDamageAndParticles() {
+        int acidExposureDamage = getAcidExposureArmorSlotCount();
+        if (acidExposureDamage > 0) {
+            hurt(null, acidExposureDamage, DamageType.GENERIC);
+        }
+
+        if (acidExposureDamage > 0) {
+            float fizzPitch = 0.6F + this.random.nextFloat() * 0.25F;
+            float bubblePitch = 0.7F + this.random.nextFloat() * 0.2F;
+            this.world.playSoundAtEntity(null, this, "random.fizz", 0.35F, fizzPitch);
+            this.world.playSoundAtEntity(null, this, "tile.acidbubble", 0.4F, bubblePitch);
+
+            for (int i = 0; i < 6; i++) {
+                double offX = (this.random.nextDouble() - 0.5D) * (double) this.bbWidth;
+                double offY = this.random.nextDouble() * (double) this.bbHeight;
+                double offZ = (this.random.nextDouble() - 0.5D) * (double) this.bbWidth;
+                this.world.spawnParticle("acidBoiling", this.x + offX, this.bb.minY + offY, this.z + offZ, 0.0F, 0.02F, 0.0F, 0, false);
+            }
+        }
+    }
+
+    public int getAcidExposureArmorSlotCount() {
+        return 4; // 4 "Slots" not covered, acid system really just didn't even think about non players
+    }
+
 
     public boolean isBoundingBoxIntersectingBlock(final @NotNull Block<?> target) {
         return isAabbIntersectingBlock(this.bb, target);
@@ -851,6 +931,20 @@ public abstract class Entity
         }
     }
 
+    public boolean isUnderAcidOrWater() {
+        double headY = this.y + (double) getHeadHeight();
+        workingPos1.set(this.x, headY, this.z);
+        Block<?> block = this.world.getBlockType(workingPos1);
+        var material = block.getMaterial();
+        if (material == Materials.WATER || material == Materials.ACID) {
+            float f = BlockLogicFluid.getHeight(this.world.getBlockData(workingPos1)) - 0.2F;
+            float f1 = (float) (workingPos1.y + 1) - f;
+            return headY < (double) f1;
+        } else {
+            return false;
+        }
+    }
+
     public float getHeadHeight() {
         return 0.0F;
     }
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 c426b3f89..8b3ded235 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
@@ -3,8 +3,6 @@ package net.minecraft.core.entity;
 import com.b100.utils.StringUtils;
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.Global;
-import net.minecraft.core.block.material.Materials;
-import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemFood;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.WeightedRandomLootObject;
@@ -336,7 +334,7 @@ public abstract class Mob extends Entity {
     }
 
     public void trySuffocate() {
-        if (isAlive() && isUnderLiquid(Materials.WATER) && !canBreatheUnderwater()) {
+        if (isAlive() && isUnderAcidOrWater() && !canBreatheUnderwater()) {
             this.airSupply--;
             if (this.airSupply == -20) {
                 this.airSupply = 0;
@@ -634,6 +632,7 @@ public abstract class Mob extends Entity {
     public @NotNull String getDeathMessageKey(@Nullable Entity entityKilledBy) {
         if (entityKilledBy != null) return "messages.death.mob.killed_by";
         if (this.isInLava()) return "messages.death.mob.lava";
+        if (this.isInAcid()) return "messages.death.mob.acid";
 
         final var tilePos = new TilePos(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z));
         if (this.world.getBlockType(tilePos) == Blocks.SPIKES) return "messages.death.mob.spikes";
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobSquid.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobSquid.java
index 32cf64749..d21bc8bc2 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobSquid.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobSquid.java
@@ -128,7 +128,7 @@ public class MobSquid extends MobWaterAnimal
     @Override
     public void trySuffocate(){
         if (isSpecial()) return;
-        if(isAlive() && !isUnderLiquid(Materials.WATER) && canBreatheUnderwater())
+        if(isAlive() && !isUnderAcidOrWater() && canBreatheUnderwater())
         {
             airSupply--;
             if(airSupply == -20)
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 952344690..f145f1694 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
@@ -59,8 +59,6 @@ import net.minecraft.core.world.chunk.ChunkCoordinates;
 import net.minecraft.core.world.chunk.provider.ChunkProvider;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
-import net.minecraft.core.world.type.WorldType;
-import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.type.tag.WorldTypeTags;
 import net.minecraft.core.world.weather.Weathers;
 import org.jetbrains.annotations.NotNull;
@@ -134,15 +132,6 @@ public abstract class Player
     public int lastRenderTick = 0;
     public float wobbleTimer = 0;
 
-    public static final int ACID_CYCLE_MAX = 10;
-    private static final int ACID_POST_EXIT_DRAIN_TICKS = 20;
-    private static final int ACID_EXIT_BUFFER = 2;
-
-    private int acidMeltTicks;
-    private int acidExitDelayLeft;
-    private int acidPostExitDrainTicksLeft;
-    private int acidPostExitPeak;
-
     public final PlayerConfig playerConfig = new PlayerConfig();
 
     public Player(World world) {
@@ -393,8 +382,6 @@ public abstract class Player
         this.cameraVelocityOld = this.cameraVelocity;
         super.onLivingUpdate();
 
-        acidTick();
-
         this.speed = this.baseSpeed;
         this.flySpeed = this.baseFlySpeed;
         if (isSprinting()) {
@@ -460,59 +447,35 @@ public abstract class Player
         }
     }
 
+    @Override
     public void acidTick() {
-        if (!getGamemode().hasToolDurability()) {
+        if (getGamemode().hasInvulnerablePlayer()) {
             this.acidMeltTicks = 0;
             this.acidExitDelayLeft = 0;
             this.acidPostExitPeak = 0;
             this.acidPostExitDrainTicksLeft = 0;
             return;
         }
+        super.acidTick();
+    }
 
-        final boolean physicallyInAcid = isInAcid();
-        final int meltRate = Math.max(1, this.world.getGameRuleValue(GameRules.ACID_MELT_RATE));
-        final boolean shouldTickRate = (this.tickCount % meltRate == 0);
+    public boolean shouldShowAcidVisualEffects() {
+        return isEffectiveInAcid() || this.acidMeltTicks > 0;
+    }
 
-        if (physicallyInAcid) {
-            this.acidExitDelayLeft = ACID_EXIT_BUFFER;
-            this.acidPostExitDrainTicksLeft = ACID_POST_EXIT_DRAIN_TICKS;
-            this.acidPostExitPeak = 0;
+    public int getAcidHudBarFillTicks() {
+        if (isEffectiveInAcid() || this.acidPostExitPeak == 0) {
+            return this.acidMeltTicks;
         }
-
-        final boolean applyAcidMeltAndDamage = physicallyInAcid || this.acidExitDelayLeft > 0;
-
-        if (applyAcidMeltAndDamage) {
-            if (!physicallyInAcid && this.acidExitDelayLeft > 0) {
-                this.acidExitDelayLeft--;
-                if (this.acidExitDelayLeft == 0) {
-                    this.acidPostExitPeak = this.acidMeltTicks;
-                }
-            }
-
-            if (shouldTickRate) {
-                this.acidMeltTicks = Math.min(this.acidMeltTicks + 1, ACID_CYCLE_MAX);
-
-                if (!this.world.isClientSide && isAlive()) {
-                    processAcidDamageAndParticles();
-                }
-            }
-        } else if (this.acidMeltTicks > 0) {
-            if (this.acidPostExitDrainTicksLeft > 0) {
-                this.acidPostExitDrainTicksLeft--;
-                if (this.acidPostExitDrainTicksLeft <= 0) {
-                    this.acidMeltTicks = 0;
-                    this.acidPostExitPeak = 0;
-                }
-            }
+        if (this.acidPostExitDrainTicksLeft <= 0) {
+            return 0;
         }
-    }
 
-    /** True while physically in acid or during {@link #ACID_EXIT_BUFFER} post-exit melt/damage ticks. */
-    public boolean isEffectiveInAcid() {
-        return isInAcid() || this.acidExitDelayLeft > 0;
+        return (this.acidPostExitPeak * this.acidPostExitDrainTicksLeft) / ACID_POST_EXIT_DRAIN_TICKS;
     }
 
-    private void processAcidDamageAndParticles() {
+    @Override
+    protected void processAcidDamageAndParticles() {
         final int acidIntensity = this.acidMeltTicks;
         boolean meltedAny = false;
 
@@ -564,22 +527,8 @@ public abstract class Player
         }
     }
 
-    public boolean shouldShowAcidVisualEffects() {
-        return isEffectiveInAcid() || this.acidMeltTicks > 0;
-    }
-
-    public int getAcidHudBarFillTicks() {
-        if (isEffectiveInAcid() || this.acidPostExitPeak == 0) {
-            return this.acidMeltTicks;
-        }
-        if (this.acidPostExitDrainTicksLeft <= 0) {
-            return 0;
-        }
-
-        return (this.acidPostExitPeak * this.acidPostExitDrainTicksLeft) / ACID_POST_EXIT_DRAIN_TICKS;
-    }
-
-    private int getAcidExposureArmorSlotCount() {
+    @Override
+    public int getAcidExposureArmorSlotCount() {
         int count = 0;
         for (int i = 0; i < getNumArmorSlots(); i++) {
             final @Nullable HumanArmorShape armorSlot = getArmorSlotByIndex(i);
@@ -719,7 +668,8 @@ public abstract class Player
 
         if (entityKilledBy == null) {
             if (this.isInLava()) return "messages.death.player.lava";
-    
+            if (this.isInAcid()) return "messages.death.player.acid";
+
             final var tilePos = new TilePos(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z));
             if (this.world.getBlockType(tilePos) == Blocks.SPIKES) return "messages.death.player.spikes";
     
@@ -898,7 +848,7 @@ public abstract class Player
         float defaultBreakSpeed = (this.inventory.getCurrentItem() != null && this.inventory.getCurrentItem().getItem() instanceof ItemToolSword) ? 1.51f : 1.01f;
         if (this.getGamemode().isProperToolNeededToMine() && str <= defaultBreakSpeed)
             return 0; // Requires to break and not effective against block
-        if (isUnderLiquid(Materials.WATER)) {
+        if (isUnderAcidOrWater()) {
             str /= 5F;
         }
         if (!this.onGround && !canClimb() && this.vehicle == null) {
@@ -1548,7 +1498,7 @@ public abstract class Player
         if (this.vehicle != null) {
             return;
         }
-        if (isUnderLiquid(Materials.WATER)) {
+        if (isUnderAcidOrWater()) {
             int i = java.lang.Math.round(MathHelper.sqrt(d * d + d1 * d1 + d2 * d2) * 100F);
             if (i > 0) {
                 addStat(StatList.distanceDoveStat, i);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemRope.java b/game/core/src/main/java/net/minecraft/core/item/ItemRope.java
index c5d2c7c3e..9b04265f2 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemRope.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemRope.java
@@ -36,6 +36,7 @@ public class ItemRope extends ItemPlaceable {
             else return false;
         }
         if (super.shouldShiftOutOf(selfStack, world, player, placePos, side, xHit, yHit)) placePos.add(side);
+        if (super.shouldShiftOutOf(selfStack, world, player, placePos, side, xHit, yHit)) return false; // Prevents overwriting non overwritable blocks
 
         final int meta = (placeOnSide) ? BlockLogicRope.MASK_ROPE_CONNECT : 0;
         return super.placeDirectly(selfStack, world, player, placePos, meta, side, xHit, yHit);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java b/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java
index c7ce862c4..3675e69d9 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java
@@ -14,11 +14,9 @@ public class ItemSaddle extends Item {
 
     @Override
     public boolean useOnEntity(@NotNull ItemStack selfStack, @NotNull Player player, @NotNull Mob mob) {
-        if(!player.isSneaking() && mob instanceof MobPig pig && selfStack.consumeItem(player)) {
-            if(!pig.getSaddled()) {
-                pig.setSaddled(true);
-                return true;
-            }
+        if(!player.isSneaking() && mob instanceof MobPig pig && !pig.getSaddled() && selfStack.consumeItem(player)) {
+            pig.setSaddled(true);
+            return true;
         }
         return false;
     }
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 7cda51a62..78197dfc4 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
@@ -88,7 +88,7 @@ public final class ItemStack {
         this.itemID = itemStack.itemID;
         this.metadata = itemStack.metadata;
         this.stackSize = itemStack.stackSize;
-        this.tag = new CompoundTag(itemStack.tag);
+        this.tag = itemStack.tag.clone();
         this.animationsToGo = 0;
     }
 
@@ -96,8 +96,11 @@ public final class ItemStack {
         this.itemID = itemID;
         this.stackSize = stackSize;
         this.metadata = metadata;
-        if (tag == null) tag = new CompoundTag();
-        this.tag = tag;
+        if (tag == null) {
+            this.tag = new CompoundTag();
+        } else {
+            this.tag = tag.clone();
+        }
     }
 
     private ItemStack()
@@ -365,7 +368,7 @@ public final class ItemStack {
     }
 
     public @NotNull ItemStack copy() {
-        return new ItemStack(this.itemID, this.stackSize, this.metadata, new CompoundTag(this.tag));
+        return new ItemStack(this.itemID, this.stackSize, this.metadata, this.tag);
     }
 
     public static boolean areItemStacksEqual(@Nullable ItemStack stack1, @Nullable ItemStack stack2) {
@@ -520,13 +523,12 @@ public final class ItemStack {
 	}
     
     public void setData(@Nullable CompoundTag tag) {
-        if (tag == null) tag = new CompoundTag();
-        this.tag = tag;
-	}
+        if (tag == null) {
+            this.tag = new CompoundTag();
+        } else {
+            this.tag = tag.clone();
+        }
 
-    public @NotNull ItemStack withTagValue(@NotNull String key, int value) {
-        this.tag.putInt(key, value);
-        return this;
     }
 
     public boolean interactsWithFluid() {
diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/messages.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/messages.lang
index 094b367ce..2e6509607 100644
--- a/game/core/src/main/resources/assets/minecraft/lang/en_US/messages.lang
+++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/messages.lang
@@ -25,6 +25,7 @@ messages.flag.copied=Flag pattern copied.
 
 messages.death.mob.generic=%s died.
 messages.death.mob.lava=%s swam in lava.
+messages.death.mob.acid=%s bathed in acid.
 messages.death.mob.spikes=%s got impaled.
 messages.death.mob.fall=%s broke their legs.
 messages.death.mob.drowned=%s suffocated.
@@ -33,6 +34,7 @@ messages.death.mob.killed_by=%s was killed by %s.
 
 messages.death.player.generic=%s died mysteriously.
 messages.death.player.lava=%s got lost in the sauce.
+messages.death.player.acid=%s is no longer a solid.
 messages.death.player.spikes=%s fell for the trap.
 messages.death.player.fall=%s forgot to tie their laces.
 messages.death.player.drowned=%s is sleeping with the fishes.
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/ByteArrayTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/ByteArrayTag.java
index 2bb14a00f..edb7c986c 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/ByteArrayTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/ByteArrayTag.java
@@ -93,10 +93,15 @@ public class ByteArrayTag extends Tag<byte @NotNull []>
 
     @Override
     public boolean equals(Object obj) {
-        if(!(obj instanceof ByteArrayTag)) return false;
-        ByteArrayTag otherTag = (ByteArrayTag) obj;
+        if(!(obj instanceof ByteArrayTag otherTag)) return false;
         byte[] thisData = getValue();
         byte[] otherData = otherTag.getValue();
         return Arrays.equals(thisData, otherData);
     }
+
+    @Override
+    public ByteArrayTag clone() {
+        var val = this.getValue();
+        return (ByteArrayTag) new ByteArrayTag(Arrays.copyOf(val, val.length)).setName(getTagName());
+    }
 }
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/ByteTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/ByteTag.java
index de6b1d810..aaefd201e 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/ByteTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/ByteTag.java
@@ -40,6 +40,11 @@ public class ByteTag extends Tag<@NotNull Byte>
         return TagID.TAG_BYTE.getId();
     }
 
+    @Override
+    public ByteTag clone() {
+        return (ByteTag) new ByteTag(getValue()).setName(getTagName());
+    }
+
     @Override
     public String toString()
     {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/CompoundTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/CompoundTag.java
index 88423f99e..fd486d77f 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/CompoundTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/CompoundTag.java
@@ -16,19 +16,15 @@ public class CompoundTag extends Tag<@NotNull Map<String, Tag<?>>>
         setValue(new HashMap<>());
     }
 
-    public CompoundTag(CompoundTag tag)
+    public CompoundTag(@Nullable CompoundTag tag)
     {
         setValue(new HashMap<>());
 
-        if (tag == null)
-        {
+        if (tag == null) {
             return;
         }
 
-        for (final String key : tag.getValue().keySet())
-        {
-            getValue().put(key, tag.getTag(key));
-        }
+        tag.getValue().forEach((key, value) -> getValue().put(key, value.clone()));
     }
 
     @Override
@@ -445,4 +441,9 @@ public class CompoundTag extends Tag<@NotNull Map<String, Tag<?>>>
         }
         return true;
     }
+
+    @Override
+    public CompoundTag clone() {
+        return (CompoundTag) new CompoundTag(this).setName(getTagName());
+    }
 }
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/DoubleArrayTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/DoubleArrayTag.java
index a54dabaac..e8da33646 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/DoubleArrayTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/DoubleArrayTag.java
@@ -95,10 +95,16 @@ public class DoubleArrayTag extends Tag<double @NotNull []>
 
     @Override
     public boolean equals(Object obj) {
-        if(!(obj instanceof DoubleArrayTag)) return false;
-        DoubleArrayTag otherTag = (DoubleArrayTag) obj;
+        if(!(obj instanceof DoubleArrayTag otherTag)) return false;
         double[] thisData = getValue();
         double[] otherData = otherTag.getValue();
         return Arrays.equals(thisData, otherData);
     }
+
+    @Override
+    public DoubleArrayTag clone() {
+        var val = this.getValue();
+        return (DoubleArrayTag) new DoubleArrayTag(Arrays.copyOf(val, val.length)).setName(getTagName());
+    }
+
 }
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/DoubleTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/DoubleTag.java
index c29321a22..34e4273b3 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/DoubleTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/DoubleTag.java
@@ -53,6 +53,11 @@ public class DoubleTag extends Tag<@NotNull Double>
         return TagID.TAG_DOUBLE.getId();
     }
 
+    @Override
+    public DoubleTag clone() {
+        return (DoubleTag) new DoubleTag(getValue()).setName(getTagName());
+    }
+
     @Override
     public String toString()
     {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/EndTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/EndTag.java
index 2a5ba8ab5..9e79c4c8b 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/EndTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/EndTag.java
@@ -43,6 +43,11 @@ public class EndTag extends Tag<Void>
         return TagID.TAG_END.getId();
     }
 
+    @Override
+    public EndTag clone() {
+        return new EndTag();
+    }
+
     @Override
     public String toString()
     {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/FloatTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/FloatTag.java
index 098f57e94..801e1d102 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/FloatTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/FloatTag.java
@@ -40,6 +40,11 @@ public class FloatTag extends Tag<@NotNull Float>
         return TagID.TAG_FLOAT.getId();
     }
 
+    @Override
+    public FloatTag clone() {
+        return (FloatTag) new FloatTag(getValue()).setName(getTagName());
+    }
+
     @Override
     public void fromJson(@NotNull final JsonElement json) throws JsonParseException {
         if (!json.isJsonPrimitive()) {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/IntTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/IntTag.java
index 365e73e34..ee5f9dbd2 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/IntTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/IntTag.java
@@ -40,6 +40,11 @@ public class IntTag extends Tag<@NotNull Integer>
         return TagID.TAG_INT.getId();
     }
 
+    @Override
+    public IntTag clone() {
+        return (IntTag) new IntTag(getValue()).setName(getTagName());
+    }
+
     @Override
     public void fromJson(@NotNull final JsonElement json) throws JsonParseException {
         if (!json.isJsonPrimitive()) {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/ListTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/ListTag.java
index e9854d0cf..b3627f246 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/ListTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/ListTag.java
@@ -105,6 +105,14 @@ public class ListTag
         return TagID.TAG_LIST.getId();
     }
 
+    @Override
+    public ListTag clone() {
+        var thisList = getValue();
+        List<Tag<?>> list = new ArrayList<>(thisList.size());
+        thisList.forEach(v -> list.add(v.clone()));
+        return (ListTag) new ListTag(list).setName(getTagName());
+    }
+
     @Override
     public String toString()
     {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/LongArrayTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/LongArrayTag.java
index 6c55902bd..24c9208cf 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/LongArrayTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/LongArrayTag.java
@@ -98,10 +98,15 @@ public class LongArrayTag extends Tag<long @NotNull []>{
 
     @Override
     public boolean equals(Object obj) {
-        if(!(obj instanceof LongArrayTag)) return false;
-        LongArrayTag otherTag = (LongArrayTag) obj;
+        if(!(obj instanceof LongArrayTag otherTag)) return false;
         long[] thisData = getValue();
         long[] otherData = otherTag.getValue();
         return Arrays.equals(thisData, otherData);
     }
+
+    @Override
+    public LongArrayTag clone() {
+        var val = this.getValue();
+        return (LongArrayTag) new LongArrayTag(Arrays.copyOf(val, val.length)).setName(getTagName());
+    }
 }
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/LongTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/LongTag.java
index d7c9f61a2..ee29ebc1a 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/LongTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/LongTag.java
@@ -40,6 +40,11 @@ public class LongTag extends Tag<@NotNull Long>
         return TagID.TAG_LONG.getId();
     }
 
+    @Override
+    public LongTag clone() {
+        return (LongTag) new LongTag(getValue()).setName(getTagName());
+    }
+
     @Override
     public void fromJson(@NotNull final JsonElement json) throws JsonParseException {
         if (!json.isJsonPrimitive()) {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/ShortArrayTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/ShortArrayTag.java
index e61702166..175ae47e5 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/ShortArrayTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/ShortArrayTag.java
@@ -100,10 +100,15 @@ public class ShortArrayTag extends Tag<short @NotNull []>
 
     @Override
     public boolean equals(Object obj) {
-        if(!(obj instanceof ShortArrayTag)) return false;
-        ShortArrayTag otherTag = (ShortArrayTag) obj;
+        if(!(obj instanceof ShortArrayTag otherTag)) return false;
         short[] thisData = getValue();
         short[] otherData = otherTag.getValue();
         return Arrays.equals(thisData, otherData);
     }
+
+    @Override
+    public ShortArrayTag clone() {
+        var val = this.getValue();
+        return (ShortArrayTag) new ShortArrayTag(Arrays.copyOf(val, val.length)).setName(getTagName());
+    }
 }
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/ShortTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/ShortTag.java
index bf50c6545..f65e62b3e 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/ShortTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/ShortTag.java
@@ -40,6 +40,11 @@ public class ShortTag extends Tag<@NotNull Short>
         return TagID.TAG_SHORT.getId();
     }
 
+    @Override
+    public ShortTag clone() {
+        return (ShortTag) new ShortTag(getValue()).setName(getTagName());
+    }
+
     @Override
     public void fromJson(@NotNull final JsonElement json) throws JsonParseException {
         if (!json.isJsonPrimitive()) {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/StringTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/StringTag.java
index 05fd29499..b3f6f37bd 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/StringTag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/StringTag.java
@@ -40,6 +40,11 @@ public class StringTag extends Tag<@NotNull String>
         return TagID.TAG_STRING.getId();
     }
 
+    @Override
+    public StringTag clone() {
+        return (StringTag) new StringTag(getValue()).setName(getTagName());
+    }
+
     @Override
     public void fromJson(@NotNull final JsonElement json) throws JsonParseException {
         if (!json.isJsonPrimitive()) {
diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/Tag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/Tag.java
index abf683851..751a137e5 100644
--- a/util/nbt/src/main/java/com/mojang/nbt/tags/Tag.java
+++ b/util/nbt/src/main/java/com/mojang/nbt/tags/Tag.java
@@ -13,7 +13,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.function.Supplier;
 
-public abstract class Tag<T>
+public abstract class Tag<T> implements Cloneable
 {
     /**
      * The key of the tag.
@@ -207,6 +207,9 @@ public abstract class Tag<T>
         return tag;
     }
 
+    @Override
+    public abstract Tag<T> clone();
+
     public enum TagID {
         TAG_END(0, "TAG_End", EndTag::new),
         TAG_BYTE(1, "TAG_Byte", ByteTag::new),
