diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index e7261e24e..25be6907c 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -55,6 +55,7 @@ import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.packet.server.play.*; +import net.minestom.server.network.packet.server.play.data.DeathLocation; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; @@ -250,10 +251,14 @@ public class Player extends LivingEntity implements CommandSender, Localizable, "minecraft:chat_type", Messenger.chatRegistry(), "minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT(), "minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT())); + + // TODO: Add some way to determine last death location + final DeathLocation deathLocation = null; + final JoinGamePacket joinGamePacket = new JoinGamePacket(getEntityId(), false, gameMode, null, List.of(dimensionType.getName().asString()), nbt, dimensionType.toString(), dimensionType.getName().asString(), 0, 0, MinecraftServer.getChunkViewDistance(), MinecraftServer.getChunkViewDistance(), - false, true, false, levelFlat); + false, true, false, levelFlat, deathLocation); sendPacket(joinGamePacket); // Server brand name @@ -443,8 +448,11 @@ public class Player extends LivingEntity implements CommandSender, Localizable, setFireForDuration(0); setOnFire(false); refreshHealth(); + + // TODO: Add some way to determine last death location + final DeathLocation deathLocation = null; sendPacket(new RespawnPacket(getDimensionType().toString(), getDimensionType().getName().asString(), - 0, gameMode, gameMode, false, levelFlat, true)); + 0, gameMode, gameMode, false, levelFlat, true, deathLocation)); PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(this); EventDispatcher.call(respawnEvent); @@ -968,8 +976,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable, final PlayerInfoPacket removePlayerPacket = getRemovePlayerToList(); final PlayerInfoPacket addPlayerPacket = getAddPlayerToList(); + // TODO: Add some way to determine last death location + final DeathLocation deathLocation = null; RespawnPacket respawnPacket = new RespawnPacket(getDimensionType().toString(), getDimensionType().getName().asString(), - 0, gameMode, gameMode, false, levelFlat, true); + 0, gameMode, gameMode, false, levelFlat, true, deathLocation); sendPacket(removePlayerPacket); sendPacket(destroyEntitiesPacket); @@ -1341,8 +1351,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable, Check.argCondition(dimensionType.equals(getDimensionType()), "The dimension needs to be different than the current one!"); this.dimensionType = dimensionType; + // TODO: Add some way to determine last death location + final DeathLocation deathLocation = null; sendPacket(new RespawnPacket(dimensionType.toString(), getDimensionType().getName().asString(), - 0, gameMode, gameMode, false, levelFlat, true)); + 0, gameMode, gameMode, false, levelFlat, true, deathLocation)); refreshClientStateAfterRespawn(); } diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index c7e827a04..11110d8f2 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Entity; import net.minestom.server.item.ItemStack; +import net.minestom.server.network.packet.server.play.data.DeathLocation; import net.minestom.server.utils.Direction; import net.minestom.server.utils.Either; import org.jetbrains.annotations.ApiStatus; @@ -57,6 +58,7 @@ public final class NetworkBuffer { public static final Type VILLAGER_DATA = NetworkBufferTypes.VILLAGER_DATA; public static final Type OPT_VAR_INT = NetworkBufferTypes.OPT_VAR_INT; public static final Type POSE = NetworkBufferTypes.POSE; + public static final Type DEATH_LOCATION = NetworkBufferTypes.DEATH_LOCATION; ByteBuffer nioBuffer; final boolean resizable; diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTypes.java b/src/main/java/net/minestom/server/network/NetworkBufferTypes.java index 20b60bc65..ad68078b5 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTypes.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTypes.java @@ -7,6 +7,7 @@ import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.network.packet.server.play.data.DeathLocation; import net.minestom.server.utils.Direction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; @@ -505,6 +506,23 @@ final class NetworkBufferTypes { final int ordinal = buffer.read(VAR_INT); return Entity.Pose.values()[ordinal]; }); + static final TypeImpl DEATH_LOCATION = new TypeImpl<>(DeathLocation.class, + (buffer, value) -> { + if (value == null) { + buffer.write(BOOLEAN, false); + } else { + buffer.write(BOOLEAN, true); + buffer.write(STRING, value.dimension()); + buffer.write(BLOCK_POSITION, value.position()); + } + return -1; + }, + buffer -> { + if (buffer.read(BOOLEAN)) { + return new DeathLocation(buffer.read(STRING), buffer.read(BLOCK_POSITION)); + } + return null; + }); record TypeImpl(@NotNull Class type, @NotNull TypeWriter writer, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java index 6935794b6..074a34510 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java @@ -4,7 +4,9 @@ import net.minestom.server.entity.GameMode; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.network.packet.server.play.data.DeathLocation; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.List; @@ -14,17 +16,18 @@ import static net.minestom.server.network.NetworkBuffer.*; public record JoinGamePacket(int entityId, boolean isHardcore, GameMode gameMode, GameMode previousGameMode, List worlds, NBTCompound dimensionCodec, String dimensionType, String world, long hashedSeed, int maxPlayers, int viewDistance, int simulationDistance, - boolean reducedDebugInfo, boolean enableRespawnScreen, boolean isDebug, - boolean isFlat) implements ServerPacket { + boolean reducedDebugInfo, boolean enableRespawnScreen, boolean isDebug, boolean isFlat, + DeathLocation deathLocation) implements ServerPacket { public JoinGamePacket { worlds = List.copyOf(worlds); } public JoinGamePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(BOOLEAN), GameMode.fromId(reader.read(BYTE)), GameMode.fromId(reader.read(BYTE)), + this(reader.read(INT), reader.read(BOOLEAN), GameMode.fromId(reader.read(BYTE)), getNullableGameMode(reader.read(BYTE)), reader.readCollection(STRING), (NBTCompound) reader.read(NBT), reader.read(STRING), reader.read(STRING), reader.read(LONG), reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), - reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(BOOLEAN)); + reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(BOOLEAN), + reader.read(DEATH_LOCATION)); } @Override @@ -54,7 +57,7 @@ public record JoinGamePacket(int entityId, boolean isHardcore, GameMode gameMode //is flat writer.write(BOOLEAN, isFlat); - writer.write(BOOLEAN, false); + writer.write(DEATH_LOCATION, deathLocation); } @Override @@ -62,4 +65,14 @@ public record JoinGamePacket(int entityId, boolean isHardcore, GameMode gameMode return ServerPacketIdentifier.JOIN_GAME; } + /** + * This method exists in lieu of a NetworkBufferType since -1 is only a + * valid value in this packet and changing behaviour of GameMode.fromId() + * to be nullable would be too big of a change. Also, game modes are often + * represented as other data types, including floats. + */ + private static @Nullable GameMode getNullableGameMode(final byte id) { + return id == (byte) -1 ? null : GameMode.fromId(id); + } + } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java index e8f7c5817..2aa51c061 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java @@ -4,17 +4,19 @@ import net.minestom.server.entity.GameMode; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.network.packet.server.play.data.DeathLocation; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record RespawnPacket(String dimensionType, String worldName, long hashedSeed, GameMode gameMode, GameMode previousGameMode, - boolean isDebug, boolean isFlat, boolean copyMeta) implements ServerPacket { + boolean isDebug, boolean isFlat, boolean copyMeta, + DeathLocation deathLocation) implements ServerPacket { public RespawnPacket(@NotNull NetworkBuffer reader) { this(reader.read(STRING), reader.read(STRING), - reader.read(LONG), GameMode.values()[reader.read(BYTE)], GameMode.values()[reader.read(BYTE)], - reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(BOOLEAN)); + reader.read(LONG), GameMode.fromId(reader.read(BYTE)), GameMode.fromId(reader.read(BYTE)), + reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(DEATH_LOCATION)); } @Override @@ -27,8 +29,7 @@ public record RespawnPacket(String dimensionType, String worldName, writer.write(BOOLEAN, isDebug); writer.write(BOOLEAN, isFlat); writer.write(BOOLEAN, copyMeta); - - writer.write(BOOLEAN, false); + writer.write(DEATH_LOCATION, deathLocation); } @Override diff --git a/src/main/java/net/minestom/server/network/packet/server/play/data/DeathLocation.java b/src/main/java/net/minestom/server/network/packet/server/play/data/DeathLocation.java new file mode 100644 index 000000000..db6d8fbb0 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/data/DeathLocation.java @@ -0,0 +1,8 @@ +package net.minestom.server.network.packet.server.play.data; + +import net.minestom.server.coordinate.Point; +import org.jetbrains.annotations.NotNull; + +public record DeathLocation(@NotNull String dimension, @NotNull Point position) { + +} \ No newline at end of file