diff --git a/game/client/src/main/java/net/betterthanadventure/utils/BiomeFinder.java b/game/client/src/main/java/net/betterthanadventure/utils/BiomeFinder.java
index 1f97baf51..bda9839ad 100644
--- a/game/client/src/main/java/net/betterthanadventure/utils/BiomeFinder.java
+++ b/game/client/src/main/java/net/betterthanadventure/utils/BiomeFinder.java
@@ -25,6 +25,7 @@ import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.save.LevelStorage;
 import net.minecraft.core.world.save.SaveFormatBase;
 import net.minecraft.core.world.save.mcregion.SaveFormat19134;
+import net.minecraft.core.world.save.mcregion.SaveFormat19135;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypes;
 import org.jetbrains.annotations.NotNull;
@@ -498,7 +499,7 @@ public class BiomeFinder implements MinecraftAccessor {
 			biomeProvider = worldType.createBiomeProvider(WorldEmpty.INSTANCE);
 			world = null;
 		} else {
-			SaveFormatBase saveFormat = new SaveFormat19134(worldFolder.getParentFile());
+			SaveFormatBase saveFormat = new SaveFormat19135(worldFolder.getParentFile());
 			LevelStorage levelStorage = saveFormat.getLevelStorage(worldFolder.getName(), false);
 			world = new World(levelStorage, Dimension.OVERWORLD);
 			biomeProvider = worldType.createBiomeProvider(world);
diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java
index b26feec9f..c211066d1 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -146,6 +146,7 @@ import net.minecraft.core.world.save.SaveConverters;
 import net.minecraft.core.world.save.SaveFormatBase;
 import net.minecraft.core.world.save.SaveFormats;
 import net.minecraft.core.world.save.mcregion.SaveFormat19134;
+import net.minecraft.core.world.save.mcregion.SaveFormat19135;
 import net.minecraft.core.world.settings.WorldConfiguration;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -476,7 +477,7 @@ public class Minecraft
 
         this.resolution.setScale(GameSettings.GUI_SCALE.value);
 
-        SaveFormatBase handlerBase = new SaveFormat19134(new File(this.mcDataDir, "saves"));
+        SaveFormatBase handlerBase = new SaveFormat19135(new File(this.mcDataDir, "saves"));
         handlerBase.factory = LevelStorageClientSP::new;
         this.saveFormat = handlerBase;
         I18n.initialize(GameSettings.LANGUAGE.value);
diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
index 52068315a..74b32badc 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
@@ -33,6 +33,7 @@ import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.vehicle.EntityBoat;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.client.net.command.ClientCommandSource;
 import net.minecraft.core.player.Session;
@@ -51,6 +52,7 @@ import org.jetbrains.annotations.Nullable;
 import org.joml.primitives.AABBdc;
 import org.slf4j.Logger;
 
+import java.util.IllegalFormatException;
 import java.util.function.Function;
 
 public class PlayerLocal extends Player {
@@ -453,13 +455,36 @@ public class PlayerLocal extends Player {
     }
 
     @Override
-    public void sendMessage(String message) {
-        this.mc.hudIngame.addChatMessage(message);
+    public void sendMessage(boolean isStatus, @Nullable TextFormatting.Base format, @NotNull String message) {
+        if (format != null) message = format.toString() + message;
+        if (!isStatus) {
+            this.mc.hudIngame.addChatMessage(message);
+        } else {
+            HudComponents.DYNAMIC_TOOLTIP.setString(message);
+        }
     }
 
     @Override
-    public void sendStatusMessage(String message) {
-        HudComponents.DYNAMIC_TOOLTIP.setString(message);
+    public void sendMessageTranslated(boolean isStatus, @Nullable TextFormatting.Base format,
+        @NotNull String key, @NotNull String... args
+    ) {
+        final var fmt = I18n.getInstance().translateKey(key);
+        if (fmt == null) return;
+
+        String message;
+        try {
+            message = String.format(fmt, (Object[])args);
+        } catch (IllegalFormatException e) {
+            LOGGER.error("Failed to translate message with key '{}': ", key, e);
+            return;
+        }
+
+        if (format != null) message = format.toString() + message;
+        if (!isStatus) {
+            this.mc.hudIngame.addChatMessage(message);
+        } else {
+            HudComponents.DYNAMIC_TOOLTIP.setString(message);
+        }
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java
index 96eda5d1a..b0cc54832 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java
@@ -9,7 +9,7 @@ import net.minecraft.core.entity.EntityItem;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.entity.vehicle.EntityBoat;
 import net.minecraft.core.net.packet.PacketBoatControl;
-import net.minecraft.core.net.packet.PacketChat;
+import net.minecraft.core.net.packet.PacketMessage;
 import net.minecraft.core.net.packet.PacketPlayerConfig;
 import net.minecraft.core.net.packet.PacketUpdatePlayerState;
 import net.minecraft.core.net.packet.PacketMovePlayer;
@@ -167,7 +167,7 @@ public class PlayerLocalMultiplayer extends PlayerLocal implements Player.Player
     @Override
 	public void sendChatMessage(String s)
     {
-        sendQueue.addToSendQueue(new PacketChat(s, AES.clientKeyChain));
+        sendQueue.addToSendQueue(new PacketMessage(s, AES.clientKeyChain));
     	addToSendHistory(s);
     }
     
diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerRemote.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerRemote.java
index e13fb7229..fc4ce6ff5 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerRemote.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerRemote.java
@@ -3,6 +3,7 @@ package net.minecraft.client.entity.player;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.util.helper.MathHelper;
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.world.World;
@@ -11,6 +12,9 @@ import net.minecraft.core.util.helper.GetSkinUrlThread;
 
 import java.util.UUID;
 
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
 public class PlayerRemote extends Player
 {
     private int lerpSteps;
@@ -137,13 +141,9 @@ public class PlayerRemote extends Player
 	public void animate4()
     {
     }
-	@Override
-	public void sendMessage(String message) {
-		
-	}
 
-	@Override
-	public void sendStatusMessage(String message) {
-		
-	}
+    @Override
+    public void sendMessage(boolean isStatus, @Nullable TextFormatting.Base format, @NotNull String message) {}
+    @Override
+    public void sendMessageTranslated(boolean isStatus, @Nullable TextFormatting.Base format, @NotNull String key, @NotNull String... args) {}
 }
diff --git a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
index 8f7eb7252..aec3987af 100644
--- a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
+++ b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
@@ -46,6 +46,7 @@ import net.minecraft.core.enums.ArtType;
 import net.minecraft.core.item.ItemMap;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
+import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.NetworkManager;
 import net.minecraft.core.net.PlayerProfile;
 import net.minecraft.core.net.entity.NetEntityHandler;
@@ -531,31 +532,56 @@ public class PacketHandlerClient extends PacketHandler {
     }
 
     @Override
-    public void handleChat(@NotNull PacketChat packet) {
+    public void handleMessage(@NotNull PacketMessage packet) {
         String message;
-        if (packet.encrypted) {
-            try {
-                message = AES.decrypt(packet.message, AES.clientKeyChain);
-            } catch (Exception e) {
-                throw new RuntimeException(PacketChat.ENCRYPTION_ERROR_MESSAGE, e);
-            }
-        } else {
+        if (!packet.encrypted) {
             message = packet.message;
+        } else try {
+            message = AES.decrypt(packet.message, AES.clientKeyChain);
+        } catch (Exception e) {
+            throw new RuntimeException(PacketMessage.ENCRYPTION_ERROR_MESSAGE, e);
         }
 
-        int type = packet.type;
-        if (type == 1) {
-            HudComponents.DYNAMIC_TOOLTIP.setString(message);
-        } else {
-            this.mc.hudIngame.addChatMessage(message);
+        if (packet.format != null) message = packet.format.toString() + message;
+
+        switch (packet.type) {
+            case PacketMessage.TYPE_CHAT -> this.mc.hudIngame.addChatMessage(message);
+            case PacketMessage.TYPE_STATUS -> HudComponents.DYNAMIC_TOOLTIP.setString(message);
         }
     }
 
-    public void handlePlayerJoin(PacketChat chatPacket) {
+    @Override
+    public void handleTranslatableMessage(@NotNull PacketMessageTranslatable packet) {
+        if (packet.key < 0 || packet.key >= PacketMessageTranslatable.ID2KEY_MAP.length)
+            return;
+
+        final String key = PacketMessageTranslatable.ID2KEY_MAP[packet.key];
+
+        final var fmt = I18n.getInstance().translateKey(key);
+        if (fmt == null) return;
+
+        String message;
+        try {
+            message = String.format(fmt, (Object[])packet.args);
+        } catch (IllegalFormatException e) {
+            LOGGER.error("Failed to translate message with key '{}': ", key, e);
+            return;
+        }
+
+        if (packet.format != null) message = packet.format.toString() + message;
+
+        switch (packet.type) {
+            case PacketMessage.TYPE_CHAT -> this.mc.hudIngame.addChatMessage(message);
+            case PacketMessage.TYPE_STATUS -> HudComponents.DYNAMIC_TOOLTIP.setString(message);
+        }
+    }
+
+    // what is this?
+    public void handlePlayerJoin(PacketMessage chatPacket) {
         this.mc.hudIngame.addChatMessage(chatPacket.message);
     }
 
-    public void handlePlayerLeave(PacketChat chatPacket) {
+    public void handlePlayerLeave(PacketMessage chatPacket) {
         this.mc.hudIngame.addChatMessage(chatPacket.message);
     }
 
@@ -930,14 +956,6 @@ public class PacketHandlerClient extends PacketHandler {
         this.mc.currentWorld.triggerEvent(packetBlockEvent.xLocation, packetBlockEvent.yLocation, packetBlockEvent.zLocation, packetBlockEvent.index, packetBlockEvent.data);
     }
 
-    @Override
-    public void handleBedMessage(@NotNull PacketBedMessage packetBedMessage) {
-        int state = packetBedMessage.bedState;
-        if (state >= 0 && state < PacketBedMessage.BED_MESSAGE_KEYS.length && PacketBedMessage.BED_MESSAGE_KEYS[state] != null) {
-            this.mc.thePlayer.sendTranslatedChatMessage(PacketBedMessage.BED_MESSAGE_KEYS[state]);
-        }
-    }
-
     @Override
     public void handleMapData(@NotNull PacketMapData packetMapData) {
         if (packetMapData.itemId == Items.MAP.id) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
index d2da4d3e4..e75c5ebd0 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
@@ -123,7 +123,7 @@ public final class BlockModelDispatcher
         addDispatch(new BlockModelGeneric<>(Blocks.BOOKSHELF_PLANKS_OAK, loadDataModel("minecraft:block/bookshelf")));
 
         addDispatch(new BlockModelGenericWool<>(Blocks.WOOL, loadDataModel("minecraft:block/wool/white")));
-        addDispatch(new BlockModelGenericRope<>(Blocks.ROPE));
+        addDispatch(new BlockModelGenericRope<>(Blocks.ROPE).forceCullSelf(true));
 
 
         addDispatch(new BlockModelGeneric<>(Blocks.BRICK_CLAY, loadDataModel("minecraft:block/brick_clay")));
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java
index a5be6ed64..23c959528 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java
@@ -12,6 +12,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
+import net.minecraft.core.world.type.WorldType;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.useless.dragonfly.DisplayPos;
@@ -93,6 +94,14 @@ public class BlockModelGeneric<T extends BlockLogic> extends BlockModel<T> {
     private final @NotNull TilePos queryPos = new TilePos();
     public boolean cullSide(@NotNull WorldSource worldSource, @NotNull TilePosc blockPos, @Nullable Direction direction) {
         if (direction != null) {
+            // Cull world ceiling and floors
+            WorldType worldType = worldSource.getWorldType();
+            if (worldType.hasCeiling() && direction == Direction.UP && blockPos.y() >= worldType.getMaxY(worldSource)) {
+                return true;
+            } else if (direction == Direction.DOWN && blockPos.y() <= worldType.getMinY(worldSource)) {
+                return true;
+            }
+
             TilePos shifted = blockPos.add(direction, this.queryPos);
             if (this.forceCullSelf) {
                 return worldSource.getBlockType(shifted) == this.block || worldSource.isBlockOpaqueCube(shifted);
diff --git a/game/core/src/main/java/net/minecraft/core/Global.java b/game/core/src/main/java/net/minecraft/core/Global.java
index 9dceda8e8..e52cbd558 100644
--- a/game/core/src/main/java/net/minecraft/core/Global.java
+++ b/game/core/src/main/java/net/minecraft/core/Global.java
@@ -8,7 +8,7 @@ public class Global
 	public static final int DAY_LENGTH_TICKS = 24000;
 	public static final @NotNull String VERSION = Version.BUILD_CHANNEL.modifyVersionString(Version.VERSION);
 	public static final @NotNull BuildChannel BUILD_CHANNEL = Version.BUILD_CHANNEL;
-	public static final int CURRENT_SAVE_VERSION = 19134;
+	public static final int CURRENT_SAVE_VERSION = 19135;
 	public static final int CURRENT_CHUNK_VERSION = 3;
 	public static boolean isServer = false;
 	public static final boolean DISABLE_OLD_WORLDS = false;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java
index c2f57246a..90017d1ce 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java
@@ -75,7 +75,7 @@ public class BlockLogicBed
                 if (!p.isPlayerSleeping()) continue;
                 final var otherBedPos = Objects.requireNonNull(p.bedTilePos);
                 if (otherBedPos.equals(footPos)) {
-                    player.sendTranslatedChatMessage("bed.occupied");
+                    player.sendMessageTranslated("messages.bed.occupied");
                     return true;
                 }
             }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java
index 690af327d..9fadd0ef0 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java
@@ -367,7 +367,7 @@ public class BlockLogicChest
         if (direction == null) return meta;
 
         meta = meta & (~directionBits);
-        meta = meta | ((direction.ordinal() << directionOffset) & directionBits);
+        meta = meta | ((direction.legacyIndex() << directionOffset) & directionBits);
 
         return meta;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
index eefc919c8..b803851d5 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
@@ -74,7 +74,7 @@ public class BlockLogicFenceGate
 
     @Override
     public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) {
-        final int direction = mob.getHorizontalPlacementDirection(side).legacyHorizontalIndex();
+        final int direction = mob.getHorizontalPlacementDirection(side).legacyIndex();
         final int meta = world.getBlockData(tilePos);
         world.setBlockDataNotify(tilePos, direction | (meta & ~MASK_DIRECTION));
     }
@@ -84,7 +84,7 @@ public class BlockLogicFenceGate
         if (!side.isHorizontal()) {
             side = Side.NORTH;
         }
-        final int direction = side.direction().legacyHorizontalIndex();
+        final int direction = side.direction().legacyIndex();
         final int meta = world.getBlockData(tilePos);
         world.setBlockDataNotify(tilePos, direction | (meta & ~MASK_DIRECTION));
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java
index 5deb76c64..f6be2916f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java
@@ -139,19 +139,20 @@ public abstract class TileEntity implements ICarriable
         tilePos.y = blockY + side.offsetY();
         tilePos.z = blockZ + side.offsetZ();
 
-        Block<?> currentBlock = world.getBlock(tilePos.x, tilePos.y, tilePos.z);
+        Block<?> currentBlock = world.getBlockType(tilePos);
         if (currentBlock != null && !currentBlock.hasTag(BlockTags.PLACE_OVERWRITES)) return false;
-        world.setBlockAndMetadata(tilePos.x, tilePos.y, tilePos.z, carriedBlock.blockId, carriedBlock.metadata);
+        world.setBlockTypeData(tilePos, carriedBlock.block(), carriedBlock.metadata);
+        world.markBlockNeedsUpdate(tilePos);
 
         worldObj = world;
         this.validate();
-        world.removeBlockTileEntity(tilePos.x, tilePos.y, tilePos.z);
-        world.setTileEntity(tilePos.x, tilePos.y, tilePos.z, this);
-        Block<?> b = world.getBlock(tilePos.x, tilePos.y, tilePos.z);
-        if (b != null && holder instanceof Mob) {
-            b.onBlockPlacedByMob(world, tilePos.x, tilePos.y, tilePos.z, side, (Mob) holder, xPlaced, yPlaced);
+        world.removeTileEntity(tilePos);
+        world.setTileEntity(tilePos, this);
+        Block<?> b = world.getBlockType(tilePos);
+        if (b != null && holder instanceof Mob mob) {
+            b.onPlacedByMob(world, tilePos, side, mob, xPlaced, yPlaced);
         }
-        final boolean isSignal = Blocks.getBlock(carriedBlock.blockId).isSignalSource();
+        final boolean isSignal = carriedBlock.block().isSignalSource();
         world.notifyBlocksInRadiusOfNeighborChange((isSignal) ? 2 : 1, tilePos, currentBlock);
         return true;
     }
@@ -171,11 +172,11 @@ public abstract class TileEntity implements ICarriable
 
     // TODO: clean this up in the future tileEntity refactor
     protected @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) {
-        Block<?> currentBlock = world.getBlock(tilePos.x, tilePos.y, tilePos.z);
-        int currentMeta = world.getBlockMetadata(tilePos.x, tilePos.y, tilePos.z);
-        world.removeBlockTileEntity(tilePos.x, tilePos.y, tilePos.z);
-        world.setBlockRaw(tilePos.x, tilePos.y, tilePos.z, 0);
-        world.markBlockDirty(tilePos);
+        Block<?> currentBlock = world.getBlockType(tilePos);
+        int currentMeta = world.getBlockData(tilePos);
+        world.removeTileEntity(tilePos);
+        world.setBlockTypeRaw(tilePos, Blocks.AIR);
+        world.markBlockNeedsUpdate(tilePos);
         final boolean isSignal = this.getBlock().isSignalSource();
         world.notifyBlocksInRadiusOfNeighborChange((isSignal) ? 2 : 1, tilePos, currentBlock);
         this.worldObj = null;
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 1295c8448..af4f33c56 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
@@ -611,39 +611,36 @@ public abstract class Mob extends Entity {
             this.vehicle = null;
         }
         this.world.sendTrackedEntityStatusUpdatePacket(this, (byte) 3);
-        if (sendDeathMessage(entityKilledBy)) {
-            this.world.sendGlobalMessage(getDeathMessage(entityKilledBy));
-        }
-    }
-
-    public boolean sendDeathMessage(Entity entityKilledBy) {
+        
+        if (this.world.isClientSide) return;
+        if (!this.sendsDeathMessage(entityKilledBy)) return;
+
+        this.world.sendGlobalMessageTranslated(
+            TextFormatting.Base.RED,
+            this.getDeathMessageKey(entityKilledBy),
+            (entityKilledBy == null) ? new String[] {
+                TextFormatting.scoped(Entity.getNameFromEntity(this, true)),
+            } : new String[] {
+                TextFormatting.scoped(Entity.getNameFromEntity(this, true)),
+                TextFormatting.scoped(Entity.getNameFromEntity(entityKilledBy, true)),
+            });
+    }
+
+    public boolean sendsDeathMessage(Entity entityKilledBy) {
         return !this.nickname.isEmpty();
     }
 
-    public String getDeathMessage(Entity entityKilledBy) {
-        final TextFormatting deathMsgColor = TextFormatting.RED;
-        final TextFormatting reset = TextFormatting.RESET;
-        String name = Entity.getNameFromEntity(this, true);
-        if (entityKilledBy != null) {
-            String murdererName = Entity.getNameFromEntity(entityKilledBy, true);
-            return String.format("%s%s was killed by %s%s", name, deathMsgColor, reset, murdererName);
-        }
-        if (this.world.isMaterialInBB(this.bb, Materials.LAVA)) {
-            return String.format("%s%s swam in lava.", name, deathMsgColor);
-        }
-        if (this.world.getBlockId(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z)) == Blocks.SPIKES.id()) {
-            return String.format("%s%s got impaled.", name, deathMsgColor);
-        }
-        if (this.fallDistance > 0) {
-            return String.format("%s%s broke their legs.", name, deathMsgColor);
-        }
-        if (this.airSupply <= 0) {
-            return String.format("%s%s suffocated.", name, deathMsgColor);
-        }
-        if (this.remainingFireTicks > 0) {
-            return String.format("%s%s was incinerated.", name, deathMsgColor);
-        }
-        return String.format("%s%s died", name, deathMsgColor);
+    public @NotNull String getDeathMessageKey(@Nullable Entity entityKilledBy) {
+        if (entityKilledBy != null) return "messages.death.mob.killed_by";
+        if (this.isInLava()) return "messages.death.mob.lava";
+
+        final var tilePos = new TilePos(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z));
+        if (this.world.getBlockType(tilePos) == Blocks.SPIKES) return "messages.death.mob.spikes";
+
+        if (this.fallDistance > 0) return "messages.death.mob.fall";
+        if (this.airSupply <= 0) return "messages.death.mob.drowned";
+        if (this.remainingFireTicks > 0) return "messages.death.mob.fire";
+        return "messages.death.mob.generic";
     }
 
     protected void dropDeathItems() {
@@ -1215,9 +1212,8 @@ public abstract class Mob extends Entity {
     }
 
     public @NotNull Direction getHorizontalPlacementDirection(Side side, PlacementMode mode) {
-        if (this.rotationLockHorizontal != null && this.rotationLockHorizontal != Direction.NONE) {
-            return this.rotationLockHorizontal;
-        }
+        if (this.rotationLockHorizontal != null) return this.rotationLockHorizontal;
+
         if (this.placementModeOverride != PlacementMode.DEFAULT) {
             mode = this.placementModeOverride;
         }
@@ -1232,9 +1228,8 @@ public abstract class Mob extends Entity {
     }
 
     public @NotNull Direction getPlacementDirection(final @Nullable Side side, @NotNull PlacementMode mode) {
-        if (this.rotationLock != null && this.rotationLock != Direction.NONE) {
-            return this.rotationLock;
-        }
+        if (this.rotationLock != null) return this.rotationLock;
+
         if (this.placementModeOverride != PlacementMode.DEFAULT) {
             mode = this.placementModeOverride;
         }
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 a4665d0a3..b2f036ecd 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
@@ -73,8 +73,8 @@ public class MobWolf
     }
 
     @Override
-    public boolean sendDeathMessage(Entity entityKilledBy) {
-        return super.sendDeathMessage(entityKilledBy) || isWolfTamed();
+    public boolean sendsDeathMessage(Entity entityKilledBy) {
+        return super.sendsDeathMessage(entityKilledBy) || isWolfTamed();
     }
 
 //    @Override
diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
index bb0386cfb..0c833f89f 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -12,6 +12,7 @@ import net.minecraft.core.entity.monster.MobCreeper;
 import net.minecraft.core.entity.monster.MobSlime;
 import net.minecraft.core.entity.monster.MobSpider;
 import net.minecraft.core.entity.monster.MobZombiePig;
+import net.minecraft.core.entity.projectile.Projectile;
 import net.minecraft.core.entity.projectile.ProjectileArrow;
 import net.minecraft.core.enums.*;
 import net.minecraft.core.achievement.Achievements;
@@ -31,9 +32,6 @@ import net.minecraft.core.entity.projectile.ProjectileFireball;
 import net.minecraft.core.entity.projectile.ProjectileArrowGolden;
 import net.minecraft.core.entity.vehicle.EntityBoat;
 import net.minecraft.core.entity.vehicle.EntityMinecart;
-import net.minecraft.core.enums.ArtType;
-import net.minecraft.core.enums.EnumDropCause;
-import net.minecraft.core.enums.EnumSleepStatus;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemArmor;
 import net.minecraft.core.item.ItemStack;
@@ -708,112 +706,79 @@ public abstract class Player
     }
 
     @Override
-    public boolean sendDeathMessage(Entity entityKilledBy) {
+    public boolean sendsDeathMessage(Entity entityKilledBy) {
         return true;
     }
-
+    
     @Override
-    public String getDeathMessage(Entity entityKilledBy) {
-        if (this.random.nextInt(8000) == 666) {
-            return getDisplayName() + deathMsgColor + " was killed by Herobrine.";
-        }
-        if (entityKilledBy instanceof MobZombie) {
-            if (entityKilledBy instanceof MobZombiePig) {
-                return getDisplayName() + deathMsgColor + " discovered mob mentality.";
-            } else {
-                return getDisplayName() + deathMsgColor + " became a zombie.";
-            }
-        }
-        if (entityKilledBy instanceof MobCreeper) {
-            return deathMsgColor + "Aw man, " + getDisplayName() + deathMsgColor + " didn't see the creeper.";
-        }
-        if (entityKilledBy instanceof MobSkeleton) {
-            return getDisplayName() + deathMsgColor + " was a victim of aimbot.";
+    public @NotNull String getDeathMessageKey(@Nullable Entity entityKilledBy) {
+        if (this.random.nextInt(8000) == 666) return "messages.death.player.herobrine";
+
+        if (entityKilledBy == null) {
+            if (this.isInLava()) return "messages.death.player.lava";
+    
+            final var tilePos = new TilePos(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z));
+            if (this.world.getBlockType(tilePos) == Blocks.SPIKES) return "messages.death.player.spikes";
+    
+            if (this.fallDistance > 0) return "messages.death.player.fall";
+            if (this.airSupply <= 0) return "messages.death.player.drowned";
+            if (this.remainingFireTicks > 0) return "messages.death.player.fire";
         }
-        if (entityKilledBy instanceof MobSpider) {
-            return getDisplayName() + deathMsgColor + " spent too much time on the web.";
-        }
-        if (entityKilledBy instanceof MobGhast) {
-            return getDisplayName() + deathMsgColor + " didn't return the serve.";
-        }
-        if (entityKilledBy instanceof MobSlime) {
-            return getDisplayName() + deathMsgColor + " was slimed.";
-        }
-        if (entityKilledBy instanceof MobWolf) {
-            return getDisplayName() + deathMsgColor + " got what they deserved.";
-        }
-        if (entityKilledBy instanceof ProjectileArrowGolden) {
-            if (((ProjectileArrowGolden) entityKilledBy).owner instanceof Player) {
-                if (((Player) ((ProjectileArrowGolden) entityKilledBy).owner).uuid.equals(this.uuid)) {
-                    return getDisplayName() + deathMsgColor + " got gold in their eye.";
-                }
-                return getDisplayName() + deathMsgColor + " got pierced by " +
-                    ((ProjectileArrow) entityKilledBy).owner.getDisplayName() + deathMsgColor + ".";
-            } else {
-                return getDisplayName() + deathMsgColor + " is Swiss cheese.";
-            }
-        }
-        if (entityKilledBy instanceof ProjectileArrow) {
-            if (((ProjectileArrow) entityKilledBy).owner instanceof MobSkeleton) {
-                return getDisplayName() + deathMsgColor + " was a victim of aimbot.";
-            } else if (((ProjectileArrow) entityKilledBy).owner instanceof Player) {
-                if (((Player) ((ProjectileArrow) entityKilledBy).owner).uuid.equals(this.uuid)) {
-                    return getDisplayName() + deathMsgColor + " lost a game of Russian roulette.";
-                }
-                return getDisplayName() + deathMsgColor + " got 360 noscoped by " +
-                    ((ProjectileArrow) entityKilledBy).owner.getDisplayName() + deathMsgColor + ".";
-            } else {
-                return getDisplayName() + deathMsgColor + " is a pincushion.";
-            }
-        }
-        if (entityKilledBy instanceof ProjectileCannonball) {
-            if (((ProjectileCannonball) entityKilledBy).owner instanceof Player) {
-                if (((Player) ((ProjectileCannonball) entityKilledBy).owner).uuid.equals(this.uuid)) {
-                    return getDisplayName() + deathMsgColor + " jumped too high.";
-                }
-                return getDisplayName() + deathMsgColor + " was fragmented by " +
-                    ((ProjectileCannonball) entityKilledBy).owner.getDisplayName() + deathMsgColor + ".";
+        
+        else murder: {
+            if (entityKilledBy instanceof EntityPrimedTNT) return "messages.death.player.tnt";
+            if (entityKilledBy instanceof EntityLightning) return "messages.death.player.lightning";
+            if (entityKilledBy instanceof MobZombie) return (entityKilledBy instanceof MobZombiePig)
+                ? "messages.death.player.killed_by.zombie_pig"
+                : "messages.death.player.killed_by.zombie";
+            if (entityKilledBy instanceof MobCreeper) return "messages.death.player.killed_by.creeper";
+            if (entityKilledBy instanceof MobSkeleton) return "messages.death.player.killed_by.skeleton";
+            if (entityKilledBy instanceof MobSpider) return "messages.death.player.killed_by.spider";
+            if (entityKilledBy instanceof MobGhast) return "messages.death.player.killed_by.ghast";
+            if (entityKilledBy instanceof MobSlime) return "messages.death.player.killed_by.slime";
+            if (entityKilledBy instanceof MobWolf) return "messages.death.player.killed_by.wolf";
+            if (entityKilledBy instanceof MobGiant) return "messages.death.player.killed_by.giant";
+            if (entityKilledBy instanceof MobPig) return "messages.death.player.killed_by.pig";
+            
+            if (!(entityKilledBy instanceof Projectile projectile)) break murder;
+
+            // TODO correct key for other sources
+            if (projectile instanceof ProjectileFireball) return "messages.death.player.killed_by.ghast";
+
+            final var archer = projectile.owner;
+            final boolean isPlayer, isSuicide; 
+            if (!(archer instanceof Player player)) {
+                isPlayer = isSuicide = false;
             } else {
-                return getDisplayName() + deathMsgColor + " was detonated remotely.";
-            }
-        }
-        if (entityKilledBy instanceof ProjectileFireball) {
-            return getDisplayName() + deathMsgColor + " didn't return the serve.";
-        }
-        if (entityKilledBy instanceof MobGiant) {
-            return getDisplayName() + deathMsgColor + " was killed by- wait, what?!";
-        }
-        if (entityKilledBy instanceof EntityLightning) {
-            return getDisplayName() + deathMsgColor + " was grounded.";
-        }
-        if (entityKilledBy instanceof EntityPrimedTNT) {
-            return getDisplayName() + deathMsgColor + " was killed by Popbob.";
-        }
-        if (entityKilledBy instanceof Player) {
-            return getDisplayName() + deathMsgColor + " was backstabbed by " + ((Player) entityKilledBy).getDisplayName() + deathMsgColor + ".";
-        }
-        if (entityKilledBy instanceof MobPig) {
-            return getDisplayName() + deathMsgColor + " is *really* bad at Minecraft.";
-        } else {
-            if (this.world.getBlockMaterial(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z)) == Materials.LAVA) {
-                return getDisplayName() + deathMsgColor + " got lost in the sauce.";
-            }
-            if (this.world.getBlockId(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z)) == Blocks.SPIKES.id()) {
-                return getDisplayName() + deathMsgColor + " fell for the trap.";
-            }
-            if (this.fallDistance > 0) {
-                return getDisplayName() + deathMsgColor + " forgot to tie their laces.";
+                isPlayer = true;
+                isSuicide = player.uuid == this.uuid;
             }
-            if (this.airSupply <= 0) {
-                return getDisplayName() + deathMsgColor + " is sleeping with the fishes.";
+
+            if (projectile instanceof ProjectileArrow) {
+                if (archer instanceof MobSkeleton) return "messages.death.player.killed_by.skeleton";
+                final var isGolden = projectile instanceof ProjectileArrowGolden;
+                if (isSuicide) return (isGolden)
+                    ? "messages.death.player.killed_by.arrow_golden_suicide"
+                    : "messages.death.player.killed_by.arrow_suicide";
+                if (isPlayer) return (isGolden)
+                    ? "messages.death.player.killed_by.arrow_golden_player"
+                    : "messages.death.player.killed_by.arrow_player";
+                return (isGolden)
+                    ? "messages.death.player.killed_by.arrow_golden"
+                    : "messages.death.player.killed_by.arrow";
             }
-            if (this.remainingFireTicks > 0) {
-                return getDisplayName() + deathMsgColor + " was cooked well done.";
+
+            if (projectile instanceof ProjectileCannonball) {
+                if (isSuicide) return "messages.death.player.killed_by.cannonball_suicide";
+                if (isPlayer) return "messages.death.player.killed_by.cannonball_player";
+                return "messages.death.player.killed_by.cannonball";
             }
-            return getDisplayName() + deathMsgColor + " died mysteriously.";
         }
+
+        return "messages.death.player.generic";
     }
 
+
     @Override
     protected void dropDeathItems() {
     }
@@ -1326,22 +1291,22 @@ public abstract class Player
             }
             if (this.bedTilePos == null || !this.bedTilePos.equals(new TilePos(x, y, z))) {
                 if (this.playerSpawnPoint == null || !this.playerSpawnPoint.equals(new TilePos(x, y, z))) {
-                    sendTranslatedChatMessage("bed.setSpawn");
+                    sendMessageTranslated("messages.bed.setSpawn");
                     setPlayerSpawnPoint(new TilePos(x, y, z));
                 }
             }
             if (!this.world.getGameRuleValue(GameRules.ALLOW_SLEEPING)) {
-                sendStatusMessage(I18n.getInstance().translateKey("bed.noAllowSleeping"));
+                sendStatusMessageTranslated("messages.bed.noAllowSleeping");
                 return EnumSleepStatus.DISABLED_BY_GAMERULE;
             }
 
             if (this.world.isDaytime() && this.world.getCurrentWeather() != Weathers.OVERWORLD_STORM) {
-                sendStatusMessage(I18n.getInstance().translateKey("bed.noSleep"));
+                sendStatusMessageTranslated("messages.bed.noSleep");
                 return EnumSleepStatus.NOT_POSSIBLE_NOW;
             }
 
             if (SpawnerMobs.isUnsafeToSleep(this.world, this)) {
-                sendStatusMessage(I18n.getInstance().translateKey("bed.unsafeToSleep"));
+                sendStatusMessageTranslated("messages.bed.unsafeToSleep");
                 return EnumSleepStatus.NOT_SAFE;
             }
         }
@@ -1487,19 +1452,36 @@ public abstract class Player
     /**
      * Translate the string and send it to this player
      */
+    @Deprecated
     public void sendTranslatedChatMessage(String message) {
         sendMessage(I18n.getInstance().translateKey(message));
     }
 
+    public abstract void sendMessage(boolean isStatus, @Nullable TextFormatting.Base format, @NotNull String message);
+    public abstract void sendMessageTranslated(boolean isStatus, @Nullable TextFormatting.Base format, @NotNull String key, @NotNull String... args);
+
+    public void sendMessage(@Nullable TextFormatting.Base format, @NotNull String message) { this.sendMessage(false, format, message); }
+    public void sendStatusMessage(@Nullable TextFormatting.Base format, String message) { this.sendMessage(true, format, message); }
     /**
      * Send a string to this player, displayed in chat
      */
-    public abstract void sendMessage(String message);
-
+    public void sendMessage(@NotNull String message) { this.sendMessage(null, message); }
     /**
      * Send a string to this player, displayed above the hotbar
      */
-    public abstract void sendStatusMessage(String message);
+    public void sendStatusMessage(@NotNull String message) { this.sendStatusMessage(null, message); }
+
+    public void sendMessageTranslated(@Nullable TextFormatting.Base format, @NotNull String key, @NotNull String... args) { this.sendMessageTranslated(false, format, key, args); }
+    public void sendStatusMessageTranslated(@Nullable TextFormatting.Base format, @NotNull String key, @NotNull String... args) { this.sendMessageTranslated(true, format, key, args); }
+    /**
+     * Send text to this player, translated client-side and displayed in chat
+     */
+    public void sendMessageTranslated(@NotNull String key, @NotNull String... args) { this.sendMessageTranslated(null, key, args); }
+    /**
+     * Send text to this player, translated client-side and displayed above the hotbar
+     */
+    public void sendStatusMessageTranslated(@NotNull String key, @NotNull String... args) { this.sendStatusMessageTranslated(null, key, args); }
+
 
     @Override
     public ItemStack getHeldItem() {
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBed.java b/game/core/src/main/java/net/minecraft/core/item/ItemBed.java
index 4f8df4f8c..04610b5b2 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBed.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBed.java
@@ -25,9 +25,9 @@ public class ItemBed extends Item {
         if (!world.canPlaceInsideBlock(pos1)) {
             pos1 = new TilePos(pos1).add(side.direction());
         }
-        Direction dir = player == null ? Direction.NORTH : player.getHorizontalPlacementDirection(null).opposite();
+        final Direction dir = player == null ? Direction.NORTH : player.getHorizontalPlacementDirection(null).opposite();
         final TilePos pos2 = new TilePos(pos1).sub(dir);
-        
+
         if (!world.canPlaceInsideBlock(pos1) || !world.canPlaceInsideBlock(pos2)) return false;
         
         final var bed = Blocks.BED.getLogic();
@@ -39,9 +39,9 @@ public class ItemBed extends Item {
         
         
         final boolean isPlaced1 = 
-        world.setBlockTypeData(pos1, Blocks.BED, dir.legacyHorizontalIndex());
+            world.setBlockTypeData(pos1, Blocks.BED, dir.legacyIndex());
         final boolean isPlaced2 = isPlaced1 &&
-        world.setBlockTypeData(pos2, Blocks.BED, dir.legacyHorizontalIndex() | BlockLogicBed.IS_HEAD.set(0, 1));
+            world.setBlockTypeData(pos2, Blocks.BED, dir.legacyIndex() | BlockLogicBed.IS_HEAD.set(0, 1));
         if (!isPlaced2) {
             if (isPlaced1) world.setBlockType(pos1, Blocks.AIR);
             return false;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java b/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java
index 453204786..c12f48bc1 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java
@@ -39,7 +39,7 @@ public class ItemDoor extends Item {
         if (!world.canBlockIdBePlacedAt(this.doorBlockBottom.id(), blockPos, false, side)) return false;
 
         Direction leftDir = player.getHorizontalPlacementDirection(side).rotateY(1);
-        int meta = leftDir.legacyHorizontalIndex();
+        int meta = leftDir.legacyIndex();
 
         final var upperPos = blockPos.up(new TilePos());
 
@@ -99,7 +99,7 @@ public class ItemDoor extends Item {
 
         if (!direction.isHorizontal()) direction = Direction.NORTH;
         Direction lefDir = direction.rotateY(1);
-        int meta = lefDir.legacyHorizontalIndex();
+        int meta = lefDir.legacyIndex();
 
         int isSolidBlockLeft = (isSupported(world, blockPos, lefDir, false) ? 1 : 0) + (isSupported(world, blockPos.up(new TilePos()), lefDir, false) ? 1 : 0);
         int isSolidBlockRight = (isSupported(world, blockPos, lefDir.opposite(), true) ? 1 : 0) + (isSupported(world, blockPos.up(new TilePos()), lefDir.opposite(), true) ? 1 : 0);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java b/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java
index 6dfaea5f8..748786a61 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java
@@ -37,13 +37,13 @@ public class ItemFlag extends Item {
             if (world.getTileEntity(blockPos) instanceof TileEntityFlag flag) {
                 CompoundTag flagData = selfStack.getData().getCompoundOrDefault("FlagData", new CompoundTag());
                 if (hasFlagBeenDrawnOn(selfStack) && doesFlagContainDyes(selfStack)) {
-                    player.sendStatusMessage(I18n.getInstance().translateKey("flag.overwrite"));
+                    player.sendStatusMessageTranslated("messages.flag.overwrite");
                     return false;
                 }
                 flag.copyFlagNBT(flagData);
                 UUIDHelper.writeToTag(flagData, player.uuid, "OwnerUUID"); // Sets the owner of the copied flag to the current player so they can actually modify the flag once they place it
                 selfStack.getData().putCompound("FlagData", flagData);
-                player.sendStatusMessage(I18n.getInstance().translateKey("flag.copied"));
+                player.sendStatusMessageTranslated("messages.flag.copied");
                 return true;
             }
         }
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemMap.java b/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
index e8c77a889..780d05ef7 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemMap.java
@@ -132,7 +132,7 @@ public class ItemMap extends Item implements IComplexItem
 					ItemMapSavedData mapData = getOrCreateSavedData((short) selfStack.getMetadata(), scale, world);
 					TileEntityFlag flag = (TileEntityFlag) world.getTileEntity(blockPos);
 					if (mapData.createNewWaypoint(flag) == ItemMapSavedData.FlagError.FULL) {
-						if (player != null) player.sendTranslatedChatMessage("flag.full");
+						if (player != null) player.sendMessageTranslated("messages.flag.full");
 						break;
 					}
 				}
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java b/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java
index 15b0765d7..b37151054 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java
@@ -23,7 +23,7 @@ public class ItemWandSpawner extends Item implements IDispensable
     @Override
     public @Nullable ItemStack onUse(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Player player) {
         if (player.gamemode != Gamemodes.CREATIVE){
-            player.sendTranslatedChatMessage("wand.wrongmode");
+            player.sendMessageTranslated("messages.wand.wrongmode");
             return selfStack;
         }
 
diff --git a/game/core/src/main/java/net/minecraft/core/lang/Language.java b/game/core/src/main/java/net/minecraft/core/lang/Language.java
index 1599c501f..c3083c8fe 100644
--- a/game/core/src/main/java/net/minecraft/core/lang/Language.java
+++ b/game/core/src/main/java/net/minecraft/core/lang/Language.java
@@ -2,6 +2,8 @@ package net.minecraft.core.lang;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.core.data.registry.Registries;
+
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 import java.io.BufferedReader;
@@ -308,5 +310,9 @@ public class Language {
         public boolean isDefault() {
             return true;
         }
+
+        public @NotNull Properties getEntries() {
+            return this.entries;
+        }
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java b/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java
index b94457bea..008847bfb 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java
@@ -1,6 +1,7 @@
 package net.minecraft.core.net.command;
 
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
 
 public class TextFormatting {
 	public static final String FORMAT_CHARS = "0123456789abcdefklmnopr+-";
@@ -114,4 +115,168 @@ public class TextFormatting {
 	public static TextFormatting get(int id) {
 		return FORMATTINGS[id];
 	}
+
+	public synchronized static @NotNull String scoped(@NotNull String str) {
+		interface ctx { static StringBuilder sb = new StringBuilder(); }
+		ctx.sb.setLength(0);
+		ctx.sb.ensureCapacity(str.length() + 4);
+		ctx.sb.append(PUSH);
+		ctx.sb.append(str);
+		ctx.sb.append(POP);
+		return ctx.sb.toString();
+	} 
+
+	public static record Base(
+		@NotNull Color color,
+		boolean obfuscated,
+		boolean bold,
+		boolean strikethrough,
+		boolean underline,
+		boolean italic,
+		boolean outline
+	) {
+		public static final @NotNull Base WHITE = new Base(Color.WHITE);
+		public static final @NotNull Base ORANGE = new Base(Color.ORANGE);
+		public static final @NotNull Base MAGENTA = new Base(Color.MAGENTA);
+		public static final @NotNull Base LIGHT_BLUE = new Base(Color.LIGHT_BLUE);
+		public static final @NotNull Base YELLOW = new Base(Color.YELLOW);
+		public static final @NotNull Base LIME = new Base(Color.LIME);
+		public static final @NotNull Base PINK = new Base(Color.PINK);
+		public static final @NotNull Base GRAY = new Base(Color.GRAY);
+		public static final @NotNull Base LIGHT_GRAY = new Base(Color.LIGHT_GRAY);
+		public static final @NotNull Base CYAN = new Base(Color.CYAN);
+		public static final @NotNull Base PURPLE = new Base(Color.PURPLE);
+		public static final @NotNull Base BLUE = new Base(Color.BLUE);
+		public static final @NotNull Base BROWN = new Base(Color.BROWN);
+		public static final @NotNull Base GREEN = new Base(Color.GREEN);
+		public static final @NotNull Base RED = new Base(Color.RED);
+		public static final @NotNull Base BLACK = new Base(Color.BLACK);
+
+		public Base(@NotNull Color color) {
+			this(color, false, false, false, false, false, false);
+		}
+
+		public @NotNull Base withStyle(
+			boolean obfuscated,
+			boolean bold,
+			boolean strikethrough,
+			boolean underline,
+			boolean italic,
+			boolean outline
+		) {
+			return new Base(this.color, obfuscated, bold, strikethrough, underline, italic, outline);
+		}
+
+		public short pack() {
+			short res = 0;
+			res |= (this.obfuscated)    ? 0b0000_0001 : 0;
+			res |= (this.bold)          ? 0b0000_0010 : 0;
+			res |= (this.strikethrough) ? 0b0000_0100 : 0;
+			res |= (this.underline)     ? 0b0000_1000 : 0;
+			res |= (this.italic)        ? 0b0001_0000 : 0;
+			res |= (this.outline)       ? 0b0010_0000 : 0;
+			res |= (this.color.ch) << 8;
+			return res;
+		}
+
+		public static @NotNull Base unpack(short packed) {
+			return new Base(
+				Color.fromByte((byte)(packed >> 8)),
+				(packed & 0b0000_0001) != 0,
+				(packed & 0b0000_0010) != 0,
+				(packed & 0b0000_0100) != 0,
+				(packed & 0b0000_1000) != 0,
+				(packed & 0b0001_0000) != 0,
+				(packed & 0b0010_0000) != 0
+			);
+		}
+
+		@Override
+		public final synchronized String toString() {
+			interface ctx { static StringBuilder sb = new StringBuilder(14); }
+			ctx.sb.setLength(0);
+
+			if (this.obfuscated)    ctx.sb.append(OBFUSCATED);
+			if (this.bold)          ctx.sb.append(BOLD);
+			if (this.strikethrough) ctx.sb.append(STRIKETHROUGH);
+			if (this.underline)     ctx.sb.append(UNDERLINE);
+			if (this.italic)        ctx.sb.append(ITALIC);
+			if (this.outline)       ctx.sb.append(OUTLINE);
+			if (this.color != Color.NONE) ctx.sb.append(this.color.str);
+
+			return ctx.sb.toString();
+		}
+
+		public static enum Color {
+			NONE ((byte)0),
+			WHITE (Const.WHITE),
+			ORANGE (Const.ORANGE),
+			MAGENTA (Const.MAGENTA),
+			LIGHT_BLUE (Const.LIGHT_BLUE),
+			YELLOW (Const.YELLOW),
+			LIME (Const.LIME),
+			PINK (Const.PINK),
+			GRAY (Const.GRAY),
+			LIGHT_GRAY (Const.LIGHT_GRAY),
+			CYAN (Const.CYAN),
+			PURPLE (Const.PURPLE),
+			BLUE (Const.BLUE),
+			BROWN (Const.BROWN),
+			GREEN (Const.GREEN),
+			RED (Const.RED),
+			BLACK (Const.BLACK);
+
+			private static final class Const {
+				static final byte WHITE = '0';
+				static final byte ORANGE = '1';
+				static final byte MAGENTA = '2';
+				static final byte LIGHT_BLUE = '3';
+				static final byte YELLOW = '4';
+				static final byte LIME = '5';
+				static final byte PINK = '6';
+				static final byte GRAY = '7';
+				static final byte LIGHT_GRAY = '8';
+				static final byte CYAN = '9';
+				static final byte PURPLE = 'a';
+				static final byte BLUE = 'b';
+				static final byte BROWN = 'c';
+				static final byte GREEN = 'd';
+				static final byte RED = 'e';
+				static final byte BLACK = 'f';
+			}
+	
+			public final byte ch;
+			public final String str;
+
+			Color(byte ch) {
+				assert (ch & ~0x7F) == 0;
+				this.ch = ch;
+				this.str = (ch == 0)
+					? ""
+					: "" + SPECIAL_CHAR + (char)ch;
+			}
+
+			public static @NotNull Color fromByte(byte value) {
+				return switch (value) {
+					default -> NONE;
+					case Const.WHITE -> WHITE;
+					case Const.ORANGE -> ORANGE;
+					case Const.MAGENTA -> MAGENTA;
+					case Const.LIGHT_BLUE -> LIGHT_BLUE;
+					case Const.YELLOW -> YELLOW;
+					case Const.LIME -> LIME;
+					case Const.PINK -> PINK;
+					case Const.GRAY -> GRAY;
+					case Const.LIGHT_GRAY -> LIGHT_GRAY;
+					case Const.CYAN -> CYAN;
+					case Const.PURPLE -> PURPLE;
+					case Const.BLUE -> BLUE;
+					case Const.BROWN -> BROWN;
+					case Const.GREEN -> GREEN;
+					case Const.RED -> RED;
+					case Const.BLACK -> BLACK;
+				};
+			}
+		}
+	}
 }
diff --git a/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java b/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
index 016ec2376..e4ebde803 100644
--- a/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
+++ b/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java
@@ -91,8 +91,12 @@ public abstract class PacketHandler {
         handleInvalidPacket(packetTakeItemEntity);
     }
 
-    public void handleChat(@NotNull PacketChat packetChat) {
-        handleInvalidPacket(packetChat);
+    public void handleMessage(@NotNull PacketMessage packetMessage) {
+        handleInvalidPacket(packetMessage);
+    }
+    
+    public void handleTranslatableMessage(@NotNull PacketMessageTranslatable packetMessageTranslatable) {
+        handleInvalidPacket(packetMessageTranslatable);
     }
 
     public void handleAddEntity(@NotNull PacketAddEntity packetAddEntity) {
@@ -231,10 +235,6 @@ public abstract class PacketHandler {
         handleInvalidPacket(packetSleep);
     }
 
-    public void handleBedMessage(@NotNull PacketBedMessage packetBedMessage) {
-        handleInvalidPacket(packetBedMessage);
-    }
-
     public void handleWeatherEffect(@NotNull PacketWeatherEffect packetWeatherEffect) {
         handleInvalidPacket(packetWeatherEffect);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java b/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java
index c99415d3f..8e3aaf97f 100644
--- a/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java
+++ b/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java
@@ -256,7 +256,7 @@ public abstract class Packet
         addMapping(0, true, true, PacketKeepAlive.class);
         addMapping(1, true, true, PacketLogin.class);
         addMapping(2, true, true, PacketHandshake.class);
-        addMapping(3, true, true, PacketChat.class);
+        addMapping(3, true, true, PacketMessage.class);
         addMapping(4, true, false, PacketSetTime.class);
         addMapping(5, true, false, PacketSetEquippedItem.class);
         addMapping(6, true, false, PacketSetSpawnPosition.class);
@@ -305,7 +305,7 @@ public abstract class Packet
         addMapping(61, true, false, PacketPlaySound.class);
         addMapping(62, true, false, PacketPlaySoundDirect.class);
         addMapping(63, true, false, PacketAddParticle.class);
-        addMapping(70, true, false, PacketBedMessage.class);
+        addMapping(70, true, false, PacketMessageTranslatable.class);
         addMapping(71, true, false, PacketWeatherEffect.class);
         addMapping(72, true, false, PacketUpdatePlayerProfile.class);
         addMapping(73, true, false, PacketWeatherStatus.class);
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketBedMessage.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketBedMessage.java
deleted file mode 100644
index 67f3197aa..000000000
--- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketBedMessage.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.minecraft.core.net.packet;
-
-import net.minecraft.core.net.handler.PacketHandler;
-
-import java.io.*;
-
-public class PacketBedMessage extends Packet
-{
-
-    public PacketBedMessage()
-    {
-    }
-    
-    public PacketBedMessage(int state)
-    {
-    	bedState = state;
-    }
-
-    @Override
-	public void read(DataInputStream dis)
-        throws IOException
-    {
-        bedState = dis.readByte();
-    }
-
-    @Override
-	public void write(DataOutputStream dos)
-        throws IOException
-    {
-        dos.writeByte(bedState);
-    }
-
-    @Override
-	public void handlePacket(PacketHandler packetHandler)
-    {
-        packetHandler.handleBedMessage(this);
-    }
-
-    @Override
-	public int getEstimatedSize()
-    {
-        return 1;
-    }
-
-    public static final String[] BED_MESSAGE_KEYS = {
-        "bed.notValid", null, null
-    };
-    public int bedState;
-
-}
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketChat.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketChat.java
deleted file mode 100644
index d5f3cb004..000000000
--- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketChat.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package net.minecraft.core.net.packet;
-
-import net.minecraft.core.net.handler.PacketHandler;
-import net.minecraft.core.util.helper.AES;
-
-import java.io.*;
-import java.security.Key;
-
-public class PacketChat extends Packet {
-	
-	public static final String ENCRYPTION_ERROR_MESSAGE = "This crash is caused by outdated Java, please update to 8u161 or newer! If your Java version is out of date due to a technical requirement, please add the JCE Unlimited Strength Jurisdiction Policy Files to your installation. https://www.oracle.com/java/technologies/javase-jce-all-downloads.html";
-	
-	public String message;
-	public int type;
-	public boolean encrypted;
-
-	public PacketChat() {
-		
-	}
-
-	public PacketChat(String string) {
-		this(string, 0, null);
-	}
-
-	public PacketChat(String string, Key key) {
-		this(string, 0, key);
-	}
-	
-	public PacketChat(String string, int type, Key key) {
-		if(string.length() > 512) {
-			string = string.substring(0, 512);
-		}
-		if(key != null) {
-			try {
-				message = AES.encrypt(string, key);
-				encrypted = true;
-			}catch (Exception e) {
-				throw new RuntimeException(ENCRYPTION_ERROR_MESSAGE, e);
-			}
-		}else {
-			this.message = string;
-			this.encrypted = false;
-		}
-		this.type = type;
-	}
-
-	@Override
-	public void read(DataInputStream in) throws IOException {
-		type = in.readByte();
-		message = readStringUTF16BE(in, MAX_MESSAGE_SIZE);
-		encrypted = in.readBoolean();
-	}
-
-	@Override
-	public void write(DataOutputStream out) throws IOException {
-		out.writeByte(type);
-		writeStringUTF16BE(message, out);
-		out.writeBoolean(encrypted);
-	}
-
-	@Override
-	public void handlePacket(PacketHandler packetHandler) {
-		packetHandler.handleChat(this);
-	}
-
-	@Override
-	public int getEstimatedSize() {
-		return message.length() + 1;
-	}
-}
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketMessage.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketMessage.java
new file mode 100644
index 000000000..341f31044
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketMessage.java
@@ -0,0 +1,86 @@
+package net.minecraft.core.net.packet;
+
+import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.net.handler.PacketHandler;
+import net.minecraft.core.util.helper.AES;
+
+import java.io.*;
+import java.security.Key;
+
+import org.jetbrains.annotations.Nullable;
+
+public class PacketMessage extends Packet {
+	
+	public static final String ENCRYPTION_ERROR_MESSAGE = "This crash is caused by outdated Java, please update to 8u161 or newer! If your Java version is out of date due to a technical requirement, please add the JCE Unlimited Strength Jurisdiction Policy Files to your installation. https://www.oracle.com/java/technologies/javase-jce-all-downloads.html";
+
+	public static final byte TYPE_CHAT = 0;
+	public static final byte TYPE_STATUS = 1;
+	private static final byte MASK_FORMATTED = (byte)0b1000_0000;
+
+	/**
+	 * server-side should not try to use this
+	 */
+    public @Nullable TextFormatting.Base format;
+	public String message;
+	public byte type;
+	public boolean encrypted;
+
+	public PacketMessage() {}
+
+	public PacketMessage(String string) {
+		this(string, TYPE_CHAT, null);
+	}
+
+	public PacketMessage(String string, Key key) {
+		this(string, TYPE_CHAT, key);
+	}
+	
+	public PacketMessage(String string, byte type, Key key) {
+		this(null, string, type, key);
+	}
+
+	public PacketMessage(@Nullable TextFormatting.Base format, String string, byte type, Key key) {
+		if(string.length() > 512) string = string.substring(0, 512);
+
+		if (key == null) {
+			this.message = string;
+		} else try {
+			this.message = AES.encrypt(string, key);
+		} catch (Exception e) {
+			throw new RuntimeException(ENCRYPTION_ERROR_MESSAGE, e);
+		}
+		this.encrypted = key != null;
+		this.format = format;
+		this.type = type;
+	}
+
+	@Override
+	public void read(DataInputStream in) throws IOException {
+		this.type = in.readByte();
+		final boolean formatted = ((type & MASK_FORMATTED) != 0);
+		this.type &= ~MASK_FORMATTED; 
+		this.encrypted = in.readBoolean();
+		this.format = (formatted)
+			? TextFormatting.Base.unpack(in.readShort())
+			: null;
+		this.message = readStringUTF8(in, MAX_MESSAGE_SIZE);
+	}
+
+	@Override
+	public void write(DataOutputStream out) throws IOException {
+		out.writeByte(this.type | ((this.format != null) ? MASK_FORMATTED : 0));
+		out.writeBoolean(this.encrypted);
+		if (this.format != null) out.writeShort(this.format.pack());
+		writeStringUTF8(this.message, out);
+	}
+
+	@Override
+	public void handlePacket(PacketHandler packetHandler) {
+		packetHandler.handleMessage(this);
+	}
+
+	@Override
+	public int getEstimatedSize() {
+		return message.length() + 1;
+	}
+}
diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketMessageTranslatable.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketMessageTranslatable.java
new file mode 100644
index 000000000..7dff81434
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketMessageTranslatable.java
@@ -0,0 +1,150 @@
+package net.minecraft.core.net.packet;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import it.unimi.dsi.fastutil.objects.Object2ShortMap;
+import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap;
+import net.minecraft.core.lang.Language;
+import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.net.handler.PacketHandler;
+
+public class PacketMessageTranslatable extends Packet {
+    public @Nullable TextFormatting.Base format;
+    public short key = -1;
+    public byte type;
+    public @NotNull String[] args;
+
+	public static final byte TYPE_CHAT = 0;
+	public static final byte TYPE_STATUS = 1;
+
+    public static final int MAX_ARG_LEN = 255;
+    public static final int MAX_ARG_COUNT = 4;
+	private static final byte MASK_FORMATTED = (byte)0b1000_0000;
+
+    public PacketMessageTranslatable() {}
+    public PacketMessageTranslatable(short key, @NotNull String... args) {
+        this(null, key, TYPE_CHAT, args);
+    }
+    public PacketMessageTranslatable(short key, byte type, @NotNull String... args) {
+        this(null, key, type, args);
+    }
+
+    public PacketMessageTranslatable(@Nullable TextFormatting.Base format, short key, @NotNull String... args) {
+        this(format, key, TYPE_CHAT, args);
+    }
+
+    public PacketMessageTranslatable(@Nullable TextFormatting.Base format, short key, byte type, @NotNull String... args) {
+        this.format = format;
+        this.key = key;
+        this.type = type;
+        this.args = args;
+    }
+
+    public PacketMessageTranslatable(@NotNull String key, @NotNull String... args) {
+        this(null, key, TYPE_CHAT, args);
+    }
+    public PacketMessageTranslatable(@NotNull String key, byte type, @NotNull String... args) {
+        this(null, key, type, args);
+    }
+
+    public PacketMessageTranslatable(@Nullable TextFormatting.Base format, @NotNull String key, @NotNull String... args) {
+        this(format, key, TYPE_CHAT, args);
+    }
+
+    public PacketMessageTranslatable(@Nullable TextFormatting.Base format, @NotNull String key, byte type, @NotNull String... args) {
+        this.format = format;
+        this.key = KEY2ID_MAP.getOrDefault(key, (short)-1);
+        assert this.key != -1;
+        this.type = type;
+        this.args = args;
+    }
+
+    @Override
+    public void write(DataOutputStream dos) throws IOException {
+        dos.writeShort(this.key);
+        dos.writeByte(this.type | ((this.format != null) ? MASK_FORMATTED : 0));
+        if (this.format != null) dos.writeShort(this.format.pack());
+
+        final int argc = Math.min(this.args.length, MAX_ARG_COUNT);
+        dos.writeByte(argc);
+
+        final var args = new byte[argc][];
+        for (int i = 0; i < argc; i++) {
+            args[i] = this.args[i].getBytes(StandardCharsets.UTF_8);
+        }
+
+        for (var arg : args) {
+            final int len = Math.min(arg.length, MAX_ARG_LEN);
+            dos.writeByte(len);
+        }
+        
+        for (var arg : args) {
+            final int len = Math.min(arg.length, MAX_ARG_LEN);
+            dos.write(arg, 0, len);
+        }
+    }
+
+    @Override
+    public void read(DataInputStream dis) throws IOException {
+        this.key = dis.readShort();
+        this.type = dis.readByte();
+        final boolean formatted = ((type & MASK_FORMATTED) != 0);
+        this.type &= ~MASK_FORMATTED; 
+        this.format = (formatted)
+            ? TextFormatting.Base.unpack(dis.readShort())
+            : null;
+
+        final int argc; {
+            final int read = Byte.toUnsignedInt(dis.readByte());
+            argc = Math.min(read, MAX_ARG_COUNT);
+        };
+
+        final var args = new byte[argc][];
+
+        for (int i = 0; i < argc; i++) {
+            final int len = Byte.toUnsignedInt(dis.readByte());
+            args[i] = new byte[len];
+        }
+        
+        for (int i = 0; i < argc; i++) {
+            dis.readFully(args[i]);
+        }
+
+        this.args = new String[argc];
+        for (int i = 0; i < argc; i++) {
+            this.args[i] = new String(args[i], StandardCharsets.UTF_8);
+        }
+    }
+
+    @Override
+    public void handlePacket(PacketHandler packetHandler) {
+        packetHandler.handleTranslatableMessage(this);
+    }
+    @Override
+    public int getEstimatedSize() {
+        return 2 + 1 + 1 + args.length + args.length * 16;
+    }
+
+    public static final @NotNull String @NotNull[] ID2KEY_MAP; 
+    static {
+        final var list = new ArrayList<String>();
+        final var entries = Language.Default.INSTANCE.getEntries();
+        for (final var key : entries.stringPropertyNames()) {
+            if (!key.startsWith("messages.")) continue;
+            list.add(key);
+        }
+        ID2KEY_MAP = list.toArray(String[]::new);
+    }
+
+    public static final @NotNull Object2ShortMap<@NotNull String> KEY2ID_MAP = new Object2ShortOpenHashMap<>(ID2KEY_MAP.length);    
+    static {
+        for (short i = 0; i < ID2KEY_MAP.length; i++) KEY2ID_MAP.put(ID2KEY_MAP[i], i);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/Direction.java b/game/core/src/main/java/net/minecraft/core/util/helper/Direction.java
index ea3aacaa6..2ad48ff04 100644
--- a/game/core/src/main/java/net/minecraft/core/util/helper/Direction.java
+++ b/game/core/src/main/java/net/minecraft/core/util/helper/Direction.java
@@ -108,17 +108,6 @@ public enum Direction {
         };
     }
 
-    @Deprecated
-    public int legacyHorizontalIndex() {
-        return switch (this) {
-            default -> 0;
-            case NORTH -> 0;
-            case EAST -> 1;
-            case SOUTH -> 2;
-            case WEST -> 3;
-        };
-    }
-
     // Friends:
     // ============================
 
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 c3968a005..ad34e9345 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
@@ -28,6 +28,7 @@ import net.minecraft.core.enums.EnumBlockSoundEffectType;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.command.CommandManager;
+import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.sound.BlockSound;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.debug.Debug;
@@ -3001,8 +3002,24 @@ public abstract class World implements MutableWorldSource {
     }
 
     public void sendGlobalMessage(final String message) {
+        this.sendGlobalMessage(null, message);
+    }
+
+    public void sendGlobalMessageTranslated(final @NotNull String key, final @NotNull String... args) {
+        this.sendGlobalMessageTranslated(null, key, args);
+    }
+
+    public void sendGlobalMessage(@Nullable TextFormatting.Base format, final String message) {
+        for (final Player player : this.players) {
+            player.sendMessage(format, message);
+        }
+    }
+
+    public void sendGlobalMessageTranslated(@Nullable TextFormatting.Base format, 
+        final @NotNull String key, final @NotNull String... args
+    ) {
         for (final Player player : this.players) {
-            player.sendMessage(message);
+            player.sendMessageTranslated(format, key, args);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
index 6c0280e47..79450252d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
@@ -89,7 +89,7 @@ public class TerrainGeneratorNether extends TerrainGeneratorLerp {
             return this.bedrockId;
         } else if (y <= this.quarterHeight + this.rand.nextInt(10)) {
             return this.bedrockId;
-        } else if (density > 0.0) {
+        }else if (density > 0.0) {
             return this.fillerBlockId;
         } else if (y < this.oceanY) {
             final int fluidId = this.getCachedOceanFluid(chunk, x, z);
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/ISaveConverter.java b/game/core/src/main/java/net/minecraft/core/world/save/ISaveConverter.java
index 9253bdb4d..84e673189 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/ISaveConverter.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/ISaveConverter.java
@@ -2,6 +2,7 @@ package net.minecraft.core.world.save;
 
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.world.ProgressListener;
+import org.jetbrains.annotations.NotNull;
 
 import java.io.File;
 
@@ -28,5 +29,5 @@ public interface ISaveConverter
      * @param saveDirName The name of the directory containing the specific save to convert.
      * @param progress A progress indicator for the conversion.
      */
-    void convertSave(CompoundTag levelData, File savesDir, String saveDirName, ProgressListener progress);
+    void convertSave(@NotNull CompoundTag levelData, @NotNull File savesDir, @NotNull String saveDirName, @NotNull ProgressListener progress);
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/SaveConverters.java b/game/core/src/main/java/net/minecraft/core/world/save/SaveConverters.java
index 0090b043a..5e483f259 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/SaveConverters.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/SaveConverters.java
@@ -2,6 +2,7 @@ package net.minecraft.core.world.save;
 
 import net.minecraft.core.world.save.conversion.SaveConverter19132To19133;
 import net.minecraft.core.world.save.conversion.SaveConverter19133To19134;
+import net.minecraft.core.world.save.conversion.SaveConverter19134To19135;
 import net.minecraft.core.world.save.conversion.SaveConverterLegacyTo19132;
 
 import java.util.ArrayList;
@@ -18,5 +19,6 @@ public class SaveConverters
         saveConverters.add(new SaveConverterLegacyTo19132());
         saveConverters.add(new SaveConverter19132To19133());
         saveConverters.add(new SaveConverter19133To19134());
+        saveConverters.add(new SaveConverter19134To19135());
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/SaveFormats.java b/game/core/src/main/java/net/minecraft/core/world/save/SaveFormats.java
index 7d219878b..4abda32e3 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/SaveFormats.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/SaveFormats.java
@@ -7,6 +7,7 @@ import net.minecraft.core.world.save.legacy.SaveFormatLegacy;
 import net.minecraft.core.world.save.mcregion.SaveFormat19132;
 import net.minecraft.core.world.save.mcregion.SaveFormat19133;
 import net.minecraft.core.world.save.mcregion.SaveFormat19134;
+import net.minecraft.core.world.save.mcregion.SaveFormat19135;
 import org.slf4j.Logger;
 
 import java.io.File;
@@ -35,5 +36,6 @@ public class SaveFormats
         saveFormats.put(19132, SaveFormat19132.class);
         saveFormats.put(19133, SaveFormat19133.class);
         saveFormats.put(19134, SaveFormat19134.class);
+        saveFormats.put(19135, SaveFormat19135.class);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19132To19133.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19132To19133.java
index d2c56cabd..abaa50516 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19132To19133.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19132To19133.java
@@ -7,6 +7,7 @@ import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.ProgressListener;
 import net.minecraft.core.world.save.mcregion.RegionFile;
 import net.minecraft.core.world.save.mcregion.RegionFileCache;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 import java.io.DataInputStream;
@@ -33,7 +34,7 @@ public class SaveConverter19132To19133
     }
 
     @Override
-    int convertDimensionRegions(Dimension dimension, ArrayList<File> regionFiles, int conversionsPerformed, int totalConversions, ProgressListener progress)
+    int convertDimensionRegions(@NotNull Dimension dimension, @NotNull ArrayList<File> regionFiles, int conversionsPerformed, int totalConversions, @NotNull ProgressListener progress)
     {
         Collections.sort(regionFiles);
         int progressValue = 0;
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19133To19134.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19133To19134.java
index 297412ccc..840fa045c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19133To19134.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19133To19134.java
@@ -2,11 +2,9 @@ package net.minecraft.core.world.save.conversion;
 
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.tags.CompoundTag;
-import net.minecraft.core.data.legacy.LegacyWorldTypes;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.ProgressListener;
-import net.minecraft.core.world.World;
 import net.minecraft.core.world.save.DimensionData;
 import net.minecraft.core.world.save.ISaveFormat;
 import net.minecraft.core.world.save.SaveFormats;
@@ -40,7 +38,7 @@ public class SaveConverter19133To19134
     }
 
     @Override
-    public void convertSave(CompoundTag levelData, File savesDir, String worldDirName, ProgressListener progress)
+    public void convertSave(@NotNull CompoundTag levelData, @NotNull File savesDir, @NotNull String worldDirName, @NotNull ProgressListener progress)
     {
         this.savesDir = savesDir;
         this.worldDirName = worldDirName;
@@ -138,7 +136,7 @@ public class SaveConverter19133To19134
     }
 
     @Override
-    int convertDimensionRegions(Dimension dimension, ArrayList<File> regionFiles, int conversionsPerformed, int totalConversions, ProgressListener progress)
+    int convertDimensionRegions(@NotNull Dimension dimension, @NotNull ArrayList<File> regionFiles, int conversionsPerformed, int totalConversions, @NotNull ProgressListener progress)
     {
         return 0;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19134To19135.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19134To19135.java
new file mode 100644
index 000000000..6ef88d731
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverter19134To19135.java
@@ -0,0 +1,209 @@
+package net.minecraft.core.world.save.conversion;
+
+import com.mojang.logging.LogUtils;
+import com.mojang.nbt.NbtIo;
+import com.mojang.nbt.tags.CompoundTag;
+import com.mojang.nbt.tags.DoubleTag;
+import com.mojang.nbt.tags.ListTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.ProgressListener;
+import net.minecraft.core.world.save.mcregion.RegionFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Random;
+
+public class SaveConverter19134To19135 extends SaveConverterMCRegionBase{
+    private static final Logger LOGGER = LogUtils.getLogger();
+
+    private final int oldMinY = 128;
+    private final int newMinY = 64;
+    private final int shift = this.oldMinY - this.newMinY;
+    private final @NotNull Random random = new Random();
+
+    @Override
+    int convertDimensionRegions(@NotNull Dimension dimension, @NotNull ArrayList<File> regionFiles, int conversionsPerformed, int totalConversions, @NotNull ProgressListener progress) {
+        if (dimension == Dimension.NETHER) {
+            for (int ri = 0, regionFilesSize = regionFiles.size(); ri < regionFilesSize; ri++) {
+                File region = regionFiles.get(ri);
+                RegionFile regionFile = new RegionFile(region);
+
+                for (int rx = 0; rx < 32; rx++) {
+                    for (int rz = 0; rz < 32; rz++) {
+                        try
+                        {
+                            DataOutputStream outputStream = regionFile.getChunkDataOutputStream(rx, rz);
+                            DataInputStream inputStream = regionFile.getChunkDataInputStream(rx, rz);
+                            if (inputStream == null) continue;
+                            CompoundTag chunkData = NbtIo.read(inputStream);
+
+                            // Shift sections down to match new min y
+                            ListTag sections = chunkData.getCompound("Level").getList("Sections");
+                            boolean shift = true;
+//                            for (final @NotNull Tag<?> tag : sections) {
+//                                if (tag instanceof CompoundTag compoundTag) {
+//                                    int section = compoundTag.getInteger("yPos");
+//                                    if (section < 8) {
+//                                        if (compoundTag.containsKey("Data")) {
+//                                            shift = false;
+//                                        }
+//                                    }
+//                                }
+//                            }
+
+                            // Hacky way to not shift existing nightly chunks
+                            if (chunkData.getCompound("Level").containsKey("TicksList")) {
+                                shift = false;
+                            }
+
+                            if (shift) {
+                                ListTag shiftedSections = new ListTag();
+                                for (final @NotNull Tag<?> tag : sections) {
+                                    if (tag instanceof CompoundTag compoundTag) {
+                                        var converted = convertSection(compoundTag);
+                                        if (converted != null) {
+                                            shiftedSections.addTag(converted);
+                                        }
+                                    }
+                                }
+
+                                // Fill now empty section above the old nether with new sections
+                                final short bedrock = 260;
+                                final short netherrack = 800;
+                                byte[] defaultBiomeMap = new byte[512];
+                                short[] defaultBlocksNetherrack = new short[16 * 16 * 16];
+                                short[] defaultBlocksBedrock = new short[16 * 16 * 16];
+                                Arrays.fill(defaultBlocksNetherrack, netherrack);
+                                Arrays.fill(defaultBlocksBedrock, bedrock);
+                                for (int i = (15 - (this.shift / 16)); i < 16; i++) {
+                                    CompoundTag newSection = new CompoundTag();
+                                    newSection.putInt("yPos", i);
+                                    newSection.putByteArray("BiomeMap", defaultBiomeMap);
+                                    if (i == 15) { // New bedrock ceiling
+                                        short[] newBlocks = new short[16 * 16 * 16];
+                                        Arrays.fill(newBlocks, 0, 16 * 16 * (15 - 10), netherrack);
+                                        for (int _y = (15 - 10); _y < 16; _y++) {
+                                            for (int _x = 0; _x < 16; _x++) {
+                                                for (int _z = 0; _z < 16; _z++) {
+                                                    newBlocks[_y * 16 * 16 + _z * 16 + _x] = _y >= 15 - this.random.nextInt(10) ? bedrock : netherrack;
+                                                }
+                                            }
+                                        }
+                                        newSection.putShortArray("Blocks", newBlocks);
+                                    } else {
+                                        newSection.putShortArray("Blocks", defaultBlocksNetherrack);
+                                    }
+                                    shiftedSections.addTag(newSection);
+                                }
+                                // fill empty sections below the nether with bedrock
+                                for (int i = 0; i < 4; i++) {
+                                    CompoundTag newSection = new CompoundTag();
+                                    newSection.putInt("yPos", i);
+                                    newSection.putByteArray("BiomeMap", defaultBiomeMap);
+                                    newSection.putShortArray("Blocks", defaultBlocksBedrock);
+                                    shiftedSections.addTag(newSection);
+                                }
+
+                                chunkData.getCompound("Level").putList("Sections", shiftedSections);
+
+                                // Shift entities
+                                ListTag entities = chunkData.getCompound("Level").getList("Entities");
+                                for (final @NotNull Tag<?> tag : entities) {
+                                    if (tag instanceof CompoundTag entityTag) {
+                                        convertEntity(entityTag);
+                                    }
+                                }
+
+                                // Shift tile entities
+                                ListTag tileEntities = chunkData.getCompound("Level").getList("TileEntities");
+                                for (final @NotNull Tag<?> tag : tileEntities) {
+                                    if (tag instanceof CompoundTag tileTag) {
+                                        convertTileEntity(tileTag);
+                                    }
+                                }
+                            }
+
+                            // Write level data
+                            NbtIo.write(chunkData, outputStream);
+
+                            // Close streams
+                            inputStream.close();
+                            outputStream.close();
+                        }
+                        catch(IOException e)
+                        {
+                            LOGGER.error("Failed to convert chunk X:{}, Z:{}, in region {}!", rx, rz, region.toPath(), e);
+                        }
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    private @Nullable CompoundTag convertSection(@NotNull CompoundTag oldSection) {
+        int section = oldSection.getInteger("yPos");
+        if (section == 15) { // Replace bedrock ceiling
+            if (oldSection.containsKey("Blocks")) {
+                short[] blocks = oldSection.getShortArray("Blocks");
+                final int bedrock = 260;
+                final int netherrack = 800;
+                for (int i = 0; i < blocks.length; i++) {
+                    short blockId = blocks[i];
+                    if (blockId == bedrock) {
+                        blocks[i] = netherrack;
+                    }
+                }
+                oldSection.putShortArray("Blocks", blocks);
+            }
+
+        }
+        section -= (this.shift / 16);
+        if (section >= 4) {
+            oldSection.putInt("yPos", section);
+            return oldSection;
+        }
+        return null;
+    }
+
+    private void convertEntity(@NotNull CompoundTag entityTag) {
+        ListTag pos = entityTag.getList("Pos");
+        double x = ((DoubleTag)pos.tagAt(0)).getValue();
+        double y = ((DoubleTag)pos.tagAt(1)).getValue() - this.shift;
+        double z = ((DoubleTag)pos.tagAt(2)).getValue();
+        ListTag newPos = new ListTag();
+        newPos.addTag(new DoubleTag(x));
+        newPos.addTag(new DoubleTag(y));
+        newPos.addTag(new DoubleTag(z));
+        entityTag.putList("Pos", newPos);
+
+        // Handle entity specific conversions
+        String entityId = entityTag.getString("id");
+        switch (entityId) {
+            case "minecraft:painting" -> entityTag.putInt("TileY", entityTag.getInteger("TileY") - this.shift);
+            case "minecraft:arrow", "minecraft:arrow_golden", "minecraft:arrow_purple" -> entityTag.putInt("yTile", entityTag.getInteger("yTile") - this.shift);
+        }
+    }
+
+    private void convertTileEntity(@NotNull CompoundTag tileEntityTag) {
+        tileEntityTag.putInt("y", tileEntityTag.getInteger("y") - this.shift);
+    }
+
+    @Override
+    public int fromVersion() {
+        return 19134;
+    }
+
+    @Override
+    public int toVersion() {
+        return 19135;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterLegacyTo19132.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterLegacyTo19132.java
index 11b7f86fd..a46029874 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterLegacyTo19132.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterLegacyTo19132.java
@@ -12,6 +12,7 @@ import net.minecraft.core.world.save.legacy.ChunkFilePattern;
 import net.minecraft.core.world.save.legacy.ChunkFolderPattern;
 import net.minecraft.core.world.save.mcregion.RegionFile;
 import net.minecraft.core.world.save.mcregion.RegionFileCache;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 import java.io.*;
@@ -39,7 +40,7 @@ public class SaveConverterLegacyTo19132
     }
 
     @Override
-    public void convertSave(CompoundTag tag, File savesDir, String saveDirName, ProgressListener progress)
+    public void convertSave(@NotNull CompoundTag tag, @NotNull File savesDir, @NotNull String saveDirName, @NotNull ProgressListener progress)
     {
         // Get directories for each dimension's data
         File dim0dir = new File(savesDir, saveDirName);
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterMCRegionBase.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterMCRegionBase.java
index 37f5bae97..2ca2f14ad 100644
--- a/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterMCRegionBase.java
+++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/SaveConverterMCRegionBase.java
@@ -6,6 +6,7 @@ import net.minecraft.core.world.ProgressListener;
 import net.minecraft.core.world.save.ISaveConverter;
 import net.minecraft.core.world.save.ISaveFormat;
 import net.minecraft.core.world.save.SaveFormats;
+import org.jetbrains.annotations.NotNull;
 
 
 import java.io.File;
@@ -18,7 +19,7 @@ public abstract class SaveConverterMCRegionBase
     String worldDirName;
 
     @Override
-    public void convertSave(CompoundTag levelData, File savesDir, String worldDirName, ProgressListener progress)
+    public void convertSave(@NotNull CompoundTag levelData, @NotNull File savesDir, @NotNull String worldDirName, @NotNull ProgressListener progress)
     {
         this.savesDir = savesDir;
         this.worldDirName = worldDirName;
@@ -63,7 +64,7 @@ public abstract class SaveConverterMCRegionBase
         }
     }
 
-    abstract int convertDimensionRegions(Dimension dimension, ArrayList<File> regionFiles, int conversionsPerformed, int totalConversions, ProgressListener progress);
+    abstract int convertDimensionRegions(@NotNull Dimension dimension, @NotNull ArrayList<File> regionFiles, int conversionsPerformed, int totalConversions, @NotNull ProgressListener progress);
 
     ArrayList<File> getRegionFiles(File dimensionDir)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/world/save/mcregion/SaveFormat19135.java b/game/core/src/main/java/net/minecraft/core/world/save/mcregion/SaveFormat19135.java
new file mode 100644
index 000000000..9ded2b877
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/save/mcregion/SaveFormat19135.java
@@ -0,0 +1,36 @@
+package net.minecraft.core.world.save.mcregion;
+
+import net.minecraft.core.world.Dimension;
+import net.minecraft.core.world.save.SaveFormatBase;
+
+import java.io.File;
+
+public class SaveFormat19135 extends SaveFormatBase {
+    public SaveFormat19135(File savesDir) {
+        super(savesDir);
+    }
+
+    @Override
+    public String getFormatName() {
+        return "BTARegion";
+    }
+
+    @Override
+    public int getSaveVersion() {
+        return 19135;
+    }
+
+    @Override
+    public void flushCache() {
+        RegionFileCache.flushCache();
+    }
+
+    @Override
+    public File getDimensionRootDir(String worldDirName, Dimension dimension) {
+        File worldDir = new File(savesDir, worldDirName);
+
+        File worldDimsDir = new File(worldDir, "dimensions");
+
+        return new File(worldDimsDir, Integer.toString(dimension.id));
+    }
+}
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 2acd63740..b28652865 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
@@ -6,6 +6,7 @@ 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;
+import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.biome.provider.BiomeProvider;
 import net.minecraft.core.world.config.season.SeasonConfig;
@@ -14,8 +15,6 @@ import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.pos.TilePosc;
 import net.minecraft.core.world.save.LevelData;
 import net.minecraft.core.world.season.Seasons;
-import net.minecraft.core.world.settings.WorldSettingNodes;
-import net.minecraft.core.world.settings.impl.WorldHeightSettingNode;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.Weathers;
 import net.minecraft.core.world.wind.WindProvider;
@@ -108,7 +107,7 @@ public abstract class WorldType
         return seasonConfig;
     }
 
-    public int getMinY(final @NotNull World world) {
+    public int getMinY(final @NotNull WorldSource world) {
 //        return world.getWorldSetting(WorldSettingNodes.WORLD_HEIGHT_BOTTOM) * WorldHeightSettingNode.VALUE_SCALE;
         return this.minY;
     }
@@ -117,7 +116,7 @@ public abstract class WorldType
         return minPortalY;
     }
 
-    public int getMaxY(final @NotNull World world) {
+    public int getMaxY(final @NotNull WorldSource world) {
 //        return (world.getWorldSetting(WorldSettingNodes.WORLD_HEIGHT_TOP) * WorldHeightSettingNode.VALUE_SCALE) - 1;
         return this.maxY;
     }
diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/messages.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/messages.lang
new file mode 100644
index 000000000..094b367ce
--- /dev/null
+++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/messages.lang
@@ -0,0 +1,62 @@
+messages.player_joined=%s joined the game.
+messages.player_left=%s left the game.
+messages.player_kicked=%s left the game.
+
+messages.illegal_characters=[SERVER] Illegal characters in chat message.
+
+messages.sleep.succeed=%s went to sleep. Sweet dreams!
+messages.sleep.enter_bed=%s went to bed.
+messages.sleep.exit_bed=%s has left their bed.
+messages.sleep.more_required=%s more players are required to sleep to skip to daytime.
+messages.sleep.more_required.singular=%s more player is required to sleep to skip to daytime.
+
+messages.bed.occupied=This bed is occupied.
+messages.bed.noSleep=You can only sleep at night or during thunderstorms.
+messages.bed.setSpawn=Respawn point set.
+messages.bed.notValid=Your home bed was missing or obstructed.
+messages.bed.noAllowSleeping=Sleeping is disabled.
+messages.bed.unsafeToSleep=It's not safe to sleep here.
+
+messages.wand.wrongmode=You must be in Creative mode to use this item!
+
+messages.flag.full=You have too many flags on this map!
+messages.flag.overwrite=Cannot overwrite an existing pattern.
+messages.flag.copied=Flag pattern copied.
+
+messages.death.mob.generic=%s died.
+messages.death.mob.lava=%s swam in lava.
+messages.death.mob.spikes=%s got impaled.
+messages.death.mob.fall=%s broke their legs.
+messages.death.mob.drowned=%s suffocated.
+messages.death.mob.fire=%s was incinerated.
+messages.death.mob.killed_by=%s was killed by %s.
+
+messages.death.player.generic=%s died mysteriously.
+messages.death.player.lava=%s got lost in the sauce.
+messages.death.player.spikes=%s fell for the trap.
+messages.death.player.fall=%s forgot to tie their laces.
+messages.death.player.drowned=%s is sleeping with the fishes.
+messages.death.player.fire=%s was cooked well done.
+messages.death.player.tnt=%s was killed by Popbob.
+messages.death.player.lightning=%s was grounded.
+messages.death.player.herobrine=%s was killed by Herobrine.
+messages.death.player.killed_by=%s was backstabbed by %s.
+messages.death.player.killed_by.zombie=%s became a zombie.
+messages.death.player.killed_by.zombie_pig=%s discovered mob mentality.
+messages.death.player.killed_by.creeper=%s didn't see the creeper.
+messages.death.player.killed_by.skeleton=%s was a victim of aimbot.
+messages.death.player.killed_by.spider=%s spent too much time on the web.
+messages.death.player.killed_by.ghast=%s didn't return the serve.
+messages.death.player.killed_by.slime=%s was slimed.
+messages.death.player.killed_by.wolf=%s got what they deserved.
+messages.death.player.killed_by.giant=%s was killed by- wait, what?!
+messages.death.player.killed_by.pig=%s is *really* bad at Minecraft.
+messages.death.player.killed_by.arrow=%s is a pincushion.
+messages.death.player.killed_by.arrow_player=%s got 360 noscoped by %s.
+messages.death.player.killed_by.arrow_suicide=%s lost a game of Russian roulette.
+messages.death.player.killed_by.arrow_golden=%s is Swiss cheese.
+messages.death.player.killed_by.arrow_golden_player=%s got pierced by %s.
+messages.death.player.killed_by.arrow_golden_suicide=%s got gold in their eye.
+messages.death.player.killed_by.cannonball=%s was detonated remotely.
+messages.death.player.killed_by.cannonball_player=%s was fragmented by %s.
+messages.death.player.killed_by.cannonball_suicide=%s jumped too high.
diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/strings.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/strings.lang
index a9e8760e3..24a86e707 100644
--- a/game/core/src/main/resources/assets/minecraft/lang/en_US/strings.lang
+++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/strings.lang
@@ -88,13 +88,6 @@ damagetype.fire=Fire
 
 progress.tip=Tip: %s
 
-bed.occupied=This bed is occupied.
-bed.noSleep=You can only sleep at night or during thunderstorms.
-bed.setSpawn=Respawn point set.
-bed.notValid=Your home bed was missing or obstructed.
-bed.noAllowSleeping=Sleeping is disabled.
-bed.unsafeToSleep=It's not safe to sleep here.
-
 sign.image.none=None
 sign.image.arrow_right=Right Arrow
 sign.image.arrow_left=Left Arrow
@@ -154,12 +147,6 @@ record.ward=Ward
 record.wait=Wait
 record.dog=Dog
 
-flag.full=You have too many flags on this map!
-flag.overwrite=Cannot overwrite an existing pattern.
-flag.copied=Flag pattern copied.
-
-wand.wrongmode=You must be in Creative mode to use this item!
-
 save.data.missing.data=Level Metadata Missing!
 
 unit.day=Day
diff --git a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
index 5e4f98e5d..54b837927 100644
--- a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -31,6 +31,7 @@ import net.minecraft.core.player.gamemode.Gamemodes;
 import net.minecraft.core.util.pool.ObjectPool;
 import net.minecraft.core.util.helper.UUIDHelper;
 import net.minecraft.core.world.pos.TilePos;
+import net.minecraft.core.world.save.mcregion.SaveFormat19135;
 import net.minecraft.core.world.settings.WorldConfiguration;
 import net.minecraft.core.world.type.WorldTypeGroups;
 import net.minecraft.server.entity.player.PlayerServer;
@@ -377,7 +378,7 @@ public class MinecraftServer
             }
         }
         LOGGER.info("Preparing level \"{}\"", lName);
-        initWorld(new SaveFormat19134(new File(".")), lName, randomLong);
+        initWorld(new SaveFormat19135(new File(".")), lName, randomLong);
         LOGGER.info("Generating RSA key...");
         try
         {
diff --git a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
index e19d0734f..b9979de3a 100644
--- a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
+++ b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
@@ -716,13 +716,6 @@ public class PlayerServer extends Player implements ContainerListener {
         lastHealth = Integer.MIN_VALUE;
         lastScore = Integer.MIN_VALUE;
     }
-
-    public void func_22061_a(String s)
-    {
-        I18n stringtranslate = I18n.getInstance();
-        String s1 = stringtranslate.translateKey(s);
-        playerNetServerHandler.sendPacket(new PacketChat(s1));
-    }
     
     @Override
     public void setCurrentItem(int i) {
@@ -750,14 +743,24 @@ public class PlayerServer extends Player implements ContainerListener {
     }
 
     @Override
-	public void sendMessage(String message) {
-		playerNetServerHandler.sendPacket(new PacketChat(message, 0, AES.keyChain.get(username)));
-	}
+    public void sendMessage(boolean isStatus, @Nullable TextFormatting.Base format, @NotNull String message) {
+        playerNetServerHandler.sendPacket(new PacketMessage(
+            format, message,
+            (isStatus) ? PacketMessage.TYPE_STATUS : PacketMessage.TYPE_CHAT,
+            AES.keyChain.get(username)
+        ));
+    }
 
-	@Override
-	public void sendStatusMessage(String message) {
-		playerNetServerHandler.sendPacket(new PacketChat(message, 1, AES.keyChain.get(username)));
-	}
+    @Override
+    public void sendMessageTranslated(boolean isStatus, @Nullable TextFormatting.Base format, @NotNull String key, @NotNull String... args) {
+        final var id = PacketMessageTranslatable.KEY2ID_MAP.getOrDefault(key, (short)-1);
+        if (id == -1) return;
+        playerNetServerHandler.sendPacket(new PacketMessageTranslatable(
+            format, id,
+            (isStatus) ? PacketMessageTranslatable.TYPE_STATUS : PacketMessageTranslatable.TYPE_CHAT,
+            args
+        ));
+    }
 
     public void teleport(double x, double y, double z, float yaw, float pitch) {
         playerNetServerHandler.teleportAndRotate(x, y, z, yaw, pitch);
diff --git a/game/server/src/main/java/net/minecraft/server/net/PlayerList.java b/game/server/src/main/java/net/minecraft/server/net/PlayerList.java
index 8f4308871..8719b4eab 100644
--- a/game/server/src/main/java/net/minecraft/server/net/PlayerList.java
+++ b/game/server/src/main/java/net/minecraft/server/net/PlayerList.java
@@ -235,7 +235,7 @@ public class PlayerList
             }
             else
             {
-                newPlayer.playerNetServerHandler.sendPacket(new PacketBedMessage(0));
+                newPlayer.playerNetServerHandler.sendPacket(new PacketMessageTranslatable("messages.bed.notValid"));
             }
         }
         worldserver.getChunkProvider().prepareChunk((int) newPlayer.x >> 4, (int) newPlayer.z >> 4);
@@ -336,7 +336,7 @@ public class PlayerList
     public void sendEncryptedChatToAllPlayers(String message)
     {
         for (PlayerServer player : playerEntities) {
-            player.playerNetServerHandler.sendPacket(new PacketChat(message, 0, AES.keyChain.get(player.username)));
+            player.playerNetServerHandler.sendPacket(new PacketMessage(message, PacketMessage.TYPE_CHAT, AES.keyChain.get(player.username)));
         }
 
     }
@@ -603,7 +603,7 @@ public class PlayerList
         PlayerServer player = getPlayerEntity(s);
         if (player != null)
         {
-            player.playerNetServerHandler.sendPacket(new PacketChat(s1));
+            player.playerNetServerHandler.sendPacket(new PacketMessage(s1));
         }
     }
 
@@ -631,7 +631,7 @@ public class PlayerList
 
     public void sendChatMessageToAllOps(String s)
     {
-        PacketChat chatPacket = new PacketChat(s);
+        PacketMessage chatPacket = new PacketMessage(s);
         for (PlayerServer player : playerEntities) {
             if (isOp(player.uuid)) {
                 player.playerNetServerHandler.sendPacket(chatPacket);
diff --git a/game/server/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java b/game/server/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java
index 018cb51b8..930940cd7 100644
--- a/game/server/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java
+++ b/game/server/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java
@@ -3,7 +3,7 @@ package net.minecraft.server.net.command;
 import com.mojang.logging.LogUtils;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.net.command.CommandSource;
-import net.minecraft.core.net.packet.PacketChat;
+import net.minecraft.core.net.packet.PacketMessage;
 import net.minecraft.core.net.packet.Packet;
 import net.minecraft.core.util.helper.AES;
 import net.minecraft.core.util.helper.LoggedPrintStream;
@@ -89,12 +89,12 @@ public class ConsoleCommandSource implements CommandSource, IServerCommandSource
 
     @Override
     public void sendMessage(Player player, String message) {
-        this.server.playerList.sendPacketToPlayer(player.username, new PacketChat(message, AES.keyChain.get(player.username)));
+        this.server.playerList.sendPacketToPlayer(player.username, new PacketMessage(message, AES.keyChain.get(player.username)));
     }
 
     @Override
     public void sendMessageToAllPlayers(String message) {
-        this.getServer().playerList.sendPacketToAllPlayers(new PacketChat(message));
+        this.getServer().playerList.sendPacketToAllPlayers(new PacketMessage(message));
     }
 
     @Override
diff --git a/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java b/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java
index d22bdf7ce..9475420f2 100644
--- a/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java
+++ b/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java
@@ -2,7 +2,7 @@ package net.minecraft.server.net.command;
 
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.net.command.CommandSource;
-import net.minecraft.core.net.packet.PacketChat;
+import net.minecraft.core.net.packet.PacketMessage;
 import net.minecraft.core.net.packet.Packet;
 import net.minecraft.core.util.helper.AES;
 import net.minecraft.core.world.World;
@@ -88,17 +88,17 @@ public class ServerCommandSource implements CommandSource, IServerCommandSource
 
     @Override
     public void sendMessage(String message) {
-        this.player.playerNetServerHandler.sendPacket(new PacketChat(message, AES.keyChain.get(this.player.username)));
+        this.player.playerNetServerHandler.sendPacket(new PacketMessage(message, AES.keyChain.get(this.player.username)));
     }
 
     @Override
     public void sendMessage(Player player, String message) {
-        this.server.playerList.sendPacketToPlayer(player.username, new PacketChat(message, AES.keyChain.get(player.username)));
+        this.server.playerList.sendPacketToPlayer(player.username, new PacketMessage(message, AES.keyChain.get(player.username)));
     }
 
     @Override
     public void sendMessageToAllPlayers(String message) {
-        this.getServer().playerList.sendPacketToAllPlayers(new PacketChat(message));
+        this.getServer().playerList.sendPacketToAllPlayers(new PacketMessage(message));
     }
 
     @Override
diff --git a/game/server/src/main/java/net/minecraft/server/net/command/commands/CommandMe.java b/game/server/src/main/java/net/minecraft/server/net/command/commands/CommandMe.java
index fab171f39..ce26b6764 100644
--- a/game/server/src/main/java/net/minecraft/server/net/command/commands/CommandMe.java
+++ b/game/server/src/main/java/net/minecraft/server/net/command/commands/CommandMe.java
@@ -12,7 +12,7 @@ import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.util.helper.LoggedPrintStream;
 import net.minecraft.server.net.command.IServerCommandSource;
 import net.minecraft.core.net.command.exceptions.CommandExceptions;
-import net.minecraft.core.net.packet.PacketChat;
+import net.minecraft.core.net.packet.PacketMessage;
 
 public class CommandMe implements CommandManager.CommandRegistry {
     public void register(CommandDispatcher<CommandSource> dispatcher) {
@@ -28,7 +28,7 @@ public class CommandMe implements CommandManager.CommandRegistry {
                         String senderName = source.getSender().getDisplayName();
 
                         ((IServerCommandSource) source).getServer().playerList.sendPacketToAllPlayers(
-                            new PacketChat(
+                            new PacketMessage(
                             TextFormatting.LIGHT_GRAY + "* " + (source.getSender().nickname.isEmpty() ? "" : TextFormatting.ITALIC) + TextFormatting.removeAllFormatting(senderName) + " " + TextFormatting.RESET + TextFormatting.LIGHT_GRAY + message
                             )
                         );
diff --git a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerLogin.java b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerLogin.java
index 6eb917c79..71ce7fd58 100644
--- a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerLogin.java
+++ b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerLogin.java
@@ -213,12 +213,17 @@ public class PacketHandlerLogin extends PacketHandler
 
             packetHandler.sendPacket(new PacketSetSpawnPosition(chunkcoordinates.x, chunkcoordinates.y, chunkcoordinates.z));
             mcServer.playerList.setTime(player, worldserver);
-            mcServer.playerList.sendPacketToAllPlayers(new PacketChat(TextFormatting.YELLOW + player.getDisplayName() + TextFormatting.YELLOW + " joined the game."));
+            mcServer.playerList.sendPacketToAllPlayers(new PacketMessageTranslatable(
+                TextFormatting.Base.YELLOW,
+                "messages.player_joined",
+                TextFormatting.scoped(player.getDisplayName())
+
+            ));
             mcServer.playerList.updatePlayerProfile(player.username, player.nickname, player.uuid, player.score, player.chatColor, true, player.isOperator());
 
             if (mcServer.joinMessage != null && !mcServer.joinMessage.isEmpty())
             {
-                player.playerNetServerHandler.sendPacket(new PacketChat(mcServer.joinMessage));
+                player.playerNetServerHandler.sendPacket(new PacketMessage(mcServer.joinMessage));
             }
 
             mcServer.playerList.playerLoggedIn(player);
diff --git a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
index f537cb748..c4b7aeb1a 100644
--- a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
+++ b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
@@ -91,7 +91,11 @@ public class PacketHandlerServer extends PacketHandler
         this.playerEntity.func_30002_A();
         sendPacket(new PacketDisconnect(s));
         this.netManager.serverShutdown();
-        this.mcServer.playerList.sendPacketToAllPlayers(new PacketChat(this.playerEntity.getDisplayName() + TextFormatting.YELLOW + " was kicked from the game."));
+        this.mcServer.playerList.sendPacketToAllPlayers(new PacketMessageTranslatable(
+            TextFormatting.Base.YELLOW,
+            "messages.player_kicked",
+            TextFormatting.scoped(this.playerEntity.getDisplayName())
+        ));
         this.mcServer.playerList.updatePlayerProfile(this.playerEntity.username, this.playerEntity.nickname, this.playerEntity.uuid, this.playerEntity.score, this.playerEntity.chatColor, false, this.playerEntity.isOperator());
         this.mcServer.playerList.playerLoggedOut(this.playerEntity);
         this.connectionClosed = true;
@@ -447,7 +451,11 @@ public class PacketHandlerServer extends PacketHandler
     @Override
     public void handleErrorMessage(String message, Object[] objects) {
         LOGGER.info(this.playerEntity.username + " lost connection: " + message);
-        this.mcServer.playerList.sendPacketToAllPlayers(new PacketChat(this.playerEntity.getDisplayName() + TextFormatting.YELLOW + " left the game."));
+        this.mcServer.playerList.sendPacketToAllPlayers(new PacketMessageTranslatable(
+            TextFormatting.Base.YELLOW,
+            "messages.player_left",
+            TextFormatting.scoped(this.playerEntity.getDisplayName())
+        ));
         this.mcServer.playerList.updatePlayerProfile(this.playerEntity.username, this.playerEntity.nickname, this.playerEntity.uuid, this.playerEntity.score, this.playerEntity.chatColor, false, this.playerEntity.isOperator());
         this.mcServer.playerList.playerLoggedOut(this.playerEntity);
         this.connectionClosed = true;
@@ -481,13 +489,13 @@ public class PacketHandlerServer extends PacketHandler
     }
 
     @Override
-    public void handleChat(@NotNull PacketChat packet) {
+    public void handleMessage(@NotNull PacketMessage packet) {
         String message;
         if (packet.encrypted) {
             try {
                 message = AES.decrypt(packet.message, AES.keyChain.get(this.playerEntity.username));
             } catch (Exception e) {
-                throw new RuntimeException(PacketChat.ENCRYPTION_ERROR_MESSAGE, e);
+                throw new RuntimeException(PacketMessage.ENCRYPTION_ERROR_MESSAGE, e);
             }
         } else {
             message = packet.message;
@@ -500,7 +508,10 @@ public class PacketHandlerServer extends PacketHandler
         message = message.trim();
 
         if (!NetCharacters.isAllowed(message)) {
-            sendPacket(new PacketChat(String.valueOf(TextFormatting.GRAY) + TextFormatting.ITALIC + "[SERVER] Illegal characters in chat message."));
+            this.sendPacket(new PacketMessageTranslatable(
+                TextFormatting.Base.GRAY.withStyle(false, false, false, false, true, false),
+                "messages.illegal_characters"
+            ));
             return;
         }
 
@@ -519,7 +530,7 @@ public class PacketHandlerServer extends PacketHandler
         try {
             this.playerEntity.world.getCommandManager().execute(s.substring(1), serverCommandSource);
         } catch (CommandSyntaxException e) {
-            this.playerEntity.playerNetServerHandler.sendPacket(new PacketChat(TextFormatting.RED + e.getMessage(), AES.keyChain.get(this.playerEntity.username)));
+            this.playerEntity.playerNetServerHandler.sendPacket(new PacketMessage(TextFormatting.RED + e.getMessage(), AES.keyChain.get(this.playerEntity.username)));
         }
     }
 
@@ -569,7 +580,7 @@ public class PacketHandlerServer extends PacketHandler
 
     @Override
     public void logInfo(String s) {
-        sendPacket(new PacketChat("\2477" + s));
+        sendPacket(new PacketMessage("\2477" + s));
     }
 
     @Override
@@ -738,9 +749,9 @@ public class PacketHandlerServer extends PacketHandler
     public void handleCustomPayload(@NotNull PacketCustomPayload packetCustomPayload) {
         if (PacketCustomPayload.CHANNEL_ROTATION_LOCK.equals(packetCustomPayload.channel)) {
             if (packetCustomPayload.data.length == 4) {
-                this.playerEntity.rotationLock = Direction.fromId(packetCustomPayload.data[0]);
-                this.playerEntity.rotationLockHorizontal = Direction.fromId(packetCustomPayload.data[1]);
-                this.playerEntity.rotationLockVertical = Direction.fromId(packetCustomPayload.data[2]);
+                this.playerEntity.rotationLock = Direction.fromIdOrDefault(null, packetCustomPayload.data[0]);
+                this.playerEntity.rotationLockHorizontal = Direction.fromIdOrDefault(null, packetCustomPayload.data[1]);
+                this.playerEntity.rotationLockVertical = Direction.fromIdOrDefault(null, packetCustomPayload.data[2]);
                 this.playerEntity.placementModeOverride = PlacementMode.get(packetCustomPayload.data[3]);
             }
         } else if (PacketCustomPayload.CHANNEL_FLAG.equals(packetCustomPayload.channel)) {
diff --git a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
index fe99dacb7..1cbab820d 100644
--- a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
+++ b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
@@ -8,7 +8,8 @@ import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.net.packet.PacketBlockEvent;
-import net.minecraft.core.net.packet.PacketChat;
+import net.minecraft.core.net.packet.PacketMessage;
+import net.minecraft.core.net.packet.PacketMessageTranslatable;
 import net.minecraft.core.net.packet.PacketCustomPayload;
 import net.minecraft.core.net.packet.PacketEntityEvent;
 import net.minecraft.core.net.packet.PacketEntityTagData;
@@ -124,67 +125,85 @@ public class WorldServer extends World {
 
     @Override
     protected void updateSleepingPlayers() {
-        if(areEnoughPlayersFullyAsleep())
-        {
-            boolean wasInterrupted = false;
-            if(getSpawnerConfig().canHostileSpawn(this) && getPlayersRequiredToSkipNight() <= 1)
-            {
-                wasInterrupted = SpawnerMobs.performSleepSpawning(this, players);
-            }
-            if(!wasInterrupted)
-            {
-                if(MinecraftServer.getInstance() != null && players.size() > 1) {
-                    if(getPlayersRequiredToSkipNight() <= 1) {
-                        Player player = null;
-                        for(Player player2 : players) {
-                            if(player2.isPlayerFullyAsleep()) {
-                                player = player2;
-                            }
-                        }
-                        if(player != null) {
-                            MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(new PacketChat(TextFormatting.YELLOW + player.getDisplayName() + TextFormatting.ORANGE + " went to sleep. Sweet dreams!"), dimension.id);
-                        }
-                    }
-                }
-
-                long timePlusOneDay = getLevelData().getWorldTime() + Global.DAY_LENGTH_TICKS;
-                getLevelData().setWorldTime(timePlusOneDay - timePlusOneDay % Global.DAY_LENGTH_TICKS + getWorldType().getSunriseTick(this) + Global.DAY_LENGTH_TICKS / 24);
-                wakeUpAllPlayers();
+        if (!this.areEnoughPlayersFullyAsleep()) return;
+
+        final boolean wasInterrupted =
+            getSpawnerConfig().canHostileSpawn(this) &&
+            getPlayersRequiredToSkipNight() <= 1 &&
+            SpawnerMobs.performSleepSpawning(this, players);
+        if (wasInterrupted) return;
+
+        send_message: {
+            if (MinecraftServer.getInstance() == null) break send_message;
+            if (players.size() <= 1) break send_message;
+            if (this.getPlayersRequiredToSkipNight() <= 1) break send_message;
+
+            Player sleeper = null;
+            for (final var p : players) {
+                if (!p.isPlayerFullyAsleep()) continue;
+                sleeper = p;
+                break;
             }
+            if (sleeper == null) break send_message;
+
+            MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(
+                new PacketMessageTranslatable(
+                    TextFormatting.Base.ORANGE,
+                    "messages.sleep.succeed",
+                    TextFormatting.scoped(sleeper.getDisplayName())),
+                dimension.id
+            );
         }
+
+        long timePlusOneDay = getLevelData().getWorldTime() + Global.DAY_LENGTH_TICKS;
+        getLevelData().setWorldTime(timePlusOneDay - timePlusOneDay % Global.DAY_LENGTH_TICKS + getWorldType().getSunriseTick(this) + Global.DAY_LENGTH_TICKS / 24);
+        wakeUpAllPlayers();
     }
 
     @Override
-    public void updateEnoughPlayersSleepingFlag(Player player)
-    {
-        enoughPlayersSleeping = false;
-        if(players.size() > 0) {
-            int playersSleeping = 0;
-            int req = getPlayersRequiredToSkipNight();
-            for(Player p : players)
-                if(p.isPlayerSleeping()) playersSleeping++;
-            if(playersSleeping >= req) {
-                enoughPlayersSleeping = true;
-            }
+    public void updateEnoughPlayersSleepingFlag(Player player) {
+        if (players.size() <= 0) return;
+        this.enoughPlayersSleeping = false;
 
-            if(MinecraftServer.getInstance() != null && player != null && players.size() > 1 && req > 1) {
-                int moreReq = req - playersSleeping;
-                if(player.isPlayerSleeping()) {
-                    MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(new PacketChat(TextFormatting.YELLOW + player.username + TextFormatting.ORANGE + " went to bed."), dimension.id);
-                }else {
-                    MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(new PacketChat(TextFormatting.YELLOW + player.username + TextFormatting.ORANGE + " has left their bed."), dimension.id);
-                }
-                if(moreReq > 0) {
-                    if(moreReq > 1) {
-                        MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(new PacketChat(TextFormatting.LIGHT_GRAY + "" + moreReq + " more players are required to sleep to skip to daytime"), dimension.id);
-                    }else {
-                        MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(new PacketChat(TextFormatting.LIGHT_GRAY + "1 more player is required to sleep to skip to daytime"), dimension.id);
-                    }
-
-                }
+        final int required = getPlayersRequiredToSkipNight();
+        int playersSleeping = 0;
+        for (final var p : players) {
+            if (!p.isPlayerSleeping()) break;
+            if (playersSleeping >= required) {
+                this.enoughPlayersSleeping = true;
+                break;
             }
+            playersSleeping++;
         }
 
+        if (player == null) return;
+        if (MinecraftServer.getInstance() == null) return;
+        if (players.size() <= 1) return;
+        if (required <= 1) return;
+
+        MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(
+            new PacketMessageTranslatable(
+                TextFormatting.Base.ORANGE,
+                (player.isPlayerSleeping()) 
+                    ? "messages.sleep.enter_bed" 
+                    : "messages.sleep.exit_bed",
+                TextFormatting.scoped(player.getDisplayName())),
+            dimension.id
+        );
+
+        if (this.enoughPlayersSleeping) return;
+        final int moreReq = required - playersSleeping;
+        assert moreReq > 0;
+
+        MinecraftServer.getInstance().playerList.sendPacketToAllPlayersInDimension(
+            new PacketMessageTranslatable(
+                TextFormatting.Base.LIGHT_GRAY,
+                (moreReq != 1)
+                    ? "messages.sleep.more_required"
+                    : "messages.sleep.more_required.singular",
+                Integer.toString(moreReq)),
+            dimension.id
+        );
     }
 
     public @NotNull Entity getEntityFromId(int i)
@@ -268,7 +287,7 @@ public class WorldServer extends World {
 
     @Override
     public void sendGlobalMessage(String message){
-        mcServer.playerList.sendPacketToAllPlayers(new PacketChat(message));
+        mcServer.playerList.sendPacketToAllPlayers(new PacketMessage(message));
     }
     @Override
     public void addRainbow(int rainbowTicks){
