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 extends BlockModel { 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(); + 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 regionFiles, int conversionsPerformed, int totalConversions, ProgressListener progress) + int convertDimensionRegions(@NotNull Dimension dimension, @NotNull ArrayList 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 regionFiles, int conversionsPerformed, int totalConversions, ProgressListener progress) + int convertDimensionRegions(@NotNull Dimension dimension, @NotNull ArrayList 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 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 regionFiles, int conversionsPerformed, int totalConversions, ProgressListener progress); + abstract int convertDimensionRegions(@NotNull Dimension dimension, @NotNull ArrayList regionFiles, int conversionsPerformed, int totalConversions, @NotNull ProgressListener progress); ArrayList 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 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){