Update to JoinGamePacket and RespawnPacket (#1640)

* Add death location support to JoinGamePacket
This commit is contained in:
Alexander 2023-03-22 03:22:24 +00:00 committed by GitHub
parent 784875943a
commit c496ee3572
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 14 deletions

View File

@ -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.ServerPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; 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.*;
import net.minestom.server.network.packet.server.play.data.DeathLocation;
import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection; 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:chat_type", Messenger.chatRegistry(),
"minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT(), "minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT(),
"minecraft:worldgen/biome", MinecraftServer.getBiomeManager().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, final JoinGamePacket joinGamePacket = new JoinGamePacket(getEntityId(), false, gameMode, null,
List.of(dimensionType.getName().asString()), nbt, dimensionType.toString(), dimensionType.getName().asString(), List.of(dimensionType.getName().asString()), nbt, dimensionType.toString(), dimensionType.getName().asString(),
0, 0, MinecraftServer.getChunkViewDistance(), MinecraftServer.getChunkViewDistance(), 0, 0, MinecraftServer.getChunkViewDistance(), MinecraftServer.getChunkViewDistance(),
false, true, false, levelFlat); false, true, false, levelFlat, deathLocation);
sendPacket(joinGamePacket); sendPacket(joinGamePacket);
// Server brand name // Server brand name
@ -443,8 +448,11 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
setFireForDuration(0); setFireForDuration(0);
setOnFire(false); setOnFire(false);
refreshHealth(); refreshHealth();
// TODO: Add some way to determine last death location
final DeathLocation deathLocation = null;
sendPacket(new RespawnPacket(getDimensionType().toString(), getDimensionType().getName().asString(), 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); PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(this);
EventDispatcher.call(respawnEvent); EventDispatcher.call(respawnEvent);
@ -968,8 +976,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
final PlayerInfoPacket removePlayerPacket = getRemovePlayerToList(); final PlayerInfoPacket removePlayerPacket = getRemovePlayerToList();
final PlayerInfoPacket addPlayerPacket = getAddPlayerToList(); 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(), 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(removePlayerPacket);
sendPacket(destroyEntitiesPacket); sendPacket(destroyEntitiesPacket);
@ -1341,8 +1351,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
Check.argCondition(dimensionType.equals(getDimensionType()), Check.argCondition(dimensionType.equals(getDimensionType()),
"The dimension needs to be different than the current one!"); "The dimension needs to be different than the current one!");
this.dimensionType = dimensionType; this.dimensionType = dimensionType;
// TODO: Add some way to determine last death location
final DeathLocation deathLocation = null;
sendPacket(new RespawnPacket(dimensionType.toString(), getDimensionType().getName().asString(), sendPacket(new RespawnPacket(dimensionType.toString(), getDimensionType().getName().asString(),
0, gameMode, gameMode, false, levelFlat, true)); 0, gameMode, gameMode, false, levelFlat, true, deathLocation));
refreshClientStateAfterRespawn(); refreshClientStateAfterRespawn();
} }

View File

