diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
index 2cc84dcf1..6bd32029e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
@@ -323,7 +323,7 @@ public class ScreenSelectWorld extends Screen {
 
             long sizeBytes = saveFile.getSizeOnDisk();
             this.descBuilder1.append(saveFile.getFileName());
-            this.descBuilder1.append(" (").append(ScreenSelectWorld.this.dateFormatter.format(new Date(saveFile.getLastTimePlayed())));
+            this.descBuilder1.append(" (").append(ScreenSelectWorld.this.dateFormatter.format(new Date(saveFile.getLastTimePlayed())).replace("\u202f", " ")); // removes the nnbsp
             this.descBuilder1.append(", ").append((float) (((sizeBytes / 1024L) * 100L) / 1024L) / 100F).append(" MB)");
 
             if (saveFile.getNeedsConversion()) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ParticleEntryBubble.java b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ParticleEntryBubble.java
index 7bd0d81f1..00f16acfb 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ParticleEntryBubble.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ParticleEntryBubble.java
@@ -2,6 +2,7 @@ package net.minecraft.client.gui.modelviewer.categories.entries.particle;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.particle.ParticleBubble;
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 
 public class ParticleEntryBubble extends ParticleEntryGeneric {
@@ -10,6 +11,6 @@ public class ParticleEntryBubble extends ParticleEntryGeneric {
     }
     @Override
     public void spawnParticle(Minecraft mc, World world, double x, double y, double z) {
-        mc.particleEngine.add(new ParticleBubble(world, x, y, z, motionX, motionY, motionZ, false));
+        mc.particleEngine.add(new ParticleBubble(world, x, y, z, motionX, motionY, motionZ, Dimension.OVERWORLD, false));
     }
 }
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 ca2d2fdf6..ae7b567d7 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
@@ -173,7 +173,7 @@ public abstract class OptionsPages {
                     .withComponent(new FloatOptionComponent(GameSettings.COLOR_CORRECTION))
                     .withComponent(new FloatOptionComponent(GameSettings.FXAA))
                     .withComponent(new ToggleableOptionComponent<>(GameSettings.BLOOM))
-                    .withComponent(new BooleanOptionComponent(GameSettings.HEAT_HAZE))
+                    .withComponent(new FloatOptionComponent(GameSettings.HEAT_HAZE))
                 )
                 .withComponent(new OptionsCategory("gui.options.page.video.category.performance")
                     .withComponent(new ToggleableOptionComponent<>(GameSettings.RENDER_DISTANCE))
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 8ea3fa761..8e2113959 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
@@ -373,7 +373,7 @@ public final class GameSettings {
             return option.toOptionsString();
         }));
     public static final @NotNull OptionEnum<RenderScale> RENDER_SCALE = register(new OptionEnum<>("renderScale", RenderScale.class, RenderScale.SCALE_100));
-    public static final @NotNull OptionBoolean HEAT_HAZE = register(new OptionBoolean("heatHaze", false));
+    public static final @NotNull OptionFloat HEAT_HAZE = register(new OptionFloat("heatHaze", 0));
     public static final @NotNull OptionBoolean ALPHA_MENU = register(new OptionBoolean("old", false));
     public static final @NotNull OptionBoolean ENABLE_ITEM_CLUMPING = register(new OptionBoolean("enableItemClumping", true));
     public static final @NotNull OptionEnum<DescriptionPromptEnum> ITEM_DESCRIPTIONS = register(new OptionEnum<>("itemDescriptions", DescriptionPromptEnum.class, DescriptionPromptEnum.PROMPT));
diff --git a/game/client/src/main/java/net/minecraft/client/render/PostProcessingManager.java b/game/client/src/main/java/net/minecraft/client/render/PostProcessingManager.java
index cb2e8cf61..7a1fabc4a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/PostProcessingManager.java
+++ b/game/client/src/main/java/net/minecraft/client/render/PostProcessingManager.java
@@ -68,7 +68,8 @@ public class PostProcessingManager {
         if (this.mc.currentWorld == null || this.mc.thePlayer == null) return;
 
         this.reset();
-        if (GameSettings.COLOR_CORRECTION.value == 0) return;
+        float ccValue = GameSettings.COLOR_CORRECTION.value;
+        boolean haze = GameSettings.HEAT_HAZE.value != 0;
 
         final float y = (float) this.mc.thePlayer.y;
         final int maxY = this.mc.currentWorld.getWorldType().getMaxY(this.mc.currentWorld);
@@ -107,67 +108,73 @@ public class PostProcessingManager {
         }
 
         // Perform season effects
-        float seasonProgress = this.mc.currentWorld.getSeasonManager().getSeasonProgress(); // Ranges from 0.0 to 1.0
-        seasonProgress = (seasonProgress * 2) - 1f; // Ranges from -1.0 to 1.0
-        seasonProgress = Math.abs(seasonProgress); // Ranges from 1.0 to 0.0 to 1.0
-        seasonProgress = -seasonProgress + 1.0f; // Ranges from 0.0 to 1.0 to 0.0
-        if (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_SPRING) {
-            this.current.saturation += 0.1f * seasonProgress * surfaceness;
-        } else if (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_SUMMER) {
-            this.current.rMod += 0.1f * seasonProgress * surfaceness;
-            this.current.gMod += 0.1f * seasonProgress * surfaceness;
-        } else if (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_FALL) {
-            this.current.contrast -= 0.1f * seasonProgress * surfaceness;
-            this.current.rMod += 0.1f * seasonProgress * surfaceness;
-        } else if (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER) {
-            this.current.contrast -= 0.1f * seasonProgress * surfaceness;
-            this.current.bMod += 0.1f * seasonProgress * surfaceness;
+        if (ccValue != 0) {
+            float seasonProgress = this.mc.currentWorld.getSeasonManager().getSeasonProgress(); // Ranges from 0.0 to 1.0
+            seasonProgress = (seasonProgress * 2) - 1f; // Ranges from -1.0 to 1.0
+            seasonProgress = Math.abs(seasonProgress); // Ranges from 1.0 to 0.0 to 1.0
+            seasonProgress = -seasonProgress + 1.0f; // Ranges from 0.0 to 1.0 to 0.0
+            if (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_SPRING) {
+                this.current.saturation += 0.1f * seasonProgress * surfaceness;
+            } else if (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_SUMMER) {
+                this.current.rMod += 0.1f * seasonProgress * surfaceness;
+                this.current.gMod += 0.1f * seasonProgress * surfaceness;
+            } else if (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_FALL) {
+                this.current.contrast -= 0.1f * seasonProgress * surfaceness;
+                this.current.rMod += 0.1f * seasonProgress * surfaceness;
+            } else if (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_WINTER) {
+                this.current.contrast -= 0.1f * seasonProgress * surfaceness;
+                this.current.bMod += 0.1f * seasonProgress * surfaceness;
+            }
         }
 
         // Perform weather effects
-        final Weather activeWeather = this.mc.currentWorld.getCurrentWeather();
-        if (activeWeather != null) {
-            final float intensity = this.mc.currentWorld.getWeatherManager().getWeatherIntensity() * this.mc.currentWorld.getWeatherManager().getWeatherIntensity();
-            if (activeWeather == Weathers.OVERWORLD_SNOW || activeWeather == Weathers.OVERWORLD_WINTER_SNOW) {
-                this.current.contrast += -0.125f * intensity * surfaceness;
-                this.current.saturation += -0.25f * intensity * surfaceness;
-                this.current.bMod += 0.25f * intensity * surfaceness;
-            } else if (activeWeather == Weathers.OVERWORLD_RAIN_BLOOD) {
-                this.current.rMod += 0.4f * intensity * surfaceness;
-                this.current.gMod += 0.1f * intensity * surfaceness;
-                this.current.saturation += 0.125f * intensity * surfaceness;
-                this.current.exposure -= 0.125f * intensity * surfaceness;
-            } else if (activeWeather == Weathers.OVERWORLD_RAIN) {
-                this.current.bMod += 0.1f * intensity * surfaceness;
-                this.current.saturation += -0.125f * intensity * surfaceness;
-                this.current.brightness += -0.0625f * intensity * surfaceness;
-            } else if (activeWeather == Weathers.OVERWORLD_STORM) {
-                this.current.bMod += 0.1f * intensity * surfaceness;
-                this.current.saturation += -0.2f * intensity * surfaceness;
-                this.current.brightness += -0.1f * intensity * surfaceness;
-            } else if (activeWeather == Weathers.OVERWORLD_FOG && GameSettings.FOG.value) {
-                this.current.saturation += -0.4f * intensity * surfaceness;
-                this.current.contrast += -0.25f * intensity * surfaceness;
+        if (ccValue != 0) {
+            final Weather activeWeather = this.mc.currentWorld.getCurrentWeather();
+            if (activeWeather != null) {
+                final float intensity = this.mc.currentWorld.getWeatherManager().getWeatherIntensity() * this.mc.currentWorld.getWeatherManager().getWeatherIntensity();
+                if (activeWeather == Weathers.OVERWORLD_SNOW || activeWeather == Weathers.OVERWORLD_WINTER_SNOW) {
+                    this.current.contrast += -0.125f * intensity * surfaceness;
+                    this.current.saturation += -0.25f * intensity * surfaceness;
+                    this.current.bMod += 0.25f * intensity * surfaceness;
+                } else if (activeWeather == Weathers.OVERWORLD_RAIN_BLOOD) {
+                    this.current.rMod += 0.4f * intensity * surfaceness;
+                    this.current.gMod += 0.1f * intensity * surfaceness;
+                    this.current.saturation += 0.125f * intensity * surfaceness;
+                    this.current.exposure -= 0.125f * intensity * surfaceness;
+                } else if (activeWeather == Weathers.OVERWORLD_RAIN) {
+                    this.current.bMod += 0.1f * intensity * surfaceness;
+                    this.current.saturation += -0.125f * intensity * surfaceness;
+                    this.current.brightness += -0.0625f * intensity * surfaceness;
+                } else if (activeWeather == Weathers.OVERWORLD_STORM) {
+                    this.current.bMod += 0.1f * intensity * surfaceness;
+                    this.current.saturation += -0.2f * intensity * surfaceness;
+                    this.current.brightness += -0.1f * intensity * surfaceness;
+                } else if (activeWeather == Weathers.OVERWORLD_FOG && GameSettings.FOG.value) {
+                    this.current.saturation += -0.4f * intensity * surfaceness;
+                    this.current.contrast += -0.25f * intensity * surfaceness;
+                }
             }
         }
 
         // Perform dimension effects
-        if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.HOT)) {
+        if ((ccValue != 0 || haze) && this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.HOT)) {
             float scale = 1.0f;
             if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.NETHER) && temperature < 0.5) {
                 scale = (float) temperature * 2.0f;
             }
-            this.current.rMod += 1.2f * scale;
-            this.current.gMod += 0.3f * scale;
-            this.current.saturation += 0.125f * scale;
-            this.current.exposure -= 0.125f;
-            this.current.contrast -= 0.05f;
-            this.current.brightness -= 0.05f;
-            this.current.heatHaze = scale;
+            if (ccValue != 0) {
+                this.current.rMod += 1.2f * scale;
+                this.current.gMod += 0.3f * scale;
+                this.current.saturation += 0.125f * scale;
+                this.current.exposure -= 0.125f;
+                this.current.contrast -= 0.05f;
+                this.current.brightness -= 0.05f;
+            }
+            if (haze) this.current.heatHaze = scale;
         }
 
         // Perform heatwave effects
