mirror of https://github.com/Minestom/Minestom.git
241 lines
8.9 KiB
Java
241 lines
8.9 KiB
Java
package net.minestom.server.network.packet.server.play;
|
|
|
|
import net.kyori.adventure.text.Component;
|
|
import net.minestom.server.adventure.ComponentHolder;
|
|
import net.minestom.server.crypto.PlayerPublicKey;
|
|
import net.minestom.server.entity.GameMode;
|
|
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
|
|
import net.minestom.server.network.packet.server.ServerPacket;
|
|
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
|
import net.minestom.server.utils.binary.BinaryReader;
|
|
import net.minestom.server.utils.binary.BinaryWriter;
|
|
import net.minestom.server.utils.binary.Writeable;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.util.*;
|
|
import java.util.function.UnaryOperator;
|
|
|
|
public record PlayerInfoPacket(@NotNull Action action,
|
|
@NotNull List<Entry> entries) implements ComponentHoldingServerPacket {
|
|
public PlayerInfoPacket {
|
|
entries = List.copyOf(entries);
|
|
for (Entry entry : entries) {
|
|
if (!entry.getClass().equals(action.getClazz()))
|
|
throw new IllegalArgumentException("Invalid entry class for action " + action);
|
|
}
|
|
}
|
|
|
|
public PlayerInfoPacket(@NotNull Action action, @NotNull Entry entry) {
|
|
this(action, List.of(entry));
|
|
}
|
|
|
|
public PlayerInfoPacket(BinaryReader reader) {
|
|
this(read(reader));
|
|
}
|
|
|
|
private PlayerInfoPacket(PlayerInfoPacket packet) {
|
|
this(packet.action, packet.entries);
|
|
}
|
|
|
|
private static PlayerInfoPacket read(BinaryReader reader) {
|
|
var action = Action.values()[reader.readVarInt()];
|
|
final int playerInfoCount = reader.readVarInt();
|
|
List<Entry> entries = new ArrayList<>(playerInfoCount);
|
|
for (int i = 0; i < playerInfoCount; i++) {
|
|
final UUID uuid = reader.readUuid();
|
|
entries.add(switch (action) {
|
|
case ADD_PLAYER -> new AddPlayer(uuid, reader);
|
|
case UPDATE_GAMEMODE -> new UpdateGameMode(uuid, reader);
|
|
case UPDATE_LATENCY -> new UpdateLatency(uuid, reader);
|
|
case UPDATE_DISPLAY_NAME -> new UpdateDisplayName(uuid, reader);
|
|
case REMOVE_PLAYER -> new RemovePlayer(uuid);
|
|
});
|
|
}
|
|
return new PlayerInfoPacket(action, entries);
|
|
}
|
|
|
|
@Override
|
|
public void write(@NotNull BinaryWriter writer) {
|
|
writer.writeVarInt(action.ordinal());
|
|
writer.writeVarIntList(entries, (w, entry) -> {
|
|
w.writeUuid(entry.uuid());
|
|
entry.write(w);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public int getId() {
|
|
return ServerPacketIdentifier.PLAYER_INFO;
|
|
}
|
|
|
|
@Override
|
|
public @NotNull Collection<Component> components() {
|
|
switch (this.action) {
|
|
case ADD_PLAYER:
|
|
case UPDATE_DISPLAY_NAME:
|
|
List<Component> components = new ArrayList<>();
|
|
for (Entry entry : entries) {
|
|
if (entry instanceof ComponentHolder) {
|
|
components.addAll(((ComponentHolder<? extends Entry>) entry).components());
|
|
}
|
|
}
|
|
return components;
|
|
default:
|
|
return Collections.emptyList();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
|
|
return switch (action) {
|
|
case ADD_PLAYER, UPDATE_DISPLAY_NAME -> {
|
|
List<Entry> entries = new ArrayList<>(this.entries.size());
|
|
for (Entry entry : this.entries) {
|
|
if (entry instanceof ComponentHolder) {
|
|
entries.add(((ComponentHolder<? extends Entry>) entry).copyWithOperator(operator));
|
|
} else {
|
|
entries.add(entry);
|
|
}
|
|
}
|
|
yield new PlayerInfoPacket(action, entries);
|
|
}
|
|
default -> this;
|
|
};
|
|
}
|
|
|
|
public enum Action {
|
|
ADD_PLAYER(AddPlayer.class),
|
|
UPDATE_GAMEMODE(UpdateGameMode.class),
|
|
UPDATE_LATENCY(UpdateLatency.class),
|
|
UPDATE_DISPLAY_NAME(UpdateDisplayName.class),
|
|
REMOVE_PLAYER(RemovePlayer.class);
|
|
|
|
private final Class<? extends Entry> clazz;
|
|
|
|
Action(Class<? extends Entry> clazz) {
|
|
this.clazz = clazz;
|
|
}
|
|
|
|
@NotNull
|
|
public Class<? extends Entry> getClazz() {
|
|
return clazz;
|
|
}
|
|
}
|
|
|
|
public sealed interface Entry extends Writeable
|
|
permits AddPlayer, UpdateGameMode, UpdateLatency, UpdateDisplayName, RemovePlayer {
|
|
UUID uuid();
|
|
}
|
|
|
|
public record AddPlayer(UUID uuid, String name, List<Property> properties, GameMode gameMode, int ping,
|
|
@Nullable Component displayName,
|
|
@Nullable PlayerPublicKey playerPublicKey) implements Entry, ComponentHolder<AddPlayer> {
|
|
public AddPlayer {
|
|
properties = List.copyOf(properties);
|
|
}
|
|
|
|
public AddPlayer(UUID uuid, BinaryReader reader) {
|
|
this(uuid, reader.readSizedString(),
|
|
reader.readVarIntList(Property::new),
|
|
GameMode.values()[reader.readVarInt()], reader.readVarInt(),
|
|
reader.readBoolean() ? reader.readComponent() : null,
|
|
reader.readBoolean() ? new PlayerPublicKey(reader) : null);
|
|
}
|
|
|
|
@Override
|
|
public void write(BinaryWriter writer) {
|
|
writer.writeSizedString(name);
|
|
writer.writeVarIntList(properties, BinaryWriter::write);
|
|
writer.writeVarInt(gameMode.id());
|
|
writer.writeVarInt(ping);
|
|
writer.writeBoolean(displayName != null);
|
|
if (displayName != null) writer.writeComponent(displayName);
|
|
writer.writeBoolean(playerPublicKey != null);
|
|
if (playerPublicKey != null) writer.write(playerPublicKey);
|
|
}
|
|
|
|
@Override
|
|
public @NotNull Collection<Component> components() {
|
|
return displayName != null ? Collections.singleton(displayName) : Collections.emptyList();
|
|
}
|
|
|
|
@Override
|
|
public @NotNull AddPlayer copyWithOperator(@NotNull UnaryOperator<Component> operator) {
|
|
return displayName != null ?
|
|
new AddPlayer(uuid, name, properties, gameMode, ping, operator.apply(displayName), playerPublicKey) : this;
|
|
}
|
|
|
|
public record Property(@NotNull String name, @NotNull String value,
|
|
@Nullable String signature) implements Writeable {
|
|
public Property(String name, String value) {
|
|
this(name, value, null);
|
|
}
|
|
|
|
public Property(BinaryReader reader) {
|
|
this(reader.readSizedString(), reader.readSizedString(),
|
|
reader.readBoolean() ? reader.readSizedString() : null);
|
|
}
|
|
|
|
@Override
|
|
public void write(BinaryWriter writer) {
|
|
writer.writeSizedString(name);
|
|
writer.writeSizedString(value);
|
|
writer.writeBoolean(signature != null);
|
|
if (signature != null) writer.writeSizedString(signature);
|
|
}
|
|
}
|
|
}
|
|
|
|
public record UpdateGameMode(UUID uuid, GameMode gameMode) implements Entry {
|
|
public UpdateGameMode(UUID uuid, BinaryReader reader) {
|
|
this(uuid, GameMode.fromId((byte) reader.readVarInt()));
|
|
}
|
|
|
|
@Override
|
|
public void write(BinaryWriter writer) {
|
|
writer.writeVarInt(gameMode.id());
|
|
}
|
|
}
|
|
|
|
public record UpdateLatency(UUID uuid, int ping) implements Entry {
|
|
public UpdateLatency(UUID uuid, BinaryReader reader) {
|
|
this(uuid, reader.readVarInt());
|
|
}
|
|
|
|
@Override
|
|
public void write(BinaryWriter writer) {
|
|
writer.writeVarInt(ping);
|
|
}
|
|
}
|
|
|
|
public record UpdateDisplayName(@NotNull UUID uuid,
|
|
@Nullable Component displayName) implements Entry, ComponentHolder<UpdateDisplayName> {
|
|
public UpdateDisplayName(UUID uuid, BinaryReader reader) {
|
|
this(uuid, reader.readBoolean() ? reader.readComponent() : null);
|
|
}
|
|
|
|
@Override
|
|
public void write(BinaryWriter writer) {
|
|
writer.writeBoolean(displayName != null);
|
|
if (displayName != null) writer.writeComponent(displayName);
|
|
}
|
|
|
|
@Override
|
|
public @NotNull Collection<Component> components() {
|
|
return displayName != null ? Collections.singleton(displayName) : Collections.emptyList();
|
|
}
|
|
|
|
@Override
|
|
public @NotNull UpdateDisplayName copyWithOperator(@NotNull UnaryOperator<Component> operator) {
|
|
return displayName != null ? new UpdateDisplayName(uuid, operator.apply(displayName)) : this;
|
|
}
|
|
}
|
|
|
|
public record RemovePlayer(@NotNull UUID uuid) implements Entry {
|
|
@Override
|
|
public void write(BinaryWriter writer) {
|
|
}
|
|
}
|
|
}
|