@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
import net.minestom.server.item.ItemStack; 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.Direction;
import net.minestom.server.utils.Either; import net.minestom.server.utils.Either;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
@ -57,6 +58,7 @@ public final class NetworkBuffer {
public static final Type<int[]> VILLAGER_DATA = NetworkBufferTypes.VILLAGER_DATA; public static final Type<int[]> VILLAGER_DATA = NetworkBufferTypes.VILLAGER_DATA;
public static final Type<Integer> OPT_VAR_INT = NetworkBufferTypes.OPT_VAR_INT; public static final Type<Integer> OPT_VAR_INT = NetworkBufferTypes.OPT_VAR_INT;
public static final Type<Entity.Pose> POSE = NetworkBufferTypes.POSE; public static final Type<Entity.Pose> POSE = NetworkBufferTypes.POSE;
public static final Type<DeathLocation> DEATH_LOCATION = NetworkBufferTypes.DEATH_LOCATION;
ByteBuffer nioBuffer; ByteBuffer nioBuffer;
final boolean resizable; final boolean resizable;

View File

@ -7,6 +7,7 @@ import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.network.packet.server.play.data.DeathLocation;
import net.minestom.server.utils.Direction; import net.minestom.server.utils.Direction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
@ -505,6 +506,23 @@ final class NetworkBufferTypes {
final int ordinal = buffer.read(VAR_INT); final int ordinal = buffer.read(VAR_INT);
return Entity.Pose.values()[ordinal]; return Entity.Pose.values()[ordinal];
}); });
static final TypeImpl<DeathLocation> 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<T>(@NotNull Class<T> type, record TypeImpl<T>(@NotNull Class<T> type,
@NotNull TypeWriter<T> writer, @NotNull TypeWriter<T> writer,

View File

@ -4,7 +4,9 @@ import net.minestom.server.entity.GameMode;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; 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.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.List; 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, public record JoinGamePacket(int entityId, boolean isHardcore, GameMode gameMode, GameMode previousGameMode,
List<String> worlds, NBTCompound dimensionCodec, String dimensionType, String world, List<String> worlds, NBTCompound dimensionCodec, String dimensionType, String world,
long hashedSeed, int maxPlayers, int viewDistance, int simulationDistance, long hashedSeed, int maxPlayers, int viewDistance, int simulationDistance,
boolean reducedDebugInfo, boolean enableRespawnScreen, boolean isDebug, boolean reducedDebugInfo, boolean enableRespawnScreen, boolean isDebug, boolean isFlat,
boolean isFlat) implements ServerPacket { DeathLocation deathLocation) implements ServerPacket {
public JoinGamePacket { public JoinGamePacket {
worlds = List.copyOf(worlds); worlds = List.copyOf(worlds);
} }
public JoinGamePacket(@NotNull NetworkBuffer reader) { 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.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(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 @Override
@ -54,7 +57,7 @@ public record JoinGamePacket(int entityId, boolean isHardcore, GameMode gameMode
//is flat //is flat
writer.write(BOOLEAN, isFlat); writer.write(BOOLEAN, isFlat);
writer.write(BOOLEAN, false); writer.write(DEATH_LOCATION, deathLocation);
} }
@Override @Override
@ -62,4 +65,14 @@ public record JoinGamePacket(int entityId, boolean isHardcore, GameMode gameMode
return ServerPacketIdentifier.JOIN_GAME; 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);
}
} }

View File

@ -4,17 +4,19 @@ import net.minestom.server.entity.GameMode;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; 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.NotNull;
import static net.minestom.server.network.NetworkBuffer.*; import static net.minestom.server.network.NetworkBuffer.*;
public record RespawnPacket(String dimensionType, String worldName, public record RespawnPacket(String dimensionType, String worldName,
long hashedSeed, GameMode gameMode, GameMode previousGameMode, 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) { public RespawnPacket(@NotNull NetworkBuffer reader) {
this(reader.read(STRING), reader.read(STRING), this(reader.read(STRING), reader.read(STRING),
reader.read(LONG), GameMode.values()[reader.read(BYTE)], GameMode.values()[reader.read(BYTE)], reader.read(LONG), GameMode.fromId(reader.read(BYTE)), GameMode.fromId(reader.read(BYTE)),
reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(BOOLEAN)); reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(BOOLEAN), reader.read(DEATH_LOCATION));
} }
@Override @Override
@ -27,8 +29,7 @@ public record RespawnPacket(String dimensionType, String worldName,
writer.write(BOOLEAN, isDebug); writer.write(BOOLEAN, isDebug);
writer.write(BOOLEAN, isFlat); writer.write(BOOLEAN, isFlat);
writer.write(BOOLEAN, copyMeta); writer.write(BOOLEAN, copyMeta);
writer.write(DEATH_LOCATION, deathLocation);
writer.write(BOOLEAN, false);
} }
@Override @Override

View File

@ -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) {
}