-        if (this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.OVERWORLD) && (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_SUMMER || this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_FALL)) {
+        if (haze && this.mc.currentWorld.getWorldType().hasTag(WorldTypeTags.OVERWORLD) && (this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_SUMMER || this.mc.currentWorld.getSeasonManager().getCurrentSeason() == Seasons.OVERWORLD_FALL)) {
             if (temperature >= 0.85 && humidity <= 0.15) {
                 final double tPercentage = (temperature - 0.85) / 0.15;
                 final double hPercentage = 1 - (humidity / 0.15);
@@ -178,24 +185,27 @@ public class PostProcessingManager {
         }
 
         // Scaling
-        if (GameSettings.COLOR_CORRECTION.value != 0) {
-            this.current.brightness *= GameSettings.COLOR_CORRECTION.value;
-            this.current.contrast *= GameSettings.COLOR_CORRECTION.value;
-            this.current.exposure *= GameSettings.COLOR_CORRECTION.value;
-            this.current.saturation *= GameSettings.COLOR_CORRECTION.value;
-            this.current.rMod = 1.0f - (1.0f - this.current.rMod) * GameSettings.COLOR_CORRECTION.value;
-            this.current.gMod = 1.0f - (1.0f - this.current.gMod) * GameSettings.COLOR_CORRECTION.value;
-            this.current.bMod = 1.0f - (1.0f - this.current.bMod) * GameSettings.COLOR_CORRECTION.value;
+        if (ccValue != 0) {
+            this.current.brightness *= ccValue;
+            this.current.contrast *= ccValue;
+            this.current.exposure *= ccValue;
+            this.current.saturation *= ccValue;
+            this.current.rMod = 1.0f - (1.0f - this.current.rMod) * ccValue;
+            this.current.gMod = 1.0f - (1.0f - this.current.gMod) * ccValue;
+            this.current.bMod = 1.0f - (1.0f - this.current.bMod) * ccValue;
+
+            this.current.brightness = smoothLerp(this.oldCurrent.brightness, this.current.brightness);
+            this.current.contrast = smoothLerp(this.oldCurrent.contrast, this.current.contrast);
+            this.current.exposure = smoothLerp(this.oldCurrent.exposure, this.current.exposure);
+            this.current.saturation = smoothLerp(this.oldCurrent.saturation, this.current.saturation);
+            this.current.rMod = smoothLerp(this.oldCurrent.rMod, this.current.rMod);
+            this.current.gMod = smoothLerp(this.oldCurrent.gMod, this.current.gMod);
+            this.current.bMod = smoothLerp(this.oldCurrent.bMod, this.current.bMod);
+        }
+        if (haze) {
+            this.current.heatHaze *= GameSettings.HEAT_HAZE.value * 3;
+            this.current.heatHaze = smoothLerp(this.oldCurrent.heatHaze, this.current.heatHaze);
         }
-
-        this.current.brightness = smoothLerp(this.oldCurrent.brightness, this.current.brightness);
-        this.current.contrast = smoothLerp(this.oldCurrent.contrast, this.current.contrast);
-        this.current.exposure = smoothLerp(this.oldCurrent.exposure, this.current.exposure);
-        this.current.saturation = smoothLerp(this.oldCurrent.saturation, this.current.saturation);
-        this.current.rMod = smoothLerp(this.oldCurrent.rMod, this.current.rMod);
-        this.current.gMod = smoothLerp(this.oldCurrent.gMod, this.current.gMod);
-        this.current.bMod = smoothLerp(this.oldCurrent.bMod, this.current.bMod);
-        this.current.heatHaze = smoothLerp(this.oldCurrent.heatHaze, this.current.heatHaze);
     }
 
     public void render(final float partialTick) {
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 59dd489e1..fed8bba1c 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
@@ -802,7 +802,7 @@ public class WorldRenderer {
                 rainParticlePositionY = (heightmapPosition + 0.1F) - Blocks.blocksList[blockId].getBounds().minY();
                 rainParticlePositionZ = z + blockZ;
             }
-            this.mc.particleEngine.add(new ParticleWaterDrop(world, x + blockX, (heightmapPosition + 0.1F) - Blocks.blocksList[blockId].getBounds().minY(), z + blockZ));
+            this.mc.particleEngine.add(new ParticleWaterDrop(world, x + blockX, (heightmapPosition + 0.1F) - Blocks.blocksList[blockId].getBounds().minY(), z + blockZ, world.dimension));
         }
 
         if (spawnedParticles > 0 && this.random.nextInt(3) < this.rainSoundCounter++) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
index bae1ed67b..c6d332f6b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
@@ -1,5 +1,6 @@
 package net.minecraft.client.render.block.model;
 
+import net.minecraft.client.option.GameSettings;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
@@ -135,10 +136,17 @@ public class BlockModelFluid<T extends BlockLogicFluid> extends BlockModelStanda
                 tessellator.addVertexWithUV(x + 1, (float) y + he, z, tex.getIconUMin(), tex.getIconVMin());
 
                 if (worldSource.getWorldType().hasTag(WorldTypeTags.NETHER) && this.block.getLogic().fluid instanceof FluidWater) {
-                    tessellator.setColorOpaque3i(
-                        ((Color.redFromInt(color) * 3) / 4) + (255/4),
-                        ((Color.greenFromInt(color) * 3) / 4) + (255/4),
-                        ((Color.blueFromInt(color) * 3) / 4) + (255/4));
+                    if (GameSettings.BIOME_WATER.value) {
+                        tessellator.setColorOpaque3i(
+                            ((Color.redFromInt(color) * 3) / 4) + (255/4),
+                            ((Color.greenFromInt(color) * 3) / 4) + (255/4),
+                            ((Color.blueFromInt(color) * 3) / 4) + (255/4));
+                    } else {
+                        tessellator.setColorOpaque3i(
+                            200,
+                            255/3,
+                            255/3);
+                    }
 
                     random.setSeed(getPositionalSeed(tilePos));
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java
index 508c84db4..8c481379f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java
@@ -6,6 +6,7 @@ import net.minecraft.client.render.renderer.GLRenderer;
 import net.minecraft.client.render.renderer.State;
 import net.minecraft.client.render.tessellator.TessellatorGeneral;
 import net.minecraft.core.entity.animal.MobWolf;
+import net.minecraft.core.item.IArmorItem;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.util.helper.MathHelper;
@@ -24,7 +25,9 @@ public class MobRendererWolf extends MobRenderer<MobWolf> {
     protected @Nullable StaticEntityModel getAndSetupModelForLayer(@NotNull final MobWolf entity, final float brightness, final float partialTick, final int layer) {
         final StaticEntityModel model;
         if (layer == 1) {
-            final ArmorMaterial material = entity.getArmorMaterial();
+            final ItemStack armor = entity.getArmorItem();
+            if (armor == null) return null;
+            final ArmorMaterial material = ((IArmorItem<?>) armor.getItem()).getArmorMaterial();
             if (material == null) return null;
             bindTexture(String.format("/assets/%s/textures/armor/wolf/%s.png", material.identifier.namespace(), material.identifier.value()));
             model = getModel("armor");
@@ -103,7 +106,7 @@ public class MobRendererWolf extends MobRenderer<MobWolf> {
 
     @Override
     protected int maxRenderLayer(@NotNull final MobWolf entity) {
-        return entity.getArmorMaterial() != null ? 1 : 0;
+        return entity.getArmorItem() != null ? 1 : 0;
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererZombieArmored.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererZombieArmored.java
index 47dc66c79..fc5928b0f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererZombieArmored.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererZombieArmored.java
@@ -24,17 +24,6 @@ public class MobRendererZombieArmored extends MobRendererBipedArmored<MobZombieA
 
         bindTexture("/assets/minecraft/textures/armor/chain" + "_" + (layer != 3 ? 1 : 2) + ".png");
 
-        // Disable armor pieces depending on health
-        final int[] armorBreakPoints = entity.getArmorBreakPoints();
-        final int[] armorBreakOrder = entity.getArmorBreakOrder();
-        for (int i = 0; i < 4; i++)
-        {
-            if (entity.getHealth() <= armorBreakPoints[i])
-            {
-                hideArmorPiece(armorBreakOrder[i]);
-            }
-        }
-
         final StaticEntityModel model;
         switch (layer) {
             case 4:
@@ -58,28 +47,46 @@ public class MobRendererZombieArmored extends MobRendererBipedArmored<MobZombieA
 
     private void hideArmorPiece(final int piece)
     {
-//        if (piece == 0)
-//        {
-//            modelArmorChestplate.head.visible = false;
-//            modelArmorChestplate.hair.visible = false;
-//        }
-//        else if (piece == 1)
-//        {
-//            modelArmorChestplate.body.visible = false;
-//            modelArmorChestplate.armLeft.visible = false;
-//            modelArmorChestplate.armRight.visible = false;
-//        }
-//        else if (piece == 2)
-//        {
-//            modelArmor.body.visible = false;
-//            modelArmor.legLeft.visible = false;
-//            modelArmor.legRight.visible = false;
-//        }
-//        else if (piece == 3)
-//        {
-//            modelArmorChestplate.legLeft.visible = false;
-//            modelArmorChestplate.legRight.visible = false;
-//        }
+        if (piece == 0)
+        {
+            StaticEntityModel model = getModel("armor.helmet");
+            model.getTransform("head").visible = false;
+            model.getTransform("chest").visible = false;
+            model.getTransform("rightArm").visible = false;
+            model.getTransform("leftArm").visible = false;
+            model.getTransform("rightLeg").visible = false;
+            model.getTransform("leftLeg").visible = false;
+        }
+        else if (piece == 1)
+        {
+            StaticEntityModel model = getModel("armor.chestplate");
+            model.getTransform("head").visible = false;
+            model.getTransform("chest").visible = false;
+            model.getTransform("rightArm").visible = false;
+            model.getTransform("leftArm").visible = false;
+            model.getTransform("rightLeg").visible = false;
+            model.getTransform("leftLeg").visible = false;
+        }
+        else if (piece == 2)
+        {
+            StaticEntityModel model = getModel("armor.leggings");
+            model.getTransform("head").visible = false;
+            model.getTransform("chest").visible = false;
+            model.getTransform("rightArm").visible = false;
+            model.getTransform("leftArm").visible = false;
+            model.getTransform("rightLeg").visible = false;
+            model.getTransform("leftLeg").visible = false;
+        }
+        else if (piece == 3)
+        {
+            StaticEntityModel model = getModel("armor.boots");
+            model.getTransform("head").visible = false;
+            model.getTransform("chest").visible = false;
+            model.getTransform("rightArm").visible = false;
+            model.getTransform("leftArm").visible = false;
+            model.getTransform("rightLeg").visible = false;
+            model.getTransform("leftLeg").visible = false;
+        }
     }
 
     @Override
@@ -107,6 +114,18 @@ public class MobRendererZombieArmored extends MobRendererBipedArmored<MobZombieA
         leftArm.rotZ -= MathHelper.cos(limbPitch * 0.09F) * 0.05F + 0.05F;
         rightArm.rotX += MathHelper.sin(limbPitch * 0.067F) * 0.05F;
         leftArm.rotX -= MathHelper.sin(limbPitch * 0.067F) * 0.05F;
+
+        // Disable armor pieces depending on health
+        final int[] armorBreakPoints = entity.getArmorBreakPoints();
+        final int[] armorBreakOrder = entity.getArmorBreakOrder();
+        for (int i = 0; i < 4; i++)
+        {
+            if (entity.getHealth() <= armorBreakPoints[i])
+            {
+                hideArmorPiece(armorBreakOrder[i]);
+            }
+        }
+
         return model1;
     }
 }
\ No newline at end of file
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
index 546314a3c..050f870af 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
@@ -429,6 +429,13 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
 
         addDispatch(new ItemModelStandard(Items.DOUGH, "minecraft"));
 
+        addDispatch(new ItemModelStandard(Items.ARMOR_WOLF_LEATHER, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.ARMOR_WOLF_CHAINMAIL, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.ARMOR_WOLF_IRON, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.ARMOR_WOLF_DIAMOND, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.ARMOR_WOLF_GOLD, "minecraft"));
+        addDispatch(new ItemModelStandard(Items.ARMOR_WOLF_STEEL, "minecraft"));
+
         for (int i = 0; i < Blocks.blocksList.length; i++) {
             if (Blocks.blocksList[i] == null) continue;
             Item item = Blocks.blocksList[i].asItem();
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java
index 1587e0b04..659823227 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java
@@ -2,19 +2,21 @@ package net.minecraft.client.render.particle;
 
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.material.Materials;
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
 
 public class ParticleBubble extends Particle {
     private final boolean needsWater;
 
-    public ParticleBubble(World world, double x, double y, double z, double xa, double ya, double za, boolean needsWater) {
+    public ParticleBubble(World world, double x, double y, double z, double xa, double ya, double za, @NotNull Dimension dimension, boolean needsWater) {
         super(world, x, y, z, xa, ya, za);
         this.needsWater = needsWater;
         this.rCol = 1.0F;
         this.gCol = 1.0F;
         this.bCol = 1.0F;
-        this.tex = TextureRegistry.getTexture("minecraft:particle/bubble");
+        this.tex = dimension == Dimension.NETHER ? TextureRegistry.getTexture("minecraft:particle/bubble_boiling") : TextureRegistry.getTexture("minecraft:particle/bubble");
         this.size = this.size * (random.nextFloat() * 0.6F + 0.2F);
         this.xd = xa * 0.2D + (Math.random() * 2D - 1.0D) * 0.02F;
         this.yd = ya * 0.2D + (Math.random() * 2D - 1.0D) * 0.02F;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubbleBoiling.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubbleBoiling.java
index b36d3fe5f..a498892fb 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubbleBoiling.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubbleBoiling.java
@@ -1,10 +1,12 @@
 package net.minecraft.client.render.particle;
 
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.material.Materials;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
 import org.joml.primitives.AABBd;
 
 public class ParticleBubbleBoiling extends Particle {
@@ -13,6 +15,7 @@ public class ParticleBubbleBoiling extends Particle {
     private final boolean needsWater;
 //    private final AABBd aabbd = new AABBd();
     private final TilePos qpos = new TilePos();
+    private final @NotNull IconCoordinate popping = TextureRegistry.getTexture("minecraft:particle/bubble_boiling_pop");
 
     public ParticleBubbleBoiling(World world, double x, double y, double z, double xa, double ya, double za, boolean needsWater) {
         super(world, x, y, z, xa, ya, za);
@@ -60,10 +63,13 @@ public class ParticleBubbleBoiling extends Particle {
         if (this.needsWater && !inWater) {
             this.lifetime = MathHelper.clamp(this.lifetime, 0, 8);
         }
-        if (this.lifetime-- <= 0) {
-            remove();
+        if (this.lifetime == 6) {
+            this.tex = this.popping;
             world.spawnParticle("smoke", x, y, z, 0.0D, 0.0D, 0.0D, 1);
+        } else if (this.lifetime <= 0) {
+            remove();
         }
+        this.lifetime--;
     }
 
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleDispatcher.java
index 955c11139..00fc5385a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleDispatcher.java
@@ -12,6 +12,7 @@ import net.minecraft.core.item.Item;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.util.helper.BlockParticleHelper;
 import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
@@ -47,7 +48,7 @@ public final class ParticleDispatcher extends Dispatcher<String, ParticleEntry>
         addDispatch("bubble", new ParticleEntry() {
             @Override
             public Particle newParticle(@NotNull World world, double x, double y, double z, double motionX, double motionY, double motionZ, int data) {
-                return new ParticleBubble(world, x, y, z, motionX, motionY, motionZ, true);
+                return new ParticleBubble(world, x, y, z, motionX, motionY, motionZ, Dimension.getDimensionList().getOrDefault(data, Dimension.OVERWORLD), true);
             }
         });
         addDispatch("bubbleboiling", new ParticleEntry() {
@@ -113,7 +114,7 @@ public final class ParticleDispatcher extends Dispatcher<String, ParticleEntry>
         addDispatch("splash", new ParticleEntry() {
             @Override
             public Particle newParticle(@NotNull World world, double x, double y, double z, double motionX, double motionY, double motionZ, int data) {
-                return new ParticleSplash(world, x, y, z, motionX, motionY, motionZ);
+                return new ParticleSplash(world, x, y, z, motionX, motionY, motionZ, Dimension.getDimensionList().getOrDefault(data, Dimension.OVERWORLD));
             }
         });
         addDispatch("largesmoke", new ParticleEntry() {
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSplash.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSplash.java
index ba55ca638..5f652edba 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSplash.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSplash.java
@@ -1,10 +1,12 @@
 package net.minecraft.client.render.particle;
 
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 
 public class ParticleSplash extends ParticleWaterDrop {
-    public ParticleSplash(World world, double x, double y, double z, double xa, double ya, double za) {
-        super(world, x, y, z);
+    public ParticleSplash(World world, double x, double y, double z, double xa, double ya, double za, @NotNull Dimension dimension) {
+        super(world, x, y, z, dimension);
         this.gravity = 0.04F;
         if (ya == 0.0D && (xa != 0.0D || za != 0.0D)) {
             this.xd = xa;
diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleWaterDrop.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleWaterDrop.java
index 415620843..7303d06d1 100644
--- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleWaterDrop.java
+++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleWaterDrop.java
@@ -4,11 +4,13 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.BlockLogicFluid;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
 
 public class ParticleWaterDrop extends Particle {
-    public ParticleWaterDrop(World world, double x, double y, double z) {
+    public ParticleWaterDrop(World world, double x, double y, double z, @NotNull Dimension dimension) {
         super(world, x, y, z, 0.0D, 0.0D, 0.0D);
         this.xd *= 0.3D;
         this.yd = (float) Math.random() * 0.2F + 0.1F;
@@ -16,7 +18,7 @@ public class ParticleWaterDrop extends Particle {
         this.rCol = 1.0F;
         this.gCol = 1.0F;
         this.bCol = 1.0F;
-        this.tex = TextureRegistry.getTexture("minecraft:particle/splash_rain_" + random.nextInt(4));
+        this.tex = TextureRegistry.getTexture((dimension == Dimension.NETHER ? "minecraft:particle/splash_rain_blood_" : "minecraft:particle/splash_rain_") + random.nextInt(4));
         this.gravity = 0.06F;
         this.lifetime = (int) (8D / (Math.random() * 0.8D + 0.2D));
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/shader/ShaderHelper.java b/game/client/src/main/java/net/minecraft/client/render/shader/ShaderHelper.java
index be7dd11e3..c0990da79 100644
--- a/game/client/src/main/java/net/minecraft/client/render/shader/ShaderHelper.java
+++ b/game/client/src/main/java/net/minecraft/client/render/shader/ShaderHelper.java
@@ -75,9 +75,9 @@ public final class ShaderHelper {
         shader.uniformFloat("frameTimeCounter", frameTimeCounter);
         shader.uniformFloat("gamma", GameSettings.GAMMA.value);
         shader.uniformFloat("fxaa", GameSettings.FXAA.value);
-        shader.uniformFloat("heatHaze", GameSettings.HEAT_HAZE.value ? minecraft.ppm.lerped.heatHaze : 0.0f);
+        shader.uniformFloat("heatHaze", (GameSettings.HEAT_HAZE.value != 0) ? minecraft.ppm.lerped.heatHaze : 0.0f);
         shader.uniformInt("bloom", GameSettings.BLOOM.value);
-        shader.uniformInt("dimension", minecraft.currentWorld != null && minecraft.currentWorld.dimension != null ? minecraft.currentWorld.dimension.id : 0);
+        shader.uniformInt("dimension", minecraft.currentWorld != null ? minecraft.currentWorld.dimension.id : 0);
         shader.uniformInt("cbCorrectionMode", GameSettings.COLORBLINDNESS_FIX.value.ordinal());
 
         ItemStack helmet = minecraft.thePlayer == null ? null : minecraft.thePlayer.getItemInArmorSlot(HumanArmorShape.HEAD);
diff --git a/game/client/src/main/java/net/minecraft/client/util/helper/ScreenShot.java b/game/client/src/main/java/net/minecraft/client/util/helper/ScreenShot.java
index 2feb5149a..55a79d076 100644
--- a/game/client/src/main/java/net/minecraft/client/util/helper/ScreenShot.java
+++ b/game/client/src/main/java/net/minecraft/client/util/helper/ScreenShot.java
@@ -11,8 +11,6 @@ import java.util.function.Supplier;
 import com.mojang.logging.LogUtils;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.shader.ShadersRenderer;
-import net.minecraft.client.render.shader.framebuffer.FrameBuffer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL41;
@@ -65,13 +63,7 @@ public class ScreenShot
                 id++;
             }
 
-            final @Nullable FrameBuffer frameBuffer = ((ShadersRenderer) mc.renderer).getGameFrameBuffer();
-            if (frameBuffer == null) {
-                throw new IllegalStateException("Game frame buffer is null!");
-            }
-
-            // Bind framebuffer and PBO
-            frameBuffer.bind();
+            // Bind PBO
             GL41.glBindBuffer(GL41.GL_PIXEL_PACK_BUFFER, transferPbo);
 
             // Insert fence
@@ -82,8 +74,7 @@ public class ScreenShot
             GL41.glPixelStorei(GL41.GL_UNPACK_ALIGNMENT, 1);
             GL41.glReadPixels(0, 0, width, height, GL41.GL_RGBA, GL41.GL_UNSIGNED_BYTE, 0);
 
-            // Unbind framebuffer and PBO
-            frameBuffer.unbind();
+            // Unbind PBO
             GL41.glBindBuffer(GL41.GL_PIXEL_PACK_BUFFER, 0);
 
         } catch(Exception exception) {
diff --git a/game/client/src/main/resources/assets/minecraft/models/block/slab/cobbled_gloomstone/upper.json b/game/client/src/main/resources/assets/minecraft/models/block/slab/cobbled_gloomstone/upper.json
index ea13c55a3..ae49ac3fc 100644
--- a/game/client/src/main/resources/assets/minecraft/models/block/slab/cobbled_gloomstone/upper.json
+++ b/game/client/src/main/resources/assets/minecraft/models/block/slab/cobbled_gloomstone/upper.json
@@ -1,8 +1,8 @@
 {
   "parent": "minecraft:block/slab/upper",
   "textures": {
-    "top": "minecraft:block/cobbled_netherrack",
-    "bottom": "minecraft:block/cobbled_netherrack",
-    "side": "minecraft:block/cobbled_netherrack"
+    "top": "minecraft:block/cobbled_gloomstone",
+    "bottom": "minecraft:block/cobbled_gloomstone",
+    "side": "minecraft:block/cobbled_gloomstone"
   }
 }
\ No newline at end of file
diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/cobbled_netherrack/crystalline.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/cobbled_netherrack/crystalline.emiss.png
index 2d4e3fa6d..d5d729778 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/cobbled_netherrack/crystalline.emiss.png and b/game/client/src/main/resources/assets/minecraft/textures/block/cobbled_netherrack/crystalline.emiss.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_chainmail.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_chainmail.png
new file mode 100644
index 000000000..0a663f0c4
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_chainmail.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_diamond.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_diamond.png
new file mode 100644
index 000000000..fc611acac
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_diamond.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_gold.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_gold.png
new file mode 100644
index 000000000..e5b9e83a7
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_gold.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_iron.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_iron.png
new file mode 100644
index 000000000..03ec47439
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_iron.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_leather.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_leather.png
new file mode 100644
index 000000000..4e5445703
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_leather.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_steel.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_steel.png
new file mode 100644
index 000000000..821279844
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_wolf_steel.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/particle/bubble_boiling.png b/game/client/src/main/resources/assets/minecraft/textures/particle/bubble_boiling.png
index 7ec9f1156..ba3591272 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/particle/bubble_boiling.png and b/game/client/src/main/resources/assets/minecraft/textures/particle/bubble_boiling.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/particle/bubble_boiling_pop.png b/game/client/src/main/resources/assets/minecraft/textures/particle/bubble_boiling_pop.png
new file mode 100644
index 000000000..ff14e427e
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/particle/bubble_boiling_pop.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_0.png b/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_0.png
new file mode 100644
index 000000000..3657955a1
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_0.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_1.png b/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_1.png
new file mode 100644
index 000000000..dc0389f1b
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_1.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_2.png b/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_2.png
new file mode 100644
index 000000000..fd6c1c934
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_2.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_3.png b/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_3.png
new file mode 100644
index 000000000..349e9008b
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/particle/splash_rain_blood_3.png differ
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
index e73cf95b5..025325c56 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
@@ -52,7 +52,8 @@ public class BlockLogicDispenser extends BlockLogicVeryRotatable {
         final int zOffset = direction.getOffsetZ();
 
         final @NotNull TileEntityDispenser tileEntity = (TileEntityDispenser) Objects.requireNonNull(world.getTileEntity(tilePos));
-        final @Nullable ItemStack itemStack = tileEntity.getRandomStackFromInventory();
+        int stackIndex = tileEntity.getRandomStackIndexFromInventory();
+        final @Nullable ItemStack itemStack = stackIndex >= 0 ? tileEntity.getItem(stackIndex) : null;
         final @NotNull Vector3dc pos = new Vector3d(tilePos.x(), tilePos.y(), tilePos.z()).add(xOffset * 0.6 + 0.5, yOffset * 0.6 + 0.5, zOffset * 0.6 + 0.5);
         if (itemStack == null) {
             world.playBlockEvent(tilePos, LevelListener.EVENT_DISPENSER_EMPTY, 0);
@@ -61,35 +62,44 @@ public class BlockLogicDispenser extends BlockLogicVeryRotatable {
                 dispensable.onDispensed(itemStack, world, random, direction, pos.x(), pos.y(), pos.z());
                 world.playBlockEvent(tilePos, LevelListener.EVENT_DISPENSER_PROJECTILE, 0);
             } else if (itemStack.itemID == Items.AMMO_ARROW.id || itemStack.itemID == Items.AMMO_ARROW_GOLD.id) {
-                final @NotNull ProjectileArrow arrow;
-                if (itemStack.itemID == Items.AMMO_ARROW.id) {
-                    arrow = new ProjectileArrow(world, pos.x(), pos.y(), pos.z(), 0);
-                } else {
-                    arrow = new ProjectileArrowGolden(world, pos.x(), pos.y(), pos.z());
+                if (itemStack.consumeItem(null)) {
+                    final @NotNull ProjectileArrow arrow;
+                    if (itemStack.itemID == Items.AMMO_ARROW.id) {
+                        arrow = new ProjectileArrow(world, pos.x(), pos.y(), pos.z(), 0);
+                    } else {
+                        arrow = new ProjectileArrowGolden(world, pos.x(), pos.y(), pos.z());
+                    }
+                    arrow.setHeading(xOffset, yOffset + 0.1D, zOffset, 1.1F, 6F);
+                    arrow.setDoesArrowBelongToPlayer(true);
+                    world.entityJoinedWorld(arrow);
                 }
-                arrow.setHeading(xOffset, yOffset + 0.1D, zOffset, 1.1F, 6F);
-                arrow.setDoesArrowBelongToPlayer(true);
-                world.entityJoinedWorld(arrow);
                 world.playBlockEvent(tilePos, LevelListener.EVENT_DISPENSER_PROJECTILE, 0);
             } else if (itemStack.itemID == Items.AMMO_CHARGE_EXPLOSIVE.id) {
-                final @NotNull ProjectileCannonball projectileCannonball = new ProjectileCannonball(world, pos.x(), pos.y(), pos.z());
-                projectileCannonball.setHeading(xOffset, yOffset + 0.1D, zOffset, 1.1F, 6F);
-                world.entityJoinedWorld(projectileCannonball);
+                if (itemStack.consumeItem(null)) {
+                    final @NotNull ProjectileCannonball projectileCannonball = new ProjectileCannonball(world, pos.x(), pos.y(), pos.z());
+                    projectileCannonball.setHeading(xOffset, yOffset + 0.1D, zOffset, 1.1F, 6F);
+                    world.entityJoinedWorld(projectileCannonball);
+                }
                 world.playBlockEvent(tilePos, LevelListener.EVENT_DISPENSER_PROJECTILE, 0);
             } else {
-                final @NotNull EntityItem item = new EntityItem(world, pos.x(), pos.y() + (direction == Direction.UP ? 0.25d : -0.3D), pos.z(), itemStack);
-                final double randOffset = random.nextDouble() * 0.1D + 0.2D;
-                item.xd = (double) xOffset * randOffset;
-                item.yd = (double) yOffset + (direction == Direction.UP ? -0.65D : 0.2D);
-                item.zd = (double) zOffset * randOffset;
-                item.xd += random.nextGaussian() * 0.0075D * 6D;
-                item.yd += random.nextGaussian() * 0.0075D * 6D;
-                item.zd += random.nextGaussian() * 0.0075D * 6D;
-                world.entityJoinedWorld(item);
+                if (itemStack.consumeItem(null)) {
+                    final @NotNull EntityItem item = new EntityItem(world, pos.x(), pos.y() + (direction == Direction.UP ? 0.25d : -0.3D), pos.z(), new ItemStack(itemStack.getItem()));
+                    final double randOffset = random.nextDouble() * 0.1D + 0.2D;
+                    item.xd = (double) xOffset * randOffset;
+                    item.yd = (double) yOffset + (direction == Direction.UP ? -0.65D : 0.2D);
+                    item.zd = (double) zOffset * randOffset;
+                    item.xd += random.nextGaussian() * 0.0075D * 6D;
+                    item.yd += random.nextGaussian() * 0.0075D * 6D;
+                    item.zd += random.nextGaussian() * 0.0075D * 6D;
+                    world.entityJoinedWorld(item);
+                }
                 world.playBlockEvent(tilePos, LevelListener.EVENT_DISPENSER_ITEM, 0);
             }
             world.playBlockEvent(tilePos, LevelListener.EVENT_DISPENSER_PARTICLES, direction.getId());
         }
+        if (stackIndex >= 0 && itemStack != null && itemStack.stackSize <= 0) {
+            tileEntity.setItem(stackIndex, null);
+        }
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
index 8d204d005..6568dc84f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
@@ -142,7 +142,7 @@ public class BlockLogicFarmland
 
     @Override
     public void onEntityWalkedOn(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Entity walker) {
-        if (world.rand.nextInt(4) == 0) {
+        if (world.rand.nextInt(4) == 0 && !world.isClientSide) {
             if (walker instanceof final @NotNull Player player) {
                 final @Nullable ItemStack bootsSlotStack = player.getItemInArmorSlot(HumanArmorShape.BOOTS);
                 if (bootsSlotStack != null && bootsSlotStack.getItem() == Items.ARMOR_BOOTS_LEATHER) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/Blocks.java b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
index ed57f4a23..49e76fa40 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Blocks.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
@@ -1123,15 +1123,15 @@ public final class Blocks {
         .withTags(BlockTags.MINEABLE_BY_PICKAXE);
 
     public static final Block<?> RUBYGLASS_COLUMN = register("rubyglass.column", "minecraft:block/rubyglass_column", 821, (b) -> new BlockLogicRubyglass(b))
-        .withSound(BlockSounds.GLASS).withHardness(3F).withLightEmission(0.8F)
+        .withSound(BlockSounds.GLASS).withHardness(3F).withLightEmission(0.5F)
         .withTags(BlockTags.MINEABLE_BY_PICKAXE)
         .withOverrideColor(MaterialColor.rubyglass);
     public static final Block<?> BLOCK_RUBYGLASS = register("block.rubyglass", "minecraft:block/block_rubyglass", 822, (b) -> new BlockLogicTransparent(b, Materials.STONE))
-        .withSound(BlockSounds.GLASS).withHardness(3F).withLightEmission(0.8F)
+        .withSound(BlockSounds.GLASS).withHardness(3F).withLightEmission(0.5F)
         .withTags(BlockTags.MINEABLE_BY_PICKAXE)
         .withOverrideColor(MaterialColor.rubyglass);
     public static final Block<?> RUBYGLASS_SPROUT = register("rubyglass.sprout", "minecraft:block/rubyglass_sprout", 823, (b) -> new BlockLogicRubyglassSprout(b))
-        .withSound(BlockSounds.GLASS).withDisabledNeighborNotifyOnMetadataChange().withLightEmission(0.8F)
+        .withSound(BlockSounds.GLASS).withDisabledNeighborNotifyOnMetadataChange().withLightEmission(0.5F)
         .withTags(BlockTags.MINEABLE_BY_PICKAXE)
         .withOverrideColor(MaterialColor.rubyglass);
     public static final Block<?> RUBYGLASS_CIRCUIT = register("rubyglass.circuit", "minecraft:block/rubyglass_circuit", 824, (b) -> new BlockLogic(b, Materials.STONE))
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java
index 28def0062..dd7fa3cd0 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java
@@ -96,6 +96,20 @@ public class TileEntityDispenser extends TileEntity
         }
     }
 
+    public int getRandomStackIndexFromInventory()
+    {
+        int i = -1;
+        int j = 1;
+        for(int k = 0; k < dispenserContents.length; k++)
+        {
+            if(dispenserContents[k] != null && random.nextInt(j++) == 0)
+            {
+                i = k;
+            }
+        }
+        return i;
+    }
+
     @Override
 	public void setItem(int slot, @Nullable ItemStack stack)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java
index b4b797808..d41a4f95f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java
@@ -108,6 +108,7 @@ public class TileEntityMobSpawner extends TileEntity {
                     updateDelay();
                     continue;
                 }
+                mob.spawnInit();
                 this.worldObj.entityJoinedWorld(mob);
                 for (int k = 0; k < 20; k++) {
                     double d1 = (double) this.x + 0.5D + ((double) this.worldObj.rand.nextFloat() - 0.5D) * 2D;
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 0276d2e48..b2ad0861b 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
@@ -24,7 +24,6 @@ import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.LightIndexHelper;
 import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.ICarriable;
 import net.minecraft.core.world.IVehicle;
 import net.minecraft.core.world.World;
@@ -323,13 +322,13 @@ public abstract class Entity
                 for (int i = 0; (float) i < 1.0F + this.bbWidth * 20F; i++) {
                     double offX = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth;
                     double offZ = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth;
-                    this.world.spawnParticle("bubble", this.x + offX, f1 + 1.0F, this.z + offZ, this.xd, this.yd - (double) (this.random.nextFloat() * 0.2F), this.zd, 0);
+                    this.world.spawnParticle("bubble", this.x + offX, f1 + 1.0F, this.z + offZ, this.xd, this.yd - (double) (this.random.nextFloat() * 0.2F), this.zd, this.world.dimension.id);
                 }
 
                 for (int j = 0; (float) j < 1.0F + this.bbWidth * 20F; j++) {
                     double offX = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth;
                     double offZ = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth;
-                    this.world.spawnParticle("splash", this.x + offX, f1 + 1.0F, this.z + offZ, this.xd, this.yd, this.zd, 0);
+                    this.world.spawnParticle("splash", this.x + offX, f1 + 1.0F, this.z + offZ, this.xd, this.yd, this.zd, this.world.dimension.id);
                 }
             }
             this.fallDistance = 0.0F;
@@ -1384,6 +1383,10 @@ public abstract class Entity
         return false;
     }
 
+    public boolean isSpawnCapExempt() {
+        return false;
+    }
+
     public static String getNameFromEntity(@NotNull Entity entity, boolean useNickname) {
         I18n translator = I18n.getInstance();
         if (entity instanceof Mob && useNickname) {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java b/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java
index dbc9e63d0..d8165fdbd 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java
@@ -274,7 +274,7 @@ public class EntityFishingBobber extends Entity {
             }
         }
 
-        if (d5 > 0.0D) {
+        if (d5 > 0.0D && !this.world.isClientSide) {
             if (this.ticksCatchable > 0) {
                 this.ticksCatchable--;
             } else {
@@ -299,13 +299,13 @@ public class EntityFishingBobber extends Entity {
                     for (int i1 = 0; (float) i1 < 1.0F + this.bbWidth * 20F; i1++) {
                         double xOff = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth;
                         double zOff = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth;
-                        this.world.spawnParticle("bubble", this.x + xOff, f3 + 1.0F, this.z + zOff, this.xd, this.yd - (double) (this.random.nextFloat() * 0.2F), this.zd, 0);
+                        this.world.spawnParticle("bubble", this.x + xOff, f3 + 1.0F, this.z + zOff, this.xd, this.yd - (double) (this.random.nextFloat() * 0.2F), this.zd, this.world.dimension.id);
                     }
 
                     for (int j1 = 0; (float) j1 < 1.0F + this.bbWidth * 20F; j1++) {
                         double xOff = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth;
                         double zOff = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth;
-                        this.world.spawnParticle("splash", this.x + xOff, f3 + 1.0F, this.z + zOff, this.xd, this.yd, this.zd, 0);
+                        this.world.spawnParticle("splash", this.x + xOff, f3 + 1.0F, this.z + zOff, this.xd, this.yd, this.zd, this.world.dimension.id);
                     }
 
                 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java b/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java
index b21344618..18c3dc302 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java
@@ -18,6 +18,7 @@ import net.minecraft.core.item.tag.ItemTags;
 import net.minecraft.core.util.helper.DamageType;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
 import org.joml.primitives.AABBd;
 
@@ -31,6 +32,7 @@ public class EntityItem extends Entity
     public float bobOffset;
     public int basketPickupDelay = 0;
     public static boolean enableItemClumping = true;
+    private final TilePos queryPos = new TilePos();
 
     public EntityItem(@NotNull World world, double x, double y, double z, @NotNull ItemStack itemstack) {
         super(world);
@@ -97,11 +99,24 @@ public class EntityItem extends Entity
         this.xo = this.x;
         this.yo = this.y;
         this.zo = this.z;
-
-        if (item.getItem().hasTag(ItemTags.IS_FIRE_PROOF)) {
-            this.yd += (this.wasInWater || inLava) ? 0.02D : -0.04D;
+        boolean throughBelow = !this.world.getBlockType(this.queryPos.set(MathHelper.floor(this.x), MathHelper.floor(this.y) - 1, MathHelper.floor(this.z))).collidesWithEntity(this, this.world, this.queryPos);
+        if (this.item.getItem().hasTag(ItemTags.IS_FIRE_PROOF)) {
+            if (((this.wasInWater || inLava) && !throughBelow)) {
+                this.yd += 0.02D;
+            } else if (this.wasInWater || inLava){
+                this.yd += (-0.04D * 3.5);
+            } else {
+                this.yd += (-0.04D * 1);
+            }
         } else {
-            this.yd += this.wasInWater ? 0.02D : -0.04D;
+
+            if ((this.wasInWater && !throughBelow)) {
+                this.yd += 0.02D;
+            } else if (this.wasInWater) {
+                this.yd += (-0.04D * 3.5);
+            } else {
+                this.yd += (-0.04D * 1);
+            }
 
             if(isInLava())
             {
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 bcb6319a7..0396e8bb3 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
@@ -4,7 +4,6 @@ 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.entity.vehicle.EntityBoat;
 import net.minecraft.core.item.ItemFood;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.WeightedRandomLootObject;
@@ -23,7 +22,6 @@ import net.minecraft.core.util.helper.DamageType;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
-import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
@@ -246,6 +244,11 @@ public abstract class Mob extends Entity {
     protected void onLabelled() {
     }
 
+    @Override
+    public boolean isSpawnCapExempt() {
+        return !this.nickname.isEmpty();
+    }
+
     public void setNickname(@NotNull String nickname) {
         this.nickname = nickname;
         this.hadNicknameSet = true;
@@ -340,7 +343,7 @@ public abstract class Mob extends Entity {
                     double offX = this.random.nextFloat() - this.random.nextFloat();
                     double offY = this.random.nextFloat() - this.random.nextFloat();
                     double offZ = this.random.nextFloat() - this.random.nextFloat();
-                    this.world.spawnParticle("bubble", this.x + offX, this.y + offY, this.z + offZ, this.xd, this.yd, this.zd, 0);
+                    this.world.spawnParticle("bubble", this.x + offX, this.y + offY, this.z + offZ, this.xd, this.yd, this.zd, this.world.dimension.id);
                 }
 
                 hurt(null, 2, DamageType.DROWN);
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
index b911eb426..7d97f88e5 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
@@ -1,13 +1,12 @@
 package net.minecraft.core.entity.animal;
 
+import com.mojang.nbt.tags.StringTag;
+import com.mojang.nbt.tags.Tag;
 import net.minecraft.core.entity.*;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.projectile.ProjectileArrow;
-import net.minecraft.core.item.ItemFood;
-import net.minecraft.core.item.IArmorItem;
-import net.minecraft.core.item.Item;
-import net.minecraft.core.item.Items;
-import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.enums.WolfArmorShape;
+import net.minecraft.core.item.*;
 import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.util.helper.UUIDHelper;
 import net.minecraft.core.util.helper.MathHelper;
@@ -23,18 +22,18 @@ import java.util.*;
 
 public class MobWolf
     extends MobAnimal
-    implements IItemHolding// ,
+    implements IItemHolding, IArmorWearing<WolfArmorShape>
 //    AgedMob
 {
     public static final Map<ArmorMaterial, IArmorItem<?>> ARMOR_MATERIALS = new HashMap<>();
 
     static {
-        ARMOR_MATERIALS.put(ArmorMaterial.LEATHER, (IArmorItem<?>) Items.ARMOR_CHESTPLATE_LEATHER);
-        ARMOR_MATERIALS.put(ArmorMaterial.CHAINMAIL, (IArmorItem<?>) Items.ARMOR_CHESTPLATE_CHAINMAIL);
-        ARMOR_MATERIALS.put(ArmorMaterial.IRON, (IArmorItem<?>) Items.ARMOR_CHESTPLATE_IRON);
-        ARMOR_MATERIALS.put(ArmorMaterial.GOLD, (IArmorItem<?>) Items.ARMOR_CHESTPLATE_GOLD);
-        ARMOR_MATERIALS.put(ArmorMaterial.DIAMOND, (IArmorItem<?>) Items.ARMOR_CHESTPLATE_DIAMOND);
-        ARMOR_MATERIALS.put(ArmorMaterial.STEEL, (IArmorItem<?>) Items.ARMOR_CHESTPLATE_STEEL);
+        ARMOR_MATERIALS.put(ArmorMaterial.LEATHER, (IArmorItem<?>) Items.ARMOR_WOLF_LEATHER);
+        ARMOR_MATERIALS.put(ArmorMaterial.CHAINMAIL, (IArmorItem<?>) Items.ARMOR_WOLF_CHAINMAIL);
+        ARMOR_MATERIALS.put(ArmorMaterial.IRON, (IArmorItem<?>) Items.ARMOR_WOLF_IRON);
+        ARMOR_MATERIALS.put(ArmorMaterial.GOLD, (IArmorItem<?>) Items.ARMOR_WOLF_GOLD);
+        ARMOR_MATERIALS.put(ArmorMaterial.DIAMOND, (IArmorItem<?>) Items.ARMOR_WOLF_DIAMOND);
+        ARMOR_MATERIALS.put(ArmorMaterial.STEEL, (IArmorItem<?>) Items.ARMOR_WOLF_STEEL);
     }
 
     public static final int DATA_HELD_ITEM = 15;
@@ -43,7 +42,7 @@ public class MobWolf
     public static final int MASK_ANGRY = 0b0000_0010;
     public static final int MASK_TAMED = 0b0000_0100;
     public static final int DATA_OWNER_UUID = 17;
-    public static final int DATA_ARMOR_MATERIAL = 19;
+    public static final int DATA_ARMOR_ITEM = 19;
 
     private boolean looksWithInterest;
     private float interestedAngle;
@@ -52,7 +51,6 @@ public class MobWolf
     private boolean field_25052_g;
     private float timeWolfIsShaking;
     private float prevTimeWolfIsShaking;
-    private ItemStack armor = null;
 //    private final @NotNull MobAge age;
 
     public MobWolf(World world) {
@@ -71,7 +69,7 @@ public class MobWolf
         this.entityData.define(DATA_HELD_ITEM, null, ItemStack.class);
         this.entityData.define(DATA_GENERIC_FLAGS, (byte) 0, Byte.class);
         this.entityData.define(DATA_OWNER_UUID, null, UUID.class);
-        this.entityData.define(DATA_ARMOR_MATERIAL, "", String.class);
+        this.entityData.define(DATA_ARMOR_ITEM, null, ItemStack.class);
     }
 
     @Override
@@ -91,31 +89,15 @@ public class MobWolf
         }
     }
 
-    public @Nullable ArmorMaterial getArmorMaterial() {
-        ArmorMaterial material = null;
-        final String name = this.entityData.getString(DATA_ARMOR_MATERIAL);
-        if (name == null) return null;
-        for (final ArmorMaterial mat : ArmorMaterial.getArmorMaterials()) {
-            if (mat.identifier.toString().equalsIgnoreCase(name)) {
-                material = mat;
-                break;
-            }
-        }
-
-        return material;
+    public @Nullable ItemStack getArmorItem() {
+        final @Nullable ItemStack item = this.entityData.getItemStack(DATA_ARMOR_ITEM);
+        if (item == null || !(item.getItem() instanceof @NotNull IArmorItem<?>)) return null;
+        return item;
     }
 
-    public void setArmor(final ItemStack stack) {
-        ArmorMaterial material = null;
-        this.armor = stack;
-        if (stack != null && stack.getItem() instanceof IArmorItem && ARMOR_MATERIALS.containsValue(stack.getItem())) {
-            material = ((IArmorItem<?>) stack.getItem()).getArmorMaterial();
-        }
-        if (material == null) {
-            this.entityData.set(DATA_ARMOR_MATERIAL, null);
-        } else {
-            this.entityData.set(DATA_ARMOR_MATERIAL, material.identifier.toString());
-        }
+    public void setArmorItem(final @Nullable ItemStack stack) {
+        if (stack != null && (!(stack.getItem() instanceof IArmorItem<?> armorItem) || armorItem.getArmorShape() != WolfArmorShape.BODY)) return;
+        this.entityData.set(DATA_ARMOR_ITEM, stack);
     }
 
     @Override
@@ -166,9 +148,9 @@ public class MobWolf
 
             tag.putCompound("HeldItem", heldItemNBT);
         }
-        if (getArmorMaterial() != null) {
+        if (getArmorItem() != null) {
             CompoundTag armorTag = new CompoundTag();
-            this.armor.writeToNBT(armorTag);
+            getArmorItem().writeToNBT(armorTag);
             tag.putCompound("Armor", armorTag);
         }
         UUIDHelper.writeToTag(tag, getWolfOwner(), "OwnerUUID");
@@ -191,21 +173,26 @@ public class MobWolf
         }
 
         if (tag.containsKey("Armor")) {
-            ArmorMaterial material = null;
-            String name = tag.getString("Armor");
-            if (!name.isEmpty()) {
-                for (ArmorMaterial mat : ArmorMaterial.getArmorMaterials()) {
-                    if (mat.identifier.toString().equalsIgnoreCase(name)) {
-                        material = mat;
-                        break;
+            Tag<?> armorTag = tag.getTag("Armor");
+
+            if (armorTag instanceof StringTag stringTag) {
+                ArmorMaterial material = null;
+                String name = stringTag.getValue();
+                if (!name.isEmpty()) {
+                    for (ArmorMaterial mat : ArmorMaterial.getArmorMaterials()) {
+                        if (mat.identifier.toString().equalsIgnoreCase(name)) {
+                            material = mat;
+                            break;
+                        }
                     }
+                    Item item = ARMOR_MATERIALS.get(material).asItem();
+                    setArmorItem(item.getDefaultStack());
+                } else {
+                    setArmorItem(null);
                 }
-                Item item = ARMOR_MATERIALS.get(material).asItem();
-                setArmor(item.getDefaultStack());
-            } else {
-                CompoundTag armorTag = tag.getCompound("Armor");
-                ItemStack armor = ItemStack.readItemStackFromNbt(armorTag);
-                setArmor(armor);
+            } else if (armorTag instanceof CompoundTag compoundTag) {
+                final @Nullable ItemStack armorItem = ItemStack.readItemStackFromNbt(compoundTag);
+                this.setArmorItem(armorItem);
             }
 
         }
@@ -229,6 +216,11 @@ public class MobWolf
 //        this.age.readTag(tag);
     }
 
+    @Override
+    public boolean isSpawnCapExempt() {
+        return this.getWolfOwner() != null;
+    }
+
     @Override
     protected boolean canDespawn() {
         return !isWolfTamed() && super.canDespawn();
@@ -278,9 +270,9 @@ public class MobWolf
             dropItem(getHeldItem(), 0.0f);
             setHeldItem(null);
         }
-        if (this.armor != null && this.armor.stackSize > 0) {
-            dropItem(this.armor, 0);
-            setArmor(null);
+        if (this.getArmorItem() != null) {
+            dropItem(this.getArmorItem(), 0);
+            this.setArmorItem(null);
         }
         super.dropDeathItems();
     }
@@ -442,7 +434,7 @@ public class MobWolf
                 for (int j = 0; j < i; j++) {
                     double offX = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth * 0.5F;
                     double offZ = (this.random.nextFloat() * 2.0F - 1.0F) * this.bbWidth * 0.5F;
-                    this.world.spawnParticle("splash", this.x + offX, f + 0.8F, this.z + offZ, this.xd, this.yd, this.zd, 0);
+                    this.world.spawnParticle("splash", this.x + offX, f + 0.8F, this.z + offZ, this.xd, this.yd, this.zd, this.world.dimension.id);
                 }
 
             }
@@ -586,47 +578,46 @@ public class MobWolf
 
     @Override
     protected void damageEntity(int damage, DamageType damageType) {
-        if (getArmorMaterial() == null) {
-            super.damageEntity(damage, damageType);
-            return;
+        float protection = 1.0f;
+        if (damageType != null) {
+            protection -= getTotalProtectionAmount(damageType);
         }
-
-        float protection = 1.0f - getArmorMaterial().getProtection(damageType);
         protection = Math.max(protection, 0.01f);
 
         //If you take little damage and have lots of protection against that damage
-        //there is a high change you wont take any damage
+        //there is a high change you won't take any damage
         double d = damage * protection;
-        int newDamage = (int) (this.random.nextFloat() > 0.5 ? Math.floor(d) : Math.ceil(d));
+        int newDamage = (int) (random.nextFloat() > 0.5 ? Math.floor(d) : Math.ceil(d));
 
-        super.damageEntity(newDamage, damageType);
+        int preventedDamage = damage - newDamage;
+        if(damageType != null && damageType.shouldDamageArmor()){
+            //Reduce armor for big damage amounts, for example explosions
+            int armorDamage = (int) Math.ceil(preventedDamage / 4.0);
+            damageArmor(armorDamage);
+        }
+
+        super.damageEntity(damage, damageType);
     }
 
     public void lavaHurt() {
-        if (!this.fireImmune) {
-            float protection = 0;
-            ArmorMaterial material;
-            if ((material = getArmorMaterial()) != null) {
-                protection = 1.0f - material.getProtection(DamageType.FIRE);
-            }
+        if(!fireImmune)
+        {
+            float protection = 1.0f - getTotalProtectionAmount(DamageType.FIRE);
             protection = Math.max(protection, 0.01f);
             hurt(null, 4, DamageType.FIRE);
-            this.remainingFireTicks = (int) (80 + 520 * protection);
-            this.maxFireTicks = this.remainingFireTicks;
+            remainingFireTicks = (int) (80 + 520 * protection);
+            maxFireTicks = remainingFireTicks;
         }
     }
 
     public void fireHurt() {
-        if (!this.fireImmune) {
-            float protection = 0;
-            ArmorMaterial material;
-            if ((material = getArmorMaterial()) != null) {
-                protection = 1.0f - material.getProtection(DamageType.FIRE);
-            }
+        if(!fireImmune)
+        {
+            float protection = 1.0f - getTotalProtectionAmount(DamageType.FIRE);
             protection = Math.max(protection, 0.01f);
             hurt(null, 1, DamageType.FIRE);
-            this.remainingFireTicks = (int) (40 + 260 * protection);
-            this.maxFireTicks = this.remainingFireTicks;
+            remainingFireTicks = (int) (40 + 260 * protection);
+            maxFireTicks = remainingFireTicks;
         }
     }
 
@@ -669,13 +660,13 @@ public class MobWolf
                     return true;
                 }
             }
-            if (itemstack != null && itemstack.getItem() instanceof IArmorItem<?> armorItem && player.uuid.equals(getWolfOwner())) {
+            if (itemstack != null && itemstack.getItem() instanceof IArmorItem<?> armorItem && armorItem.getArmorShape() == WolfArmorShape.BODY && player.uuid.equals(getWolfOwner())) {
                 if (armorItem.getArmorMaterial() != null && ARMOR_MATERIALS.containsValue(armorItem)) {
-                    if (this.armor != null) {
-                        dropItem(this.armor, 0.0f);
-                        setArmor(null);
+                    if (this.getArmorItem() != null) {
+                        dropItem(this.getArmorItem(), 0.0f);
+                        setArmorItem(null);
                     }
-                    setArmor(new ItemStack(itemstack.getItem(), 1, itemstack.getMetadata(), itemstack.getData()));
+                    setArmorItem(new ItemStack(itemstack.getItem(), 1, itemstack.getMetadata(), itemstack.getData()));
                     if (player.getGamemode().hasBlockConsumption()) {
                         itemstack.stackSize--;
                         if (itemstack.stackSize <= 0) {
@@ -685,9 +676,9 @@ public class MobWolf
                     return true;
                 }
             }
-            if (itemstack == null && player.isSneaking() && this.armor != null && player.uuid.equals(getWolfOwner())) {
-                dropItem(this.armor, 0.0f);
-                setArmor(null);
+            if (itemstack == null && player.isSneaking() && this.getArmorItem() != null && player.uuid.equals(getWolfOwner())) {
+                dropItem(this.getArmorItem(), 0.0f);
+                setArmorItem(null);
                 return true;
             }
             if (player.uuid.equals(getWolfOwner())) {
@@ -808,4 +799,34 @@ public class MobWolf
     public boolean isLeftHanded() {
         return false;
     }
+
+    @Override
+    public @Nullable ItemStack getItemInArmorSlot(@NotNull WolfArmorShape slot) {
+        if (slot == WolfArmorShape.BODY) {
+            return this.getArmorItem();
+        }
+
+        return null;
+    }
+
+    @Override
+    public void setItemInArmorSlot(@NotNull WolfArmorShape slot, @Nullable ItemStack item) {
+        if (slot == WolfArmorShape.BODY) {
+            this.setArmorItem(item);
+        }
+    }
+
+    @Override
+    public int getNumArmorSlots() {
+        return 1;
+    }
+
+    @Override
+    public @Nullable WolfArmorShape getArmorSlotByIndex(int index) {
+        if (index == 0) {
+            return WolfArmorShape.BODY;
+        }
+
+        return null;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/ArmorBags.java b/game/core/src/main/java/net/minecraft/core/entity/monster/ArmorBags.java
index 6296e9515..0f7b8de10 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/ArmorBags.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/ArmorBags.java
@@ -14,28 +14,28 @@ public abstract class ArmorBags {
     static {
         ZOMBIE_ARMOR_BAGS.put(HumanArmorShape.HEAD,
                 new ArmorBag<>(HumanArmorShape.HEAD)
-                        .addEntry(null, 100, 1.0f)
+                        .addEntry(null, 400, 1.0f)
                         .addEntry(Items.ARMOR_HELMET_LEATHER, 30, 0.8f)
                         .addEntry(Items.ARMOR_HELMET_IRON, 10, 0.5f)
                         .addEntry(Items.ARMOR_HELMET_DIAMOND, 5, 0.125f)
                         .addEntry(Items.ARMOR_HELMET_STEEL, 1, 0.125f));
         ZOMBIE_ARMOR_BAGS.put(HumanArmorShape.CHEST,
                 new ArmorBag<>(HumanArmorShape.CHEST)
-                        .addEntry(null, 100, 1.0f)
+                        .addEntry(null, 400, 1.0f)
                         .addEntry(Items.ARMOR_CHESTPLATE_LEATHER, 30, 0.8f)
                         .addEntry(Items.ARMOR_CHESTPLATE_IRON, 10, 0.5f)
                         .addEntry(Items.ARMOR_CHESTPLATE_DIAMOND, 5, 0.125f)
                         .addEntry(Items.ARMOR_CHESTPLATE_STEEL, 1, 0.125f));
         ZOMBIE_ARMOR_BAGS.put(HumanArmorShape.LEGS,
                 new ArmorBag<>(HumanArmorShape.LEGS)
-                        .addEntry(null, 100, 1.0f)
+                        .addEntry(null, 400, 1.0f)
                         .addEntry(Items.ARMOR_LEGGINGS_LEATHER, 30, 0.8f)
                         .addEntry(Items.ARMOR_LEGGINGS_IRON, 10, 0.5f)
                         .addEntry(Items.ARMOR_LEGGINGS_DIAMOND, 5, 0.125f)
                         .addEntry(Items.ARMOR_LEGGINGS_STEEL, 1, 0.125f));
         ZOMBIE_ARMOR_BAGS.put(HumanArmorShape.BOOTS,
                 new ArmorBag<>(HumanArmorShape.BOOTS)
-                        .addEntry(null, 100, 1.0f)
+                        .addEntry(null, 400, 1.0f)
                         .addEntry(Items.ARMOR_BOOTS_LEATHER, 30, 0.8f)
                         .addEntry(Items.ARMOR_BOOTS_IRON, 10, 0.5f)
                         .addEntry(Items.ARMOR_BOOTS_DIAMOND, 5, 0.125f)
@@ -46,28 +46,28 @@ public abstract class ArmorBags {
     static {
         SKELETON_ARMOR_BAGS.put(HumanArmorShape.HEAD,
                 new ArmorBag<>(HumanArmorShape.HEAD)
-                        .addEntry(null, 100, 1.0f)
+                        .addEntry(null, 400, 1.0f)
                         .addEntry(Items.ARMOR_HELMET_LEATHER, 30, 0.8f)
                         .addEntry(Items.ARMOR_HELMET_IRON, 10, 0.5f)
                         .addEntry(Items.ARMOR_HELMET_DIAMOND, 5, 0.125f)
                         .addEntry(Items.ARMOR_HELMET_STEEL, 1, 0.125f));
         SKELETON_ARMOR_BAGS.put(HumanArmorShape.CHEST,
                 new ArmorBag<>(HumanArmorShape.CHEST)
-                        .addEntry(null, 100, 1.0f)
+                        .addEntry(null, 400, 1.0f)
                         .addEntry(Items.ARMOR_CHESTPLATE_LEATHER, 30, 0.8f)
                         .addEntry(Items.ARMOR_CHESTPLATE_IRON, 10, 0.5f)
                         .addEntry(Items.ARMOR_CHESTPLATE_DIAMOND, 5, 0.125f)
                         .addEntry(Items.ARMOR_CHESTPLATE_STEEL, 1, 0.125f));
         SKELETON_ARMOR_BAGS.put(HumanArmorShape.LEGS,
                 new ArmorBag<>(HumanArmorShape.LEGS)
-                        .addEntry(null, 100, 1.0f)
+                        .addEntry(null, 400, 1.0f)
                         .addEntry(Items.ARMOR_LEGGINGS_LEATHER, 30, 0.8f)
                         .addEntry(Items.ARMOR_LEGGINGS_IRON, 10, 0.5f)
                         .addEntry(Items.ARMOR_LEGGINGS_DIAMOND, 5, 0.125f)
                         .addEntry(Items.ARMOR_LEGGINGS_STEEL, 1, 0.125f));
         SKELETON_ARMOR_BAGS.put(HumanArmorShape.BOOTS,
                 new ArmorBag<>(HumanArmorShape.BOOTS)
-                        .addEntry(null, 100, 1.0f)
+                        .addEntry(null, 400, 1.0f)
                         .addEntry(Items.ARMOR_BOOTS_LEATHER, 30, 0.8f)
                         .addEntry(Items.ARMOR_BOOTS_IRON, 10, 0.5f)
                         .addEntry(Items.ARMOR_BOOTS_DIAMOND, 5, 0.125f)
diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
index ee2bdf387..cd0b376b2 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
@@ -250,7 +250,7 @@ public class Projectile extends Entity {
     public void waterTick() {
         for (int k = 0; k < 4; k++) {
             double particleDistance = 0.25F;
-            this.world.spawnParticle("bubble", this.x - this.xd * particleDistance, this.y - this.yd * particleDistance, this.z - this.zd * particleDistance, this.xd, this.yd, this.zd, 0);
+            this.world.spawnParticle("bubble", this.x - this.xd * particleDistance, this.y - this.yd * particleDistance, this.z - this.zd * particleDistance, this.xd, this.yd, this.zd, this.world.dimension.id);
         }
 
         this.projectileSpeed = 0.8F;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileCannonballBouncy.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileCannonballBouncy.java
index 214b20130..c4550ac05 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileCannonballBouncy.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileCannonballBouncy.java
@@ -111,7 +111,7 @@ public class ProjectileCannonballBouncy extends ProjectileCannonball {
         if (isInWater()) {
             for (int i = 0; i < 4; i++) {
                 double particleDistance = 0.25D;
-                this.world.spawnParticle("bubble", this.x - this.xd * particleDistance, this.y - this.yd * particleDistance, this.z - this.zd * particleDistance, this.xd, this.yd, this.zd, 0);
+                this.world.spawnParticle("bubble", this.x - this.xd * particleDistance, this.y - this.yd * particleDistance, this.z - this.zd * particleDistance, this.xd, this.yd, this.zd, this.world.dimension.id);
             }
 
             deceleration = 0.8F;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java
index 4decb46f8..7dd61afcc 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java
@@ -286,11 +286,11 @@ public class EntityBoat extends Entity {
                 if (this.random.nextBoolean()) {
                     double posX = (this.x - d12 * d18 * 0.8D) + d15 * d20;
                     double posZ = this.z - d15 * d18 * 0.8D - d12 * d20;
-                    this.world.spawnParticle("splash", posX, this.y - 0.125D, posZ, this.xd, this.yd, this.zd, 0);
+                    this.world.spawnParticle("splash", posX, this.y - 0.125D, posZ, this.xd, this.yd, this.zd, this.world.dimension.id);
                 } else {
                     double posX = this.x + d12 + d15 * d18 * 0.7D;
                     double posZ = (this.z + d15) - d12 * d18 * 0.7D;
-                    this.world.spawnParticle("splash", posX, this.y - 0.125D, posZ, this.xd, this.yd, this.zd, 0);
+                    this.world.spawnParticle("splash", posX, this.y - 0.125D, posZ, this.xd, this.yd, this.zd, this.world.dimension.id);
                 }
             }
 
diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
index 1f6db4191..f90a48dfa 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
@@ -335,21 +335,18 @@ public class EntityMinecart extends Entity implements Container {
         this.yo = this.y;
         this.zo = this.z;
         this.yd -= 0.04D;
-        int blockX = MathHelper.floor(this.x);
-        int blockY = MathHelper.floor(this.y);
-        int blockZ = MathHelper.floor(this.z);
         TilePos tilePos = new TilePos(this.x, this.y, this.z);
         TilePos queryPos = new TilePos();
         if (BlockLogicRail.isRailBlockAt(this.world, tilePos.down(queryPos))) {
-            blockY--;
+            tilePos.y--;
         }
         final double maxSpeed = 0.4D;
         boolean didFurnacePush = false;
         final double d5 = 0.0078125D;
         Block<?> block = this.world.getBlockType(tilePos);
-        if (block != null && block.getLogic() instanceof BlockLogicRail rail) {
+        if (block.getLogic() instanceof BlockLogicRail rail) {
             Vector3dc vec3d = getPos(this.x, this.y, this.z);
-            this.y = blockY;
+            this.y = tilePos.y;
             boolean onPoweredPoweredRail = false;
             boolean onUnpoweredPoweredRail = false;
             if (block == Blocks.RAIL_POWERED) {
@@ -359,7 +356,7 @@ public class EntityMinecart extends Entity implements Container {
             RailDirection railDirection = rail.getRailDirection(this.world, new TilePos(tilePos));
 
             if (railDirection.isSloped()) {
-                this.y = blockY + 1;
+                this.y = tilePos.y + 1;
             }
             if (railDirection == RailDirection.SLOPE_E) {
                 this.xd -= d5;
@@ -398,17 +395,17 @@ public class EntityMinecart extends Entity implements Container {
                     this.zd *= 0.5D;
                 }
             }
-            double d18 = (double) blockX + 0.5D + (double) nextRailTable[0][0] * 0.5D;
-            double d19 = (double) blockZ + 0.5D + (double) nextRailTable[0][2] * 0.5D;
-            double d20 = (double) blockX + 0.5D + (double) nextRailTable[1][0] * 0.5D;
-            double d21 = (double) blockZ + 0.5D + (double) nextRailTable[1][2] * 0.5D;
+            double d18 = tilePos.x + 0.5D + (double) nextRailTable[0][0] * 0.5D;
+            double d19 = tilePos.z + 0.5D + (double) nextRailTable[0][2] * 0.5D;
+            double d20 = tilePos.x + 0.5D + (double) nextRailTable[1][0] * 0.5D;
+            double d21 = tilePos.z + 0.5D + (double) nextRailTable[1][2] * 0.5D;
             d9 = d20 - d18;
             d10 = d21 - d19;
             double d17;
             if (d9 == 0.0D) {
-                d17 = this.z - (double) blockZ;
+                d17 = this.z - (double) tilePos.z;
             } else if (d10 == 0.0D) {
-                d17 = this.x - (double) blockX;
+                d17 = this.x - (double) tilePos.x;
             } else {
                 double d22 = this.x - d18;
                 double d24 = this.z - d19;
@@ -434,9 +431,9 @@ public class EntityMinecart extends Entity implements Container {
             _zd = MathHelper.clamp(_zd, -maxSpeed, maxSpeed);
 
             move(_xd, 0.0D, _zd);
-            if (nextRailTable[0][1] != 0 && MathHelper.floor(this.x) - blockX == nextRailTable[0][0] && MathHelper.floor(this.z) - blockZ == nextRailTable[0][2]) {
+            if (nextRailTable[0][1] != 0 && MathHelper.floor(this.x) - tilePos.x == nextRailTable[0][0] && MathHelper.floor(this.z) - tilePos.z == nextRailTable[0][2]) {
                 setPos(this.x, this.y + (double) nextRailTable[0][1], this.z);
-            } else if (nextRailTable[1][1] != 0 && MathHelper.floor(this.x) - blockX == nextRailTable[1][0] && MathHelper.floor(this.z) - blockZ == nextRailTable[1][2]) {
+            } else if (nextRailTable[1][1] != 0 && MathHelper.floor(this.x) - tilePos.x == nextRailTable[1][0] && MathHelper.floor(this.z) - tilePos.z == nextRailTable[1][2]) {
                 setPos(this.x, this.y + (double) nextRailTable[1][1], this.z);
             }
             if (this.passenger != null) {
@@ -478,10 +475,10 @@ public class EntityMinecart extends Entity implements Container {
             }
             int newBlockX = MathHelper.floor(this.x);
             int newBlockZ = MathHelper.floor(this.z);
-            if (newBlockX != blockX || newBlockZ != blockZ) {
+            if (newBlockX != tilePos.x || newBlockZ != tilePos.z) {
                 vel = Math.hypot(this.xd, this.zd);
-                this.xd = vel * (double) (newBlockX - blockX);
-                this.zd = vel * (double) (newBlockZ - blockZ);
+                this.xd = vel * (double) (newBlockX - tilePos.x);
+                this.zd = vel * (double) (newBlockZ - tilePos.z);
             }
             if (getType() == FURNACE_CART) {
                 double pushMagnitude = Math.hypot(this.xPush, this.zPush);
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 7b08f9f97..387d2b673 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
@@ -38,8 +38,10 @@ public class ItemEgg extends Item implements IDispensable {
 
     @Override
     public void onDispensed(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Random random, @NotNull Direction direction, double x, double y, double z) {
-        ProjectileEgg projectileEgg = new ProjectileEgg(world, x, y, z);
-        projectileEgg.setHeading(direction.getOffsetX(), direction.getOffsetY() + 0.1D, direction.getOffsetZ(), 1.1F, 6F);
-        world.entityJoinedWorld(projectileEgg);
+        if (selfStack.consumeItem(null)) {
+            ProjectileEgg projectileEgg = new ProjectileEgg(world, x, y, z);
+            projectileEgg.setHeading(direction.getOffsetX(), direction.getOffsetY() + 0.1D, direction.getOffsetZ(), 1.1F, 6F);
+            world.entityJoinedWorld(projectileEgg);
+        }
     }
 }
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 573cdc66f..663c88b78 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
@@ -115,8 +115,10 @@ public class ItemPebble extends Item implements IDispensable {
 
     @Override
     public void onDispensed(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Random random, @NotNull Direction direction, double x, double y, double z) {
-        ProjectilePebble projectilePebble = new ProjectilePebble(world, x, y, z);
-        projectilePebble.setHeading(direction.getOffsetX(), direction.getOffsetY() + 0.1D, direction.getOffsetZ(), 1.1F, 6F);
-        world.entityJoinedWorld(projectilePebble);
+        if (selfStack.consumeItem(null)) {
+            ProjectilePebble projectilePebble = new ProjectilePebble(world, x, y, z);
+            projectilePebble.setHeading(direction.getOffsetX(), direction.getOffsetY() + 0.1D, direction.getOffsetZ(), 1.1F, 6F);
+            world.entityJoinedWorld(projectilePebble);
+        }
     }
 }
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 fa54d5791..be24c7702 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
@@ -1,14 +1,19 @@
 package net.minecraft.core.item;
 
 import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.entity.projectile.ProjectileArrow;
+import net.minecraft.core.entity.projectile.ProjectileArrowGolden;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.player.inventory.slot.Slot;
+import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class ItemQuiver extends Item implements IArmorItem<HumanArmorShape> {
+import java.util.Random;
+
+public class ItemQuiver extends Item implements IArmorItem<HumanArmorShape>, IDispensable {
 
     public ItemQuiver(@NotNull String name, @NotNull String namespaceId, int id) {
         super(name, namespaceId, id);
@@ -113,4 +118,16 @@ public class ItemQuiver extends Item implements IArmorItem<HumanArmorShape> {
 	public @NotNull HumanArmorShape getArmorShape() {
 		return HumanArmorShape.CHEST;
 	}
+
+    @Override
+    public void onDispensed(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Random random, @NotNull Direction direction, double x, double y, double z) {
+        int count = getArrowCount(selfStack);
+        if (count > 0) {
+            final @NotNull ProjectileArrow arrow = new ProjectileArrow(world, x, y, z, 0);
+            arrow.setHeading(direction.getOffsetX(), direction.getOffsetY() + 0.1D, direction.getOffsetZ(), 1.1F, 6F);
+            arrow.setDoesArrowBelongToPlayer(true);
+            world.entityJoinedWorld(arrow);
+            setArrowCount(selfStack, count - 1);
+        }
+    }
 }
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 6ee7ee0c4..e1e5fa509 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,13 +1,18 @@
 package net.minecraft.core.item;
 
 import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.entity.projectile.ProjectileArrow;
+import net.minecraft.core.entity.projectile.ProjectileArrowPurple;
 import net.minecraft.core.enums.HumanArmorShape;
 import net.minecraft.core.item.material.ArmorMaterial;
+import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class ItemQuiverEndless extends Item implements IArmorItem<HumanArmorShape> {
+import java.util.Random;
+
+public class ItemQuiverEndless extends Item implements IArmorItem<HumanArmorShape>, IDispensable {
 
     public ItemQuiverEndless(@NotNull String name, @NotNull String namespaceId, int id) {
         super(name, namespaceId, id);
@@ -32,4 +37,11 @@ public class ItemQuiverEndless extends Item implements IArmorItem<HumanArmorShap
         return HumanArmorShape.CHEST;
     }
 
+    @Override
+    public void onDispensed(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Random random, @NotNull Direction direction, double x, double y, double z) {
+        final @NotNull ProjectileArrowPurple arrow = new ProjectileArrowPurple(world, x, y, z);
+        arrow.setHeading(direction.getOffsetX(), direction.getOffsetY() + 0.1D, direction.getOffsetZ(), 1.1F, 6F);
+        arrow.setDoesArrowBelongToPlayer(true);
+        world.entityJoinedWorld(arrow);
+    }
 }
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 03373e16e..3a7e3922b 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
@@ -38,8 +38,10 @@ public class ItemSnowball extends Item implements IDispensable {
 
     @Override
     public void onDispensed(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Random random, @NotNull Direction direction, double x, double y, double z) {
-        ProjectileSnowball snowball = new ProjectileSnowball(world, x, y, z);
-        snowball.setHeading(direction.getOffsetX(), direction.getOffsetY() + 0.1D, direction.getOffsetZ(), 1.1F, 6F);
-        world.entityJoinedWorld(snowball);
+        if (selfStack.consumeItem(null)) {
+            ProjectileSnowball snowball = new ProjectileSnowball(world, x, y, z);
+            snowball.setHeading(direction.getOffsetX(), direction.getOffsetY() + 0.1D, direction.getOffsetZ(), 1.1F, 6F);
+            world.entityJoinedWorld(snowball);
+        }
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/item/Items.java b/game/core/src/main/java/net/minecraft/core/item/Items.java
index cdb68cf16..cd467accd 100644
--- a/game/core/src/main/java/net/minecraft/core/item/Items.java
+++ b/game/core/src/main/java/net/minecraft/core/item/Items.java
@@ -5,6 +5,7 @@ import net.minecraft.core.achievement.stat.StatList;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.vehicle.EntityMinecart;
 import net.minecraft.core.enums.HumanArmorShape;
+import net.minecraft.core.enums.WolfArmorShape;
 import net.minecraft.core.item.material.ArmorMaterial;
 import net.minecraft.core.item.material.ToolMaterial;
 import net.minecraft.core.item.tag.ItemTags;
@@ -83,6 +84,7 @@ public final class Items {
     public static Item ARMOR_CHESTPLATE_GOLD;
     public static Item ARMOR_LEGGINGS_GOLD;
     public static Item ARMOR_BOOTS_GOLD;
+
     public static Item FLINT;
     public static Item FOOD_PORKCHOP_RAW;
     public static Item FOOD_PORKCHOP_COOKED;
@@ -208,6 +210,12 @@ public final class Items {
     public static Item RUBYGLASS_DUST;
     public static Item RUBYGLASS_CRYSTAL;
 
+    public static Item ARMOR_WOLF_LEATHER;
+    public static Item ARMOR_WOLF_CHAINMAIL;
+    public static Item ARMOR_WOLF_IRON;
+    public static Item ARMOR_WOLF_DIAMOND;
+    public static Item ARMOR_WOLF_GOLD;
+    public static Item ARMOR_WOLF_STEEL;
 
     private static boolean hasInit = false;
     public static void init(){
@@ -287,30 +295,30 @@ public final class Items {
         WHEAT = (new Item("wheat", "minecraft:item/wheat", 16424)).withTags(ItemTags.COWS_FAVOURITE_ITEM);
         FOOD_BREAD = (new ItemFood("food.bread", "minecraft:item/food_bread", 16425, 5, 12, false, 8));
 
-        ARMOR_HELMET_LEATHER = (new ItemArmor("armor.helmet.leather", "minecraft:item/armor_helmet_leather", 16426, ArmorMaterial.LEATHER, HumanArmorShape.HEAD));
-        ARMOR_CHESTPLATE_LEATHER = (new ItemArmor("armor.chestplate.leather", "minecraft:item/armor_chestplate_leather", 16427, ArmorMaterial.LEATHER, HumanArmorShape.CHEST));
-        ARMOR_LEGGINGS_LEATHER = (new ItemArmor("armor.leggings.leather", "minecraft:item/armor_leggings_leather", 16428, ArmorMaterial.LEATHER, HumanArmorShape.LEGS));
-        ARMOR_BOOTS_LEATHER = (new ItemArmor("armor.boots.leather", "minecraft:item/armor_boots_leather", 16429, ArmorMaterial.LEATHER, HumanArmorShape.BOOTS));
+        ARMOR_HELMET_LEATHER = (new ItemArmor<>("armor.helmet.leather", "minecraft:item/armor_helmet_leather", 16426, ArmorMaterial.LEATHER, HumanArmorShape.HEAD));
+        ARMOR_CHESTPLATE_LEATHER = (new ItemArmor<>("armor.chestplate.leather", "minecraft:item/armor_chestplate_leather", 16427, ArmorMaterial.LEATHER, HumanArmorShape.CHEST));
+        ARMOR_LEGGINGS_LEATHER = (new ItemArmor<>("armor.leggings.leather", "minecraft:item/armor_leggings_leather", 16428, ArmorMaterial.LEATHER, HumanArmorShape.LEGS));
+        ARMOR_BOOTS_LEATHER = (new ItemArmor<>("armor.boots.leather", "minecraft:item/armor_boots_leather", 16429, ArmorMaterial.LEATHER, HumanArmorShape.BOOTS));
 
-        ARMOR_HELMET_CHAINMAIL = (new ItemArmor("armor.helmet.chainmail", "minecraft:item/armor_helmet_chainmail", 16430, ArmorMaterial.CHAINMAIL, HumanArmorShape.HEAD));
-        ARMOR_CHESTPLATE_CHAINMAIL = (new ItemArmor("armor.chestplate.chainmail", "minecraft:item/armor_chestplate_chainmail", 16431, ArmorMaterial.CHAINMAIL, HumanArmorShape.CHEST));
-        ARMOR_LEGGINGS_CHAINMAIL = (new ItemArmor("armor.leggings.chainmail", "minecraft:item/armor_leggings_chainmail", 16432, ArmorMaterial.CHAINMAIL, HumanArmorShape.LEGS));
-        ARMOR_BOOTS_CHAINMAIL = (new ItemArmor("armor.boots.chainmail", "minecraft:item/armor_boots_chainmail", 16433, ArmorMaterial.CHAINMAIL, HumanArmorShape.BOOTS));
+        ARMOR_HELMET_CHAINMAIL = (new ItemArmor<>("armor.helmet.chainmail", "minecraft:item/armor_helmet_chainmail", 16430, ArmorMaterial.CHAINMAIL, HumanArmorShape.HEAD));
+        ARMOR_CHESTPLATE_CHAINMAIL = (new ItemArmor<>("armor.chestplate.chainmail", "minecraft:item/armor_chestplate_chainmail", 16431, ArmorMaterial.CHAINMAIL, HumanArmorShape.CHEST));
+        ARMOR_LEGGINGS_CHAINMAIL = (new ItemArmor<>("armor.leggings.chainmail", "minecraft:item/armor_leggings_chainmail", 16432, ArmorMaterial.CHAINMAIL, HumanArmorShape.LEGS));
+        ARMOR_BOOTS_CHAINMAIL = (new ItemArmor<>("armor.boots.chainmail", "minecraft:item/armor_boots_chainmail", 16433, ArmorMaterial.CHAINMAIL, HumanArmorShape.BOOTS));
 
-        ARMOR_HELMET_IRON = (new ItemArmor("armor.helmet.iron", "minecraft:item/armor_helmet_iron", 16434, ArmorMaterial.IRON, HumanArmorShape.HEAD));
-        ARMOR_CHESTPLATE_IRON = (new ItemArmor("armor.chestplate.iron", "minecraft:item/armor_chestplate_iron", 16435, ArmorMaterial.IRON, HumanArmorShape.CHEST));
-        ARMOR_LEGGINGS_IRON = (new ItemArmor("armor.leggings.iron", "minecraft:item/armor_leggings_iron", 16436, ArmorMaterial.IRON, HumanArmorShape.LEGS));
-        ARMOR_BOOTS_IRON = (new ItemArmor("armor.boots.iron", "minecraft:item/armor_boots_iron", 16437, ArmorMaterial.IRON, HumanArmorShape.BOOTS));
+        ARMOR_HELMET_IRON = (new ItemArmor<>("armor.helmet.iron", "minecraft:item/armor_helmet_iron", 16434, ArmorMaterial.IRON, HumanArmorShape.HEAD));
+        ARMOR_CHESTPLATE_IRON = (new ItemArmor<>("armor.chestplate.iron", "minecraft:item/armor_chestplate_iron", 16435, ArmorMaterial.IRON, HumanArmorShape.CHEST));
+        ARMOR_LEGGINGS_IRON = (new ItemArmor<>("armor.leggings.iron", "minecraft:item/armor_leggings_iron", 16436, ArmorMaterial.IRON, HumanArmorShape.LEGS));
+        ARMOR_BOOTS_IRON = (new ItemArmor<>("armor.boots.iron", "minecraft:item/armor_boots_iron", 16437, ArmorMaterial.IRON, HumanArmorShape.BOOTS));
 
-        ARMOR_HELMET_DIAMOND = (new ItemArmor("armor.helmet.diamond", "minecraft:item/armor_helmet_diamond", 16438, ArmorMaterial.DIAMOND, HumanArmorShape.HEAD)).withTags(ItemTags.IS_FIRE_PROOF);
-        ARMOR_CHESTPLATE_DIAMOND = (new ItemArmor("armor.chestplate.diamond", "minecraft:item/armor_chestplate_diamond", 16439, ArmorMaterial.DIAMOND, HumanArmorShape.CHEST)).withTags(ItemTags.IS_FIRE_PROOF);
-        ARMOR_LEGGINGS_DIAMOND = (new ItemArmor("armor.leggings.diamond", "minecraft:item/armor_leggings_diamond", 16440, ArmorMaterial.DIAMOND, HumanArmorShape.LEGS)).withTags(ItemTags.IS_FIRE_PROOF);
-        ARMOR_BOOTS_DIAMOND = (new ItemArmor("armor.boots.diamond", "minecraft:item/armor_boots_diamond", 16441, ArmorMaterial.DIAMOND, HumanArmorShape.BOOTS)).withTags(ItemTags.IS_FIRE_PROOF);
+        ARMOR_HELMET_DIAMOND = (new ItemArmor<>("armor.helmet.diamond", "minecraft:item/armor_helmet_diamond", 16438, ArmorMaterial.DIAMOND, HumanArmorShape.HEAD)).withTags(ItemTags.IS_FIRE_PROOF);
+        ARMOR_CHESTPLATE_DIAMOND = (new ItemArmor<>("armor.chestplate.diamond", "minecraft:item/armor_chestplate_diamond", 16439, ArmorMaterial.DIAMOND, HumanArmorShape.CHEST)).withTags(ItemTags.IS_FIRE_PROOF);
+        ARMOR_LEGGINGS_DIAMOND = (new ItemArmor<>("armor.leggings.diamond", "minecraft:item/armor_leggings_diamond", 16440, ArmorMaterial.DIAMOND, HumanArmorShape.LEGS)).withTags(ItemTags.IS_FIRE_PROOF);
+        ARMOR_BOOTS_DIAMOND = (new ItemArmor<>("armor.boots.diamond", "minecraft:item/armor_boots_diamond", 16441, ArmorMaterial.DIAMOND, HumanArmorShape.BOOTS)).withTags(ItemTags.IS_FIRE_PROOF);
 
-        ARMOR_HELMET_GOLD = (new ItemArmor("armor.helmet.gold", "minecraft:item/armor_helmet_gold", 16442, ArmorMaterial.GOLD, HumanArmorShape.HEAD));
-        ARMOR_CHESTPLATE_GOLD = (new ItemArmor("armor.chestplate.gold", "minecraft:item/armor_chestplate_gold", 16443, ArmorMaterial.GOLD, HumanArmorShape.CHEST));
-        ARMOR_LEGGINGS_GOLD = (new ItemArmor("armor.leggings.gold", "minecraft:item/armor_leggings_gold", 16444, ArmorMaterial.GOLD, HumanArmorShape.LEGS));
-        ARMOR_BOOTS_GOLD = (new ItemArmor("armor.boots.gold", "minecraft:item/armor_boots_gold", 16445, ArmorMaterial.GOLD, HumanArmorShape.BOOTS));
+        ARMOR_HELMET_GOLD = (new ItemArmor<>("armor.helmet.gold", "minecraft:item/armor_helmet_gold", 16442, ArmorMaterial.GOLD, HumanArmorShape.HEAD));
+        ARMOR_CHESTPLATE_GOLD = (new ItemArmor<>("armor.chestplate.gold", "minecraft:item/armor_chestplate_gold", 16443, ArmorMaterial.GOLD, HumanArmorShape.CHEST));
+        ARMOR_LEGGINGS_GOLD = (new ItemArmor<>("armor.leggings.gold", "minecraft:item/armor_leggings_gold", 16444, ArmorMaterial.GOLD, HumanArmorShape.LEGS));
+        ARMOR_BOOTS_GOLD = (new ItemArmor<>("armor.boots.gold", "minecraft:item/armor_boots_gold", 16445, ArmorMaterial.GOLD, HumanArmorShape.BOOTS));
         FLINT = (new Item("flint", "minecraft:item/flint", 16446));
         FOOD_PORKCHOP_RAW = (new ItemFood("food.porkchop.raw", "minecraft:item/food_porkchop_raw", 16447, 3, 16, true, 4));
         FOOD_PORKCHOP_COOKED = (new ItemFood("food.porkchop.cooked", "minecraft:item/food_porkchop_cooked", 16448, 8, 16, true, 4));
@@ -366,10 +374,10 @@ public final class Items {
         RECORD_WAIT = (new ItemDiscMusic("record.wait", "minecraft:item/record_wait", 18394, "record.wait", "C418"));
         RECORD_DOG = (new ItemDiscMusic("record.dog", "minecraft:item/record_dog", 18395, "record.dog", "C418"));
         NETHERCOAL = (new Item("nethercoal", "minecraft:item/nethercoal", 16488));
-        ARMOR_HELMET_STEEL = (new ItemArmor("armor.helmet.steel", "minecraft:item/armor_helmet_steel", 16489, ArmorMaterial.STEEL, HumanArmorShape.HEAD)).withTags(ItemTags.IS_BLAST_PROOF);
-        ARMOR_CHESTPLATE_STEEL = (new ItemArmor("armor.chestplate.steel", "minecraft:item/armor_chestplate_steel", 16490, ArmorMaterial.STEEL, HumanArmorShape.CHEST)).withTags(ItemTags.IS_BLAST_PROOF);
-        ARMOR_LEGGINGS_STEEL = (new ItemArmor("armor.leggings.steel", "minecraft:item/armor_leggings_steel", 16491, ArmorMaterial.STEEL, HumanArmorShape.LEGS)).withTags(ItemTags.IS_BLAST_PROOF);
-        ARMOR_BOOTS_STEEL = (new ItemArmor("armor.boots.steel", "minecraft:item/armor_boots_steel", 16492, ArmorMaterial.STEEL, HumanArmorShape.BOOTS)).withTags(ItemTags.IS_BLAST_PROOF);
+        ARMOR_HELMET_STEEL = (new ItemArmor<>("armor.helmet.steel", "minecraft:item/armor_helmet_steel", 16489, ArmorMaterial.STEEL, HumanArmorShape.HEAD)).withTags(ItemTags.IS_BLAST_PROOF);
+        ARMOR_CHESTPLATE_STEEL = (new ItemArmor<>("armor.chestplate.steel", "minecraft:item/armor_chestplate_steel", 16490, ArmorMaterial.STEEL, HumanArmorShape.CHEST)).withTags(ItemTags.IS_BLAST_PROOF);
+        ARMOR_LEGGINGS_STEEL = (new ItemArmor<>("armor.leggings.steel", "minecraft:item/armor_leggings_steel", 16491, ArmorMaterial.STEEL, HumanArmorShape.LEGS)).withTags(ItemTags.IS_BLAST_PROOF);
+        ARMOR_BOOTS_STEEL = (new ItemArmor<>("armor.boots.steel", "minecraft:item/armor_boots_steel", 16492, ArmorMaterial.STEEL, HumanArmorShape.BOOTS)).withTags(ItemTags.IS_BLAST_PROOF);
 
         TOOL_SWORD_STEEL = (new ItemToolSword("tool.sword.steel", "minecraft:item/tool_sword_steel", 16493, ToolMaterial.steel)).withTags(ItemTags.PREVENT_CREATIVE_MINING, ItemTags.IS_BLAST_PROOF);
         TOOL_SHOVEL_STEEL = (new ItemToolShovel("tool.shovel.steel", "minecraft:item/tool_shovel_steel", 16494, ToolMaterial.steel)).withTags(ItemTags.IS_BLAST_PROOF);
@@ -435,5 +443,12 @@ public final class Items {
         WAND_NBT = new ItemWandNBT("wand.nbt", "minecraft:item/wand_nbt", 16553);
         RUBYGLASS_DUST = (new Item("rubyglass.crystal.cracked", "minecraft:item/rubyglass_crystal_cracked", 16554));
         RUBYGLASS_CRYSTAL = (new Item("rubyglass.crystal.pure", "minecraft:item/rubyglass_crystal_pure", 16555));
+
+        ARMOR_WOLF_LEATHER = new ItemArmor<>("armor.wolf.leather", "minecraft:item/armor_wolf_leather", 16556, ArmorMaterial.LEATHER, WolfArmorShape.BODY);
+        ARMOR_WOLF_CHAINMAIL = new ItemArmor<>("armor.wolf.chainmail", "minecraft:item/armor_wolf_chainmail", 16557, ArmorMaterial.CHAINMAIL, WolfArmorShape.BODY);
+        ARMOR_WOLF_IRON = new ItemArmor<>("armor.wolf.iron", "minecraft:item/armor_wolf_iron", 16558, ArmorMaterial.IRON, WolfArmorShape.BODY);
+        ARMOR_WOLF_DIAMOND = new ItemArmor<>("armor.wolf.diamond", "minecraft:item/armor_wolf_diamond", 16559, ArmorMaterial.DIAMOND, WolfArmorShape.BODY);
+        ARMOR_WOLF_GOLD = new ItemArmor<>("armor.wolf.gold", "minecraft:item/armor_wolf_gold", 16560, ArmorMaterial.GOLD, WolfArmorShape.BODY);
+        ARMOR_WOLF_STEEL = new ItemArmor<>("armor.wolf.steel", "minecraft:item/armor_wolf_steel", 16561, ArmorMaterial.STEEL, WolfArmorShape.BODY);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java
index e387859df..f84c19180 100644
--- a/game/core/src/main/java/net/minecraft/core/world/World.java
+++ b/game/core/src/main/java/net/minecraft/core/world/World.java
@@ -1187,7 +1187,9 @@ public abstract class World implements MutableWorldSource {
                 this.updateEnoughPlayersSleepingFlag(null);
             }
 
-            this.getChunkFromChunkCoords(i, j).addEntity(entity);
+            if (!this.getChunkFromChunkCoords(i, j).addEntity(entity)) {
+                this.getChunkFromChunkCoords(i, j).addEntity(entity);
+            }
             this.entities.add(entity);
             this.obtainEntitySkin(entity);
             return true;
@@ -2269,7 +2271,7 @@ public abstract class World implements MutableWorldSource {
         int i = 0;
         for (int j = 0, entitiesSize = this.entities.size(); j < entitiesSize; j++) {
             final Entity entity = this.entities.get(j);
-            if (clazz.isAssignableFrom(entity.getClass())) {
+            if (clazz.isAssignableFrom(entity.getClass()) && !entity.isSpawnCapExempt()) {
                 i++;
             }
         }
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
index df17a90bd..472c9b5ed 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
@@ -547,13 +547,12 @@ public class Chunk {
         return this.getRawSkyLightLevel(new ChunkTilePos(x, y, z), subtractedSkyLight);
     }
 
-    public void addEntity(final @NotNull Entity entity) {
+    public boolean addEntity(final @NotNull Entity entity) {
         this.hasEntities = true;
         this.isModified = true;
         final @NotNull ChunkPos entityChunkPos = new ChunkPos(entity);
         if (!entityChunkPos.equals(this.pos)) {
-            LOGGER.warn("Wrong location! {}", entity);
-            Thread.dumpStack();
+            return false;
         }
         int section = MathHelper.clamp(MathHelper.floor(entity.y / 16D), 0, CHUNK_SECTIONS - 1);
         entity.addedToChunk = true;
@@ -561,6 +560,8 @@ public class Chunk {
         entity.chunkCoordY = section;
         entity.chunkCoordZ = this.pos.z;
         getSection(section).addEntity(entity);
+
+        return true;
     }
 
     public void removeEntity(@NotNull Entity entity) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
index 102286a8c..c02252ab1 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
@@ -76,7 +76,7 @@ public class EmptyChunk extends Chunk {
     }
 
     @Override
-    public void addEntity(final @NotNull Entity entity) { }
+    public boolean addEntity(final @NotNull Entity entity) { return true; }
 
     @Override
     public void removeEntity(final @NotNull Entity entity) { }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/CavesLargeFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/CavesLargeFeature.java
index 107a88dc5..7c0ea46d8 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/CavesLargeFeature.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/CavesLargeFeature.java
@@ -120,7 +120,7 @@ public class CavesLargeFeature extends LargeFeature {
             }
 
             // Check if we've hit the ocean, and if so, stop generating
-            if (world.getWorldType().getOceanBlockId() != 0) {
+            if (world.getWorldType().getOceanBlockIds()[0] != 0) {
                 boolean hasHitOcean = false;
                 for (int x = minX; !hasHitOcean && x < maxX; x++) {
                     for (int z = minZ; !hasHitOcean && z < maxZ; z++) {
@@ -130,8 +130,11 @@ public class CavesLargeFeature extends LargeFeature {
                             if (y < this.minY || y >= this.maxY) {
                                 continue;
                             }
-                            if (blockId == world.getWorldType().getOceanBlockId()) {
-                                hasHitOcean = true;
+                            for (int id : world.getWorldType().getOceanBlockIds()) {
+                                if (blockId == id) {
+                                    hasHitOcean = true;
+                                    break;
+                                }
                             }
                             if (y != minY - 1 && x != minX && x != maxX - 1 && z != minZ && z != maxZ - 1) {
                                 y = minY;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java
index 06cabca62..e348ee30b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/RetroCavesLargeFeature.java
@@ -119,7 +119,7 @@ public class RetroCavesLargeFeature extends LargeFeature {
             }
 
             // Check if we've hit the ocean, and if so, stop generating
-            if (world.getWorldType().getOceanBlockId() != 0) {
+            if (world.getWorldType().getOceanBlockIds().length != 0) {
                 boolean hasHitOcean = false;
                 for (int x = minX; !hasHitOcean && x < maxX; x++) {
                     for (int z = minZ; !hasHitOcean && z < maxZ; z++) {
@@ -129,8 +129,11 @@ public class RetroCavesLargeFeature extends LargeFeature {
                             if (y < this.minY || y >= this.maxY) {
                                 continue;
                             }
-                            if (blockId == world.getWorldType().getOceanBlockId()) {
-                                hasHitOcean = true;
+                            for (int id : world.getWorldType().getOceanBlockIds()) {
+                                if (blockId == id) {
+                                    hasHitOcean = true;
+                                    break;
+                                }
                             }
                             if (y != minY - 1 && x != minX && x != maxX - 1 && z != minZ && z != maxZ - 1) {
                                 y = minY;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
index 0d102f7c5..59ee6e7f5 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
@@ -127,7 +127,7 @@ public class ChunkGeneratorClassic
                     if (y < newHeight) {
                         blockID = this.world.getWorldType().getFillerBlockId();
                     } else if (y < this.world.getWorldType().getOceanY()) {
-                        blockID = this.world.getWorldType().getOceanBlockId();
+                        blockID = this.world.getWorldType().getOceanBlockIds()[0];
                     }
 
                     if (y == 0) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
index 9090cd118..cc925031c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
@@ -40,7 +40,7 @@ public class SurfaceGeneratorNether
         int chunkX = chunk.pos.x;
         int chunkZ = chunk.pos.z;
 
-        int oceanBlock = this.world.getWorldType().getOceanBlockId();
+        int oceanBlock = this.world.getWorldType().getOceanBlockIds()[0];
         int worldFillBlock = this.world.getWorldType().getFillerBlockId();
 
         Random rand = new Random((long) chunkX * 0x4F9939F508L + (long) chunkZ * 0x1EF1565BD5L);
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
index 95e4720c9..97317851a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
@@ -58,7 +58,7 @@ public class SurfaceGeneratorOverworld
         int chunkX = chunk.pos.x;
         int chunkZ = chunk.pos.z;
 
-        int oceanBlock = world.getWorldType().getOceanBlockId();
+        int oceanBlock = world.getWorldType().getOceanBlockIds()[0];
         int worldFillBlock = world.getWorldType().getFillerBlockId();
 
         Random rand = new Random((long) chunkX * 0x4F9939F508L + (long) chunkZ * 0x1EF1565BD5L);
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/TerrainGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/TerrainGeneratorOverworld.java
index 8838e954b..4d7d5bf1d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/TerrainGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/TerrainGeneratorOverworld.java
@@ -47,7 +47,7 @@ public class TerrainGeneratorOverworld
         }
         else if (y >= minY && y < minY + type.getOceanY())
         {
-            return type.getOceanBlockId();
+            return type.getOceanBlockIds()[0];
         }
 
         return 0;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
index f719594bc..e53cd9eee 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
@@ -233,8 +233,8 @@ public class ChunkDecoratorOverworldHell
 
         final int minY = world.getWorldType().getMinY(world);
 
-        if (world.getBlockId(worldX, minY + world.getWorldType().getOceanY() - 1, worldZ) == world.getWorldType().getOceanBlockId()) {
-            world.setBlockWithNotify(worldX, minY + world.getWorldType().getOceanY() - 1, worldZ, world.getWorldType().getOceanBlockId());
+        if (world.getBlockId(worldX, minY + world.getWorldType().getOceanY() - 1, worldZ) == world.getWorldType().getOceanBlockIds()[0]) {
+            world.setBlockWithNotify(worldX, minY + world.getWorldType().getOceanY() - 1, worldZ, world.getWorldType().getOceanBlockIds()[0]);
         }
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java
index ba9b554b7..9581f8d1c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java
@@ -121,16 +121,19 @@ public class WorldFeatureLabyrinth extends WorldFeature
         chestLoot.addEntry(new WeightedRandomLootObject(Items.HANDCANNON_UNLOADED.getDefaultStack()), 4.5);
 
         chestLoot.addEntry(new WeightedRandomLootObject(Items.ARMOR_HELMET_CHAINMAIL.getDefaultStack())
-                        .setRandomMetadata(Items.ARMOR_HELMET_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_HELMET_CHAINMAIL.getMaxDamage()), 20);
+            .setRandomMetadata(Items.ARMOR_HELMET_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_HELMET_CHAINMAIL.getMaxDamage()), 20);
 
         chestLoot.addEntry(new WeightedRandomLootObject(Items.ARMOR_CHESTPLATE_CHAINMAIL.getDefaultStack())
-                .setRandomMetadata(Items.ARMOR_CHESTPLATE_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_CHESTPLATE_CHAINMAIL.getMaxDamage()), 20);
+            .setRandomMetadata(Items.ARMOR_CHESTPLATE_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_CHESTPLATE_CHAINMAIL.getMaxDamage()), 20);
 
         chestLoot.addEntry(new WeightedRandomLootObject(Items.ARMOR_LEGGINGS_CHAINMAIL.getDefaultStack())
-                .setRandomMetadata(Items.ARMOR_LEGGINGS_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_LEGGINGS_CHAINMAIL.getMaxDamage()), 20);
+            .setRandomMetadata(Items.ARMOR_LEGGINGS_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_LEGGINGS_CHAINMAIL.getMaxDamage()), 20);
 
         chestLoot.addEntry(new WeightedRandomLootObject(Items.ARMOR_BOOTS_CHAINMAIL.getDefaultStack())
-                .setRandomMetadata(Items.ARMOR_BOOTS_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_BOOTS_CHAINMAIL.getMaxDamage()), 20);
+            .setRandomMetadata(Items.ARMOR_BOOTS_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_BOOTS_CHAINMAIL.getMaxDamage()), 20);
+
+        chestLoot.addEntry(new WeightedRandomLootObject(Items.ARMOR_WOLF_CHAINMAIL.getDefaultStack())
+            .setRandomMetadata(Items.ARMOR_WOLF_CHAINMAIL.getMaxDamage()/2, Items.ARMOR_WOLF_CHAINMAIL.getMaxDamage()), 20);
 
         chestLoot.addEntry(new WeightedRandomLootObject(Items.INGOT_STEEL_CRUDE.getDefaultStack()), 10);
         chestLoot.addEntry(new WeightedRandomLootObject(null), 892);
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
index 13061a6d8..2acd63740 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
@@ -2,6 +2,7 @@ package net.minecraft.core.world.type;
 
 import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
+import net.minecraft.core.block.Blocks;
 import net.minecraft.core.data.tag.ITaggable;
 import net.minecraft.core.data.tag.Tag;
 import net.minecraft.core.world.World;
@@ -41,7 +42,7 @@ public abstract class WorldType
     private final int maxY;
     private final int maxPortalY;
     private final int oceanY;
-    private final int oceanBlockId;
+    private final int[] oceanBlockIds;
     private final int fillerBlockId;
     private final int dayNightCycleTicks;
     private final boolean mayRespawn;
@@ -66,7 +67,14 @@ public abstract class WorldType
             this.maxPortalY = this.maxY;
         }
         this.oceanY = properties.oceanY;
-        this.oceanBlockId = properties.oceanBlock == null ? 0 : properties.oceanBlock.id();
+        if (properties.oceanBlocks.isEmpty()) {
+            this.oceanBlockIds = new int[] { Blocks.AIR.id() };
+        } else {
+            this.oceanBlockIds = new int[properties.oceanBlocks.size()];
+            for (int i = 0; i < properties.oceanBlocks.size(); i++) {
+                this.oceanBlockIds[i] = properties.oceanBlocks.get(i).id();
+            }
+        }
         this.fillerBlockId = properties.fillerBlock == null ? 0 : properties.fillerBlock.id();
         this.dayNightCycleTicks = properties.dayNightCycleTicks;
         this.mayRespawn = properties.mayRespawn;
@@ -122,8 +130,8 @@ public abstract class WorldType
         return oceanY;
     }
 
-    public int getOceanBlockId() {
-        return oceanBlockId;
+    public int[] getOceanBlockIds() {
+        return oceanBlockIds;
     }
 
     public int getFillerBlockId() {
@@ -314,7 +322,7 @@ public abstract class WorldType
         private int maxY = 255;
         private Integer maxPortalY = null;
         private int oceanY = 128;
-        private @Nullable Block<?> oceanBlock = null;
+        private @NotNull List<Block<?>> oceanBlocks = new ArrayList<>();
         private @Nullable Block<?> fillerBlock = null;
         private int dayNightCycleTicks = Global.DAY_LENGTH_TICKS;
         private boolean mayRespawn = false;
@@ -389,8 +397,9 @@ public abstract class WorldType
             return this;
         }
 
-        public @NotNull Properties oceanBlock(Block<?> oceanBlock) {
-            this.oceanBlock = oceanBlock;
+        public @NotNull Properties oceanBlocks(Block<?>... oceanBlocks) {
+            this.oceanBlocks.clear();
+            this.oceanBlocks.addAll(Arrays.asList(oceanBlocks));
             return this;
         }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
index 026509a68..539333335 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
@@ -73,7 +73,7 @@ public abstract class WorldTypes {
         new WorldTypeOverworldFloating(
             WorldTypeOverworld.defaultProperties("worldType.overworld.floating")
                 .bounds(0, 255, 0)
-                .oceanBlock(null)
+                .oceanBlocks()
                 .withTags(WorldTypeTags.OVERWORLD)
         )
     );
@@ -125,7 +125,7 @@ public abstract class WorldTypes {
                     .withSingleSeason(Seasons.OVERWORLD_HELL)
                     .build()
                 )
-                .oceanBlock(Blocks.FLUID_LAVA_STILL)
+                .oceanBlocks(Blocks.FLUID_LAVA_STILL)
                 .fillerBlock(Blocks.STONE)
                 .allowRespawn()
                 .bounds(0, 127, 64)
@@ -160,7 +160,7 @@ public abstract class WorldTypes {
         new WorldTypeOverworldInland(
             WorldTypeOverworld.defaultProperties("worldType.overworld.inland")
                 .bounds(0, 255, 0)
-                .oceanBlock(null)
+                .oceanBlocks()
                 .withTags(WorldTypeTags.OVERWORLD)
         )
     );
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java b/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
index 3ef04360f..da9180de2 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java
@@ -19,7 +19,7 @@ public class WorldTypeNether
     public static Properties defaultProperties(String translationKey) {
         return Properties.of(translationKey)
                 .brightnessRamp(getLightRamp())
-                .oceanBlock(Blocks.FLUID_LAVA_STILL)
+                .oceanBlocks(Blocks.FLUID_LAVA_STILL, Blocks.FLUID_WATER_STILL)
                 .fillerBlock(Blocks.COBBLE_NETHERRACK)
                 .withCeiling()
                 .bounds(0, 255, 64 + 32);
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
index 453d831db..b7dd03970 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
@@ -37,7 +37,7 @@ public class WorldTypeOverworld extends WorldType {
                 .withSeasonInCycle(Seasons.OVERWORLD_WINTER, 14)
                 .build()
             )
-            .oceanBlock(Blocks.FLUID_WATER_STILL)
+            .oceanBlocks(Blocks.FLUID_WATER_STILL)
             .fillerBlock(Blocks.STONE)
             .allowRespawn();
     }
diff --git a/game/core/src/main/resources/lang/en_US/item.lang b/game/core/src/main/resources/lang/en_US/item.lang
index 0368825e8..0b340f245 100644
--- a/game/core/src/main/resources/lang/en_US/item.lang
+++ b/game/core/src/main/resources/lang/en_US/item.lang
@@ -497,4 +497,17 @@ item.rubyglass.crystal.pure.name=Rubyglass
 item.rubyglass.crystal.pure.desc=A shard of charged Rubyglass crystal, brimming with energy. Perfectly intact and slightly translucent.
 
 item.sulfur.name=Sulfur
-item.sulfur.desc=Highly flammable and yellow. Packs a punch.
\ No newline at end of file
+item.sulfur.desc=Highly flammable and yellow. Packs a punch.
+
+item.armor.wolf.leather.name=Leather Wolf Armor
+item.armor.wolf.leather.desc=Keep your best friend safe with this soft leather shell.
+item.armor.wolf.chainmail.name=Chainmail Wolf Armor
+item.armor.wolf.chainmail.desc=Keep your best friend safe with this tough chainmail shell. Can be repaired.
+item.armor.wolf.iron.name=Iron Wolf Armor
+item.armor.wolf.iron.desc=Keep your best friend safe with this strong iron shell.
+item.armor.wolf.diamond.name=Diamond Wolf Armor
+item.armor.wolf.diamond.desc=Keep your best friend safe with this fancy diamond shell.
+item.armor.wolf.gold.name=Gold Wolf Armor
+item.armor.wolf.gold.desc=Keep your best friend fabulous with this shiny gold shell.
+item.armor.wolf.steel.name=Steel Wolf Armor
+item.armor.wolf.steel.desc=Keep your best friend safe with this sturdy steel shell.
diff --git a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
index 944946b8d..19b25d8a9 100644
--- a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
+++ b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java
@@ -31,6 +31,7 @@ class WorkbenchGenerator {
         generateChestPlates();
         generateLeggings();
         generateBoots();
+        generateWolfArmors();
 
         generateBlockCompression();
         generateBlockDecompression();
@@ -686,6 +687,22 @@ class WorkbenchGenerator {
         boots.addInput('X', Items.INGOT_STEEL).create("steel_boots", Items.ARMOR_BOOTS_STEEL.getDefaultStack());
     }
 
+    private static void generateWolfArmors() {
+        RecipeBuilderShaped armor = RecipeBuilder.Shaped(CORE_NAMESPACE)
+            .setAllowMirrored(true)
+            .setShape(
+                " XX",
+                "XXX",
+                "X X"
+            );
+
+        armor.addInput('X', Items.LEATHER).create("leather_wolf_armor", Items.ARMOR_WOLF_LEATHER.getDefaultStack());
+        armor.addInput('X', Items.INGOT_IRON).create("iron_wolf_armor", Items.ARMOR_WOLF_IRON.getDefaultStack());
+        armor.addInput('X', Items.INGOT_GOLD).create("gold_wolf_armor", Items.ARMOR_WOLF_GOLD.getDefaultStack());
+        armor.addInput('X', Items.DIAMOND).create("diamond_wolf_armor", Items.ARMOR_WOLF_DIAMOND.getDefaultStack());
+        armor.addInput('X', Items.INGOT_STEEL).create("steel_wolf_armor", Items.ARMOR_WOLF_STEEL.getDefaultStack());
+    }
+
     private static void generateBlockCompression() {
         RecipeBuilderShaped block = RecipeBuilder.Shaped(CORE_NAMESPACE)
             .setShape(
@@ -1348,6 +1365,7 @@ class WorkbenchGenerator {
          Registries.RECIPES.WORKBENCH.register("repair_chainmail_leggings",    new RecipeEntryRepairable(Items.ARMOR_LEGGINGS_CHAINMAIL.getDefaultStack(),     new RecipeSymbol(Items.CHAINLINK.getDefaultStack())));
          Registries.RECIPES.WORKBENCH.register("repair_chainmail_chestplate",  new RecipeEntryRepairable(Items.ARMOR_CHESTPLATE_CHAINMAIL.getDefaultStack(),   new RecipeSymbol(Items.CHAINLINK.getDefaultStack())));
          Registries.RECIPES.WORKBENCH.register("repair_chainmail_helmet",      new RecipeEntryRepairable(Items.ARMOR_HELMET_CHAINMAIL.getDefaultStack(),       new RecipeSymbol(Items.CHAINLINK.getDefaultStack())));
+         Registries.RECIPES.WORKBENCH.register("repair_chainmail_wolf",        new RecipeEntryRepairable(Items.ARMOR_WOLF_CHAINMAIL.getDefaultStack(),         new RecipeSymbol(Items.CHAINLINK.getDefaultStack())));
     }
 
     private static void generateToolRecipes() {
