minecraft-src/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
2025-07-04 03:15:13 +03:00

209 lines
8.2 KiB
Java

package net.minecraft.network.protocol.game;
import com.google.common.base.MoreObjects;
import com.mojang.authlib.GameProfile;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import net.minecraft.Optionull;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentSerialization;
import net.minecraft.network.chat.RemoteChatSession;
import net.minecraft.network.chat.RemoteChatSession.Data;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.PacketType;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket.Action.Reader;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket.Action.Writer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.PlayerModelPart;
import net.minecraft.world.level.GameType;
import org.jetbrains.annotations.Nullable;
public class ClientboundPlayerInfoUpdatePacket implements Packet<ClientGamePacketListener> {
public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundPlayerInfoUpdatePacket> STREAM_CODEC = Packet.codec(
ClientboundPlayerInfoUpdatePacket::write, ClientboundPlayerInfoUpdatePacket::new
);
private final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions;
private final List<ClientboundPlayerInfoUpdatePacket.Entry> entries;
public ClientboundPlayerInfoUpdatePacket(EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions, Collection<ServerPlayer> players) {
this.actions = actions;
this.entries = players.stream().map(ClientboundPlayerInfoUpdatePacket.Entry::new).toList();
}
public ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action action, ServerPlayer player) {
this.actions = EnumSet.of(action);
this.entries = List.of(new ClientboundPlayerInfoUpdatePacket.Entry(player));
}
public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection<ServerPlayer> players) {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(
ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LIST_ORDER
);
return new ClientboundPlayerInfoUpdatePacket(enumSet, players);
}
private ClientboundPlayerInfoUpdatePacket(RegistryFriendlyByteBuf buffer) {
this.actions = buffer.readEnumSet(ClientboundPlayerInfoUpdatePacket.Action.class);
this.entries = buffer.readList(friendlyByteBuf -> {
ClientboundPlayerInfoUpdatePacket.EntryBuilder entryBuilder = new ClientboundPlayerInfoUpdatePacket.EntryBuilder(friendlyByteBuf.readUUID());
for (ClientboundPlayerInfoUpdatePacket.Action action : this.actions) {
action.reader.read(entryBuilder, (RegistryFriendlyByteBuf)friendlyByteBuf);
}
return entryBuilder.build();
});
}
private void write(RegistryFriendlyByteBuf buffer) {
buffer.writeEnumSet(this.actions, ClientboundPlayerInfoUpdatePacket.Action.class);
buffer.writeCollection(this.entries, (friendlyByteBuf, entry) -> {
friendlyByteBuf.writeUUID(entry.profileId());
for (ClientboundPlayerInfoUpdatePacket.Action action : this.actions) {
action.writer.write((RegistryFriendlyByteBuf)friendlyByteBuf, entry);
}
});
}
@Override
public PacketType<ClientboundPlayerInfoUpdatePacket> type() {
return GamePacketTypes.CLIENTBOUND_PLAYER_INFO_UPDATE;
}
public void handle(ClientGamePacketListener clientGamePacketListener) {
clientGamePacketListener.handlePlayerInfoUpdate(this);
}
public EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions() {
return this.actions;
}
public List<ClientboundPlayerInfoUpdatePacket.Entry> entries() {
return this.entries;
}
public List<ClientboundPlayerInfoUpdatePacket.Entry> newEntries() {
return this.actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER) ? this.entries : List.of();
}
public String toString() {
return MoreObjects.toStringHelper(this).add("actions", this.actions).add("entries", this.entries).toString();
}
public static enum Action {
ADD_PLAYER((entryBuilder, registryFriendlyByteBuf) -> {
GameProfile gameProfile = new GameProfile(entryBuilder.profileId, registryFriendlyByteBuf.readUtf(16));
gameProfile.getProperties().putAll(ByteBufCodecs.GAME_PROFILE_PROPERTIES.decode(registryFriendlyByteBuf));
entryBuilder.profile = gameProfile;
}, (registryFriendlyByteBuf, entry) -> {
GameProfile gameProfile = (GameProfile)Objects.requireNonNull(entry.profile());
registryFriendlyByteBuf.writeUtf(gameProfile.getName(), 16);
ByteBufCodecs.GAME_PROFILE_PROPERTIES.encode(registryFriendlyByteBuf, gameProfile.getProperties());
}),
INITIALIZE_CHAT(
(entryBuilder, registryFriendlyByteBuf) -> entryBuilder.chatSession = registryFriendlyByteBuf.readNullable(Data::read),
(registryFriendlyByteBuf, entry) -> registryFriendlyByteBuf.writeNullable(entry.chatSession, Data::write)
),
UPDATE_GAME_MODE(
(entryBuilder, registryFriendlyByteBuf) -> entryBuilder.gameMode = GameType.byId(registryFriendlyByteBuf.readVarInt()),
(registryFriendlyByteBuf, entry) -> registryFriendlyByteBuf.writeVarInt(entry.gameMode().getId())
),
UPDATE_LISTED(
(entryBuilder, registryFriendlyByteBuf) -> entryBuilder.listed = registryFriendlyByteBuf.readBoolean(),
(registryFriendlyByteBuf, entry) -> registryFriendlyByteBuf.writeBoolean(entry.listed())
),
UPDATE_LATENCY(
(entryBuilder, registryFriendlyByteBuf) -> entryBuilder.latency = registryFriendlyByteBuf.readVarInt(),
(registryFriendlyByteBuf, entry) -> registryFriendlyByteBuf.writeVarInt(entry.latency())
),
UPDATE_DISPLAY_NAME(
(entryBuilder, registryFriendlyByteBuf) -> entryBuilder.displayName = FriendlyByteBuf.readNullable(
registryFriendlyByteBuf, ComponentSerialization.TRUSTED_STREAM_CODEC
),
(registryFriendlyByteBuf, entry) -> FriendlyByteBuf.writeNullable(registryFriendlyByteBuf, entry.displayName(), ComponentSerialization.TRUSTED_STREAM_CODEC)
),
UPDATE_LIST_ORDER(
(entryBuilder, registryFriendlyByteBuf) -> entryBuilder.listOrder = registryFriendlyByteBuf.readVarInt(),
(registryFriendlyByteBuf, entry) -> registryFriendlyByteBuf.writeVarInt(entry.listOrder)
),
UPDATE_HAT(
(entryBuilder, registryFriendlyByteBuf) -> entryBuilder.showHat = registryFriendlyByteBuf.readBoolean(),
(registryFriendlyByteBuf, entry) -> registryFriendlyByteBuf.writeBoolean(entry.showHat)
);
final Reader reader;
final Writer writer;
private Action(final Reader reader, final Writer writer) {
this.reader = reader;
this.writer = writer;
}
}
public record Entry(
UUID profileId,
@Nullable GameProfile profile,
boolean listed,
int latency,
GameType gameMode,
@Nullable Component displayName,
boolean showHat,
int listOrder,
@Nullable Data chatSession
) {
Entry(ServerPlayer player) {
this(
player.getUUID(),
player.getGameProfile(),
true,
player.connection.latency(),
player.gameMode.getGameModeForPlayer(),
player.getTabListDisplayName(),
player.isModelPartShown(PlayerModelPart.HAT),
player.getTabListOrder(),
Optionull.map(player.getChatSession(), RemoteChatSession::asData)
);
}
}
static class EntryBuilder {
final UUID profileId;
@Nullable
GameProfile profile;
boolean listed;
int latency;
GameType gameMode = GameType.DEFAULT_MODE;
@Nullable
Component displayName;
boolean showHat;
int listOrder;
@Nullable
Data chatSession;
EntryBuilder(UUID profileId) {
this.profileId = profileId;
}
ClientboundPlayerInfoUpdatePacket.Entry build() {
return new ClientboundPlayerInfoUpdatePacket.Entry(
this.profileId, this.profile, this.listed, this.latency, this.gameMode, this.displayName, this.showHat, this.listOrder, this.chatSession
);
}
}
}