PlayerList.java

net.minecraft.server.players.PlayerList

信息

  • 全限定名:net.minecraft.server.players.PlayerList
  • 类型:public abstract class
  • 包:net.minecraft.server.players
  • 源码路径:src/main/java/net/minecraft/server/players/PlayerList.java
  • 起始行号:L105
  • 职责:

    TODO

字段/常量

  • USERBANLIST_FILE

    • 类型: File
    • 修饰符: public static final
    • 源码定位: L106
    • 说明:

      TODO

  • IPBANLIST_FILE

    • 类型: File
    • 修饰符: public static final
    • 源码定位: L107
    • 说明:

      TODO

  • OPLIST_FILE

    • 类型: File
    • 修饰符: public static final
    • 源码定位: L108
    • 说明:

      TODO

  • WHITELIST_FILE

    • 类型: File
    • 修饰符: public static final
    • 源码定位: L109
    • 说明:

      TODO

  • CHAT_FILTERED_FULL

    • 类型: Component
    • 修饰符: public static final
    • 源码定位: L110
    • 说明:

      TODO

  • DUPLICATE_LOGIN_DISCONNECT_MESSAGE

    • 类型: Component
    • 修饰符: public static final
    • 源码定位: L111
    • 说明:

      TODO

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L112
    • 说明:

      TODO

  • SEND_PLAYER_INFO_INTERVAL

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L113
    • 说明:

      TODO

  • BAN_DATE_FORMAT

    • 类型: SimpleDateFormat
    • 修饰符: private static final
    • 源码定位: L114
    • 说明:

      TODO

  • server

    • 类型: MinecraftServer
    • 修饰符: private final
    • 源码定位: L115
    • 说明:

      TODO

  • players

    • 类型: List<ServerPlayer>
    • 修饰符: private final
    • 源码定位: L116
    • 说明:

      TODO

  • playersByUUID

    • 类型: Map<UUID,ServerPlayer>
    • 修饰符: private final
    • 源码定位: L117
    • 说明:

      TODO

  • bans

    • 类型: UserBanList
    • 修饰符: private final
    • 源码定位: L118
    • 说明:

      TODO

  • ipBans

    • 类型: IpBanList
    • 修饰符: private final
    • 源码定位: L119
    • 说明:

      TODO

  • ops

    • 类型: ServerOpList
    • 修饰符: private final
    • 源码定位: L120
    • 说明:

      TODO

  • whitelist

    • 类型: UserWhiteList
    • 修饰符: private final
    • 源码定位: L121
    • 说明:

      TODO

  • stats

    • 类型: Map<UUID,ServerStatsCounter>
    • 修饰符: private final
    • 源码定位: L122
    • 说明:

      TODO

  • advancements

    • 类型: Map<UUID,PlayerAdvancements>
    • 修饰符: private final
    • 源码定位: L123
    • 说明:

      TODO

  • playerIo

    • 类型: PlayerDataStorage
    • 修饰符: private final
    • 源码定位: L124
    • 说明:

      TODO

  • registries

    • 类型: LayeredRegistryAccess<RegistryLayer>
    • 修饰符: private final
    • 源码定位: L125
    • 说明:

      TODO

  • viewDistance

    • 类型: int
    • 修饰符: private
    • 源码定位: L126
    • 说明:

      TODO

  • simulationDistance

    • 类型: int
    • 修饰符: private
    • 源码定位: L127
    • 说明:

      TODO

  • allowCommandsForAllPlayers

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L128
    • 说明:

      TODO

  • sendAllPlayerInfoIn

    • 类型: int
    • 修饰符: private
    • 源码定位: L129
    • 说明:

      TODO

内部类/嵌套类型

构造器

public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registries, PlayerDataStorage playerIo, NotificationService notificationService) @ L131

  • 构造器名:PlayerList
  • 源码定位:L131
  • 修饰符:public

参数:

  • server: MinecraftServer
  • registries: LayeredRegistryAccess
  • playerIo: PlayerDataStorage
  • notificationService: NotificationService

说明:

TODO

方法

下面的方法块按源码顺序生成。

  • 方法名:placeNewPlayer
  • 源码定位:L143
  • 返回类型:void
  • 修饰符:public

参数:

  • connection: Connection
  • player: ServerPlayer
  • cookie: CommonListenerCookie

说明:

TODO

protected void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) @ L224

  • 方法名:updateEntireScoreboard
  • 源码定位:L224
  • 返回类型:void
  • 修饰符:protected

参数:

  • scoreboard: ServerScoreboard
  • player: ServerPlayer

说明:

TODO

public void addWorldborderListener(ServerLevel level) @ L243

  • 方法名:addWorldborderListener
  • 源码定位:L243
  • 返回类型:void
  • 修饰符:public

参数:

  • level: ServerLevel

说明:

TODO

public Optional<CompoundTag> loadPlayerData(NameAndId nameAndId) @ L284

  • 方法名:loadPlayerData
  • 源码定位:L284
  • 返回类型:Optional
  • 修饰符:public

参数:

  • nameAndId: NameAndId

说明:

TODO

protected void save(ServerPlayer player) @ L294

  • 方法名:save
  • 源码定位:L294
  • 返回类型:void
  • 修饰符:protected

参数:

  • player: ServerPlayer

说明:

TODO

public void remove(ServerPlayer player) @ L307

  • 方法名:remove
  • 源码定位:L307
  • 返回类型:void
  • 修饰符:public

参数:

  • player: ServerPlayer

说明:

TODO

public Component canPlayerLogin(SocketAddress address, NameAndId nameAndId) @ L342

  • 方法名:canPlayerLogin
  • 源码定位:L342
  • 返回类型:Component
  • 修饰符:public

参数:

  • address: SocketAddress
  • nameAndId: NameAndId

说明:

TODO

public boolean disconnectAllPlayersWithProfile(UUID playerId) @ L368

  • 方法名:disconnectAllPlayersWithProfile
  • 源码定位:L368
  • 返回类型:boolean
  • 修饰符:public

参数:

  • playerId: UUID

说明:

TODO

public ServerPlayer respawn(ServerPlayer serverPlayer, boolean keepAllPlayerData, Entity.RemovalReason removalReason) @ L389

  • 方法名:respawn
  • 源码定位:L389
  • 返回类型:ServerPlayer
  • 修饰符:public

参数:

  • serverPlayer: ServerPlayer
  • keepAllPlayerData: boolean
  • removalReason: Entity.RemovalReason

说明:

TODO

public void sendActivePlayerEffects(ServerPlayer player) @ L457

  • 方法名:sendActivePlayerEffects
  • 源码定位:L457
  • 返回类型:void
  • 修饰符:public

参数:

  • player: ServerPlayer

说明:

TODO

public void sendActiveEffects(LivingEntity livingEntity, ServerGamePacketListenerImpl connection) @ L461

  • 方法名:sendActiveEffects
  • 源码定位:L461
  • 返回类型:void
  • 修饰符:public

参数:

  • livingEntity: LivingEntity
  • connection: ServerGamePacketListenerImpl

说明:

TODO

public void sendPlayerPermissionLevel(ServerPlayer player) @ L467

  • 方法名:sendPlayerPermissionLevel
  • 源码定位:L467
  • 返回类型:void
  • 修饰符:public

参数:

  • player: ServerPlayer

说明:

TODO

public void tick() @ L472

  • 方法名:tick
  • 源码定位:L472
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void broadcastAll(Packet<?> packet) @ L479

  • 方法名:broadcastAll
  • 源码定位:L479
  • 返回类型:void
  • 修饰符:public

参数:

  • packet: Packet<?>

说明:

TODO

public void broadcastAll(Packet<?> packet, ResourceKey<Level> dimension) @ L485

  • 方法名:broadcastAll
  • 源码定位:L485
  • 返回类型:void
  • 修饰符:public

参数:

  • packet: Packet<?>
  • dimension: ResourceKey

说明:

TODO

public void broadcastSystemToTeam(Player player, Component message) @ L493

  • 方法名:broadcastSystemToTeam
  • 源码定位:L493
  • 返回类型:void
  • 修饰符:public

参数:

  • player: Player
  • message: Component

说明:

TODO

public void broadcastSystemToAllExceptTeam(Player player, Component message) @ L505

  • 方法名:broadcastSystemToAllExceptTeam
  • 源码定位:L505
  • 返回类型:void
  • 修饰符:public

参数:

  • player: Player
  • message: Component

说明:

TODO

public String[] getPlayerNamesArray() @ L519

  • 方法名:getPlayerNamesArray
  • 源码定位:L519
  • 返回类型:String[]
  • 修饰符:public

参数:

说明:

TODO

public UserBanList getBans() @ L529

  • 方法名:getBans
  • 源码定位:L529
  • 返回类型:UserBanList
  • 修饰符:public

参数:

说明:

TODO

public IpBanList getIpBans() @ L533

  • 方法名:getIpBans
  • 源码定位:L533
  • 返回类型:IpBanList
  • 修饰符:public

参数:

说明:

TODO

public void op(NameAndId nameAndId) @ L537

  • 方法名:op
  • 源码定位:L537
  • 返回类型:void
  • 修饰符:public

参数:

  • nameAndId: NameAndId

说明:

TODO

public void op(NameAndId nameAndId, Optional<LevelBasedPermissionSet> permissions, Optional<Boolean> canBypassPlayerLimit) @ L541

  • 方法名:op
  • 源码定位:L541
  • 返回类型:void
  • 修饰符:public

参数:

  • nameAndId: NameAndId
  • permissions: Optional
  • canBypassPlayerLimit: Optional

说明:

TODO

public void deop(NameAndId nameAndId) @ L554

  • 方法名:deop
  • 源码定位:L554
  • 返回类型:void
  • 修饰符:public

参数:

  • nameAndId: NameAndId

说明:

TODO

private void sendPlayerPermissionLevel(ServerPlayer player, LevelBasedPermissionSet permissions) @ L563

  • 方法名:sendPlayerPermissionLevel
  • 源码定位:L563
  • 返回类型:void
  • 修饰符:private

参数:

  • player: ServerPlayer
  • permissions: LevelBasedPermissionSet

说明:

TODO

public boolean isWhiteListed(NameAndId nameAndId) @ L578

  • 方法名:isWhiteListed
  • 源码定位:L578
  • 返回类型:boolean
  • 修饰符:public

参数:

  • nameAndId: NameAndId

说明:

TODO

public boolean isOp(NameAndId nameAndId) @ L582

  • 方法名:isOp
  • 源码定位:L582
  • 返回类型:boolean
  • 修饰符:public

参数:

  • nameAndId: NameAndId

说明:

TODO

public ServerPlayer getPlayerByName(String name) @ L588

  • 方法名:getPlayerByName
  • 源码定位:L588
  • 返回类型:ServerPlayer
  • 修饰符:public

参数:

  • name: String

说明:

TODO

public void broadcast(Player except, double x, double y, double z, double range, ResourceKey<Level> dimension, Packet<?> packet) @ L601

  • 方法名:broadcast
  • 源码定位:L601
  • 返回类型:void
  • 修饰符:public

参数:

  • except: Player
  • x: double
  • y: double
  • z: double
  • range: double
  • dimension: ResourceKey
  • packet: Packet<?>

说明:

TODO

public void saveAll() @ L615

  • 方法名:saveAll
  • 源码定位:L615
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public UserWhiteList getWhiteList() @ L621

  • 方法名:getWhiteList
  • 源码定位:L621
  • 返回类型:UserWhiteList
  • 修饰符:public

参数:

说明:

TODO

public String[] getWhiteListNames() @ L625

  • 方法名:getWhiteListNames
  • 源码定位:L625
  • 返回类型:String[]
  • 修饰符:public

参数:

说明:

TODO

public ServerOpList getOps() @ L629

  • 方法名:getOps
  • 源码定位:L629
  • 返回类型:ServerOpList
  • 修饰符:public

参数:

说明:

TODO

public String[] getOpNames() @ L633

  • 方法名:getOpNames
  • 源码定位:L633
  • 返回类型:String[]
  • 修饰符:public

参数:

说明:

TODO

public void reloadWhiteList() @ L637

  • 方法名:reloadWhiteList
  • 源码定位:L637
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void sendLevelInfo(ServerPlayer player, ServerLevel level) @ L640

  • 方法名:sendLevelInfo
  • 源码定位:L640
  • 返回类型:void
  • 修饰符:public

参数:

  • player: ServerPlayer
  • level: ServerLevel

说明:

TODO

public void sendAllPlayerInfo(ServerPlayer player) @ L655

  • 方法名:sendAllPlayerInfo
  • 源码定位:L655
  • 返回类型:void
  • 修饰符:public

参数:

  • player: ServerPlayer

说明:

TODO

public int getPlayerCount() @ L661

  • 方法名:getPlayerCount
  • 源码定位:L661
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public int getMaxPlayers() @ L665

  • 方法名:getMaxPlayers
  • 源码定位:L665
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public boolean isUsingWhitelist() @ L669

  • 方法名:isUsingWhitelist
  • 源码定位:L669
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public List<ServerPlayer> getPlayersWithAddress(String ip) @ L673

  • 方法名:getPlayersWithAddress
  • 源码定位:L673
  • 返回类型:List
  • 修饰符:public

参数:

  • ip: String

说明:

TODO

public int getViewDistance() @ L685

  • 方法名:getViewDistance
  • 源码定位:L685
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public int getSimulationDistance() @ L689

  • 方法名:getSimulationDistance
  • 源码定位:L689
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public MinecraftServer getServer() @ L693

  • 方法名:getServer
  • 源码定位:L693
  • 返回类型:MinecraftServer
  • 修饰符:public

参数:

说明:

TODO

public void setAllowCommandsForAllPlayers(boolean allowCommands) @ L697

  • 方法名:setAllowCommandsForAllPlayers
  • 源码定位:L697
  • 返回类型:void
  • 修饰符:public

参数:

  • allowCommands: boolean

说明:

TODO

public void removeAll() @ L701

  • 方法名:removeAll
  • 源码定位:L701
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void broadcastSystemMessage(Component message, boolean overlay) @ L707

  • 方法名:broadcastSystemMessage
  • 源码定位:L707
  • 返回类型:void
  • 修饰符:public

参数:

  • message: Component
  • overlay: boolean

说明:

TODO

public void broadcastSystemMessage(Component message, Function<ServerPlayer,Component> playerMessages, boolean overlay) @ L711

  • 方法名:broadcastSystemMessage
  • 源码定位:L711
  • 返回类型:void
  • 修饰符:public

参数:

  • message: Component
  • playerMessages: Function<ServerPlayer,Component>
  • overlay: boolean

说明:

TODO

public void broadcastChatMessage(PlayerChatMessage message, CommandSourceStack sender, ChatType.Bound chatType) @ L722

  • 方法名:broadcastChatMessage
  • 源码定位:L722
  • 返回类型:void
  • 修饰符:public

参数:

  • message: PlayerChatMessage
  • sender: CommandSourceStack
  • chatType: ChatType.Bound

说明:

TODO

public void broadcastChatMessage(PlayerChatMessage message, ServerPlayer sender, ChatType.Bound chatType) @ L726

  • 方法名:broadcastChatMessage
  • 源码定位:L726
  • 返回类型:void
  • 修饰符:public

参数:

  • message: PlayerChatMessage
  • sender: ServerPlayer
  • chatType: ChatType.Bound

说明:

TODO

private void broadcastChatMessage(PlayerChatMessage message, Predicate<ServerPlayer> isFiltered, ServerPlayer senderPlayer, ChatType.Bound chatType) @ L730

  • 方法名:broadcastChatMessage
  • 源码定位:L730
  • 返回类型:void
  • 修饰符:private

参数:

  • message: PlayerChatMessage
  • isFiltered: Predicate
  • senderPlayer: ServerPlayer
  • chatType: ChatType.Bound

说明:

TODO

private boolean verifyChatTrusted(PlayerChatMessage message) @ L749

  • 方法名:verifyChatTrusted
  • 源码定位:L749
  • 返回类型:boolean
  • 修饰符:private

参数:

  • message: PlayerChatMessage

说明:

TODO

public ServerStatsCounter getPlayerStats(Player player) @ L753

  • 方法名:getPlayerStats
  • 源码定位:L753
  • 返回类型:ServerStatsCounter
  • 修饰符:public

参数:

  • player: Player

说明:

TODO

private Path locateStatsFile(GameProfile gameProfile) @ L761

  • 方法名:locateStatsFile
  • 源码定位:L761
  • 返回类型:Path
  • 修饰符:private

参数:

  • gameProfile: GameProfile

说明:

TODO

public PlayerAdvancements getPlayerAdvancements(ServerPlayer player) @ L784

  • 方法名:getPlayerAdvancements
  • 源码定位:L784
  • 返回类型:PlayerAdvancements
  • 修饰符:public

参数:

  • player: ServerPlayer

说明:

TODO

public void setViewDistance(int viewDistance) @ L797

  • 方法名:setViewDistance
  • 源码定位:L797
  • 返回类型:void
  • 修饰符:public

参数:

  • viewDistance: int

说明:

TODO

public void setSimulationDistance(int simulationDistance) @ L806

  • 方法名:setSimulationDistance
  • 源码定位:L806
  • 返回类型:void
  • 修饰符:public

参数:

  • simulationDistance: int

说明:

TODO

public List<ServerPlayer> getPlayers() @ L815

  • 方法名:getPlayers
  • 源码定位:L815
  • 返回类型:List
  • 修饰符:public

参数:

说明:

TODO

public ServerPlayer getPlayer(UUID uuid) @ L819

  • 方法名:getPlayer
  • 源码定位:L819
  • 返回类型:ServerPlayer
  • 修饰符:public

参数:

  • uuid: UUID

说明:

TODO

public ServerPlayer getPlayer(String playerName) @ L823

  • 方法名:getPlayer
  • 源码定位:L823
  • 返回类型:ServerPlayer
  • 修饰符:public

参数:

  • playerName: String

说明:

TODO

public boolean canBypassPlayerLimit(NameAndId nameAndId) @ L833

  • 方法名:canBypassPlayerLimit
  • 源码定位:L833
  • 返回类型:boolean
  • 修饰符:public

参数:

  • nameAndId: NameAndId

说明:

TODO

public void reloadResources() @ L837

  • 方法名:reloadResources
  • 源码定位:L837
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public boolean isAllowCommandsForAllPlayers() @ L854

  • 方法名:isAllowCommandsForAllPlayers
  • 源码定位:L854
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

代码

public abstract class PlayerList {
    public static final File USERBANLIST_FILE = new File("banned-players.json");
    public static final File IPBANLIST_FILE = new File("banned-ips.json");
    public static final File OPLIST_FILE = new File("ops.json");
    public static final File WHITELIST_FILE = new File("whitelist.json");
    public static final Component CHAT_FILTERED_FULL = Component.translatable("chat.filtered_full");
    public static final Component DUPLICATE_LOGIN_DISCONNECT_MESSAGE = Component.translatable("multiplayer.disconnect.duplicate_login");
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final int SEND_PLAYER_INFO_INTERVAL = 600;
    private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z", Locale.ROOT);
    private final MinecraftServer server;
    private final List<ServerPlayer> players = Lists.newArrayList();
    private final Map<UUID, ServerPlayer> playersByUUID = Maps.newHashMap();
    private final UserBanList bans;
    private final IpBanList ipBans;
    private final ServerOpList ops;
    private final UserWhiteList whitelist;
    private final Map<UUID, ServerStatsCounter> stats = Maps.newHashMap();
    private final Map<UUID, PlayerAdvancements> advancements = Maps.newHashMap();
    private final PlayerDataStorage playerIo;
    private final LayeredRegistryAccess<RegistryLayer> registries;
    private int viewDistance;
    private int simulationDistance;
    private boolean allowCommandsForAllPlayers;
    private int sendAllPlayerInfoIn;
 
    public PlayerList(
        MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registries, PlayerDataStorage playerIo, NotificationService notificationService
    ) {
        this.server = server;
        this.registries = registries;
        this.playerIo = playerIo;
        this.whitelist = new UserWhiteList(WHITELIST_FILE, notificationService);
        this.ops = new ServerOpList(OPLIST_FILE, notificationService);
        this.bans = new UserBanList(USERBANLIST_FILE, notificationService);
        this.ipBans = new IpBanList(IPBANLIST_FILE, notificationService);
    }
 
    public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie cookie) {
        NameAndId gameProfile = player.nameAndId();
        UserNameToIdResolver profileCache = this.server.services().nameToIdCache();
        Optional<NameAndId> oldProfile = profileCache.get(gameProfile.id());
        String oldName = oldProfile.map(NameAndId::name).orElse(gameProfile.name());
        profileCache.add(gameProfile);
        ServerLevel level = player.level();
        String address = connection.getLoggableAddress(this.server.logIPs());
        LOGGER.info(
            "{}[{}] logged in with entity id {} at ({}, {}, {})",
            player.getPlainTextName(),
            address,
            player.getId(),
            player.getX(),
            player.getY(),
            player.getZ()
        );
        LevelData levelData = level.getLevelData();
        ServerGamePacketListenerImpl playerConnection = new ServerGamePacketListenerImpl(this.server, connection, player, cookie);
        connection.setupInboundProtocol(
            GameProtocols.SERVERBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()), playerConnection), playerConnection
        );
        playerConnection.suspendFlushing();
        GameRules gameRules = level.getGameRules();
        boolean immediateRespawn = gameRules.get(GameRules.IMMEDIATE_RESPAWN);
        boolean reducedDebugInfo = gameRules.get(GameRules.REDUCED_DEBUG_INFO);
        boolean doLimitedCrafting = gameRules.get(GameRules.LIMITED_CRAFTING);
        playerConnection.send(
            new ClientboundLoginPacket(
                player.getId(),
                levelData.isHardcore(),
                this.server.levelKeys(),
                this.getMaxPlayers(),
                this.getViewDistance(),
                this.getSimulationDistance(),
                reducedDebugInfo,
                !immediateRespawn,
                doLimitedCrafting,
                player.createCommonSpawnInfo(level),
                this.server.enforceSecureProfile()
            )
        );
        playerConnection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked()));
        playerConnection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities()));
        playerConnection.send(new ClientboundSetHeldSlotPacket(player.getInventory().getSelectedSlot()));
        RecipeManager recipeManager = this.server.getRecipeManager();
        playerConnection.send(
            new ClientboundUpdateRecipesPacket(recipeManager.getSynchronizedItemProperties(), recipeManager.getSynchronizedStonecutterRecipes())
        );
        this.sendPlayerPermissionLevel(player);
        player.getStats().markAllDirty();
        player.getRecipeBook().sendInitialRecipeBook(player);
        this.updateEntireScoreboard(level.getScoreboard(), player);
        this.server.invalidateStatus();
        MutableComponent component;
        if (player.getGameProfile().name().equalsIgnoreCase(oldName)) {
            component = Component.translatable("multiplayer.player.joined", player.getDisplayName());
        } else {
            component = Component.translatable("multiplayer.player.joined.renamed", player.getDisplayName(), oldName);
        }
 
        this.broadcastSystemMessage(component.withStyle(ChatFormatting.YELLOW), false);
        playerConnection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot());
        ServerStatus status = this.server.getStatus();
        if (status != null && !cookie.transferred()) {
            player.sendServerStatus(status);
        }
 
        player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players));
        this.players.add(player);
        this.playersByUUID.put(player.getUUID(), player);
        this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)));
        this.sendLevelInfo(player, level);
        level.addNewPlayer(player);
        this.server.getCustomBossEvents().onPlayerConnect(player);
        this.sendActivePlayerEffects(player);
        player.initInventoryMenu();
        this.server.notificationManager().playerJoined(player);
        playerConnection.resumeFlushing();
    }
 
    protected void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) {
        Set<Objective> objectives = Sets.newHashSet();
 
        for (PlayerTeam team : scoreboard.getPlayerTeams()) {
            player.connection.send(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true));
        }
 
        for (DisplaySlot slot : DisplaySlot.values()) {
            Objective objective = scoreboard.getDisplayObjective(slot);
            if (objective != null && !objectives.contains(objective)) {
                for (Packet<?> packet : scoreboard.getStartTrackingPackets(objective)) {
                    player.connection.send(packet);
                }
 
                objectives.add(objective);
            }
        }
    }
 
    public void addWorldborderListener(ServerLevel level) {
        level.getWorldBorder().addListener(new BorderChangeListener() {
            {
                Objects.requireNonNull(PlayerList.this);
            }
 
            @Override
            public void onSetSize(WorldBorder border, double newSize) {
                PlayerList.this.broadcastAll(new ClientboundSetBorderSizePacket(border), level.dimension());
            }
 
            @Override
            public void onLerpSize(WorldBorder border, double fromSize, double targetSize, long ticks, long gameTime) {
                PlayerList.this.broadcastAll(new ClientboundSetBorderLerpSizePacket(border), level.dimension());
            }
 
            @Override
            public void onSetCenter(WorldBorder border, double x, double z) {
                PlayerList.this.broadcastAll(new ClientboundSetBorderCenterPacket(border), level.dimension());
            }
 
            @Override
            public void onSetWarningTime(WorldBorder border, int time) {
                PlayerList.this.broadcastAll(new ClientboundSetBorderWarningDelayPacket(border), level.dimension());
            }
 
            @Override
            public void onSetWarningBlocks(WorldBorder border, int blocks) {
                PlayerList.this.broadcastAll(new ClientboundSetBorderWarningDistancePacket(border), level.dimension());
            }
 
            @Override
            public void onSetDamagePerBlock(WorldBorder border, double damagePerBlock) {
            }
 
            @Override
            public void onSetSafeZone(WorldBorder border, double safeZone) {
            }
        });
    }
 
    public Optional<CompoundTag> loadPlayerData(NameAndId nameAndId) {
        UUID lastSingleplayerOwnerUUID = this.server.getWorldData().getSinglePlayerUUID();
        if (this.server.isSingleplayerOwner(nameAndId) && lastSingleplayerOwnerUUID != null) {
            LOGGER.debug("loading single player");
            return this.playerIo.load(new NameAndId(lastSingleplayerOwnerUUID, "<singleplayer owner>"));
        } else {
            return this.playerIo.load(nameAndId);
        }
    }
 
    protected void save(ServerPlayer player) {
        this.playerIo.save(player);
        ServerStatsCounter stats = this.stats.get(player.getUUID());
        if (stats != null) {
            stats.save();
        }
 
        PlayerAdvancements advancements = this.advancements.get(player.getUUID());
        if (advancements != null) {
            advancements.save();
        }
    }
 
    public void remove(ServerPlayer player) {
        ServerLevel level = player.level();
        player.awardStat(Stats.LEAVE_GAME);
        this.save(player);
        if (player.isPassenger()) {
            Entity vehicle = player.getRootVehicle();
            if (vehicle.hasExactlyOnePlayerPassenger()) {
                LOGGER.debug("Removing player mount");
                player.stopRiding();
                vehicle.getPassengersAndSelf().forEach(e -> e.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER));
            }
        }
 
        player.unRide();
 
        for (ThrownEnderpearl enderpearl : player.getEnderPearls()) {
            enderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER);
        }
 
        level.removePlayerImmediately(player, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
        player.getAdvancements().stopListening();
        this.players.remove(player);
        this.server.getCustomBossEvents().onPlayerDisconnect(player);
        UUID uuid = player.getUUID();
        ServerPlayer serverPlayer = this.playersByUUID.get(uuid);
        if (serverPlayer == player) {
            this.playersByUUID.remove(uuid);
            this.stats.remove(uuid);
            this.advancements.remove(uuid);
            this.server.notificationManager().playerLeft(player);
        }
 
        this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(player.getUUID())));
    }
 
    public @Nullable Component canPlayerLogin(SocketAddress address, NameAndId nameAndId) {
        if (this.bans.isBanned(nameAndId)) {
            UserBanListEntry ban = this.bans.get(nameAndId);
            MutableComponent reason = Component.translatable("multiplayer.disconnect.banned.reason", ban.getReasonMessage());
            if (ban.getExpires() != null) {
                reason.append(Component.translatable("multiplayer.disconnect.banned.expiration", BAN_DATE_FORMAT.format(ban.getExpires())));
            }
 
            return reason;
        } else if (!this.isWhiteListed(nameAndId)) {
            return Component.translatable("multiplayer.disconnect.not_whitelisted");
        } else if (this.ipBans.isBanned(address)) {
            IpBanListEntry ban = this.ipBans.get(address);
            MutableComponent reason = Component.translatable("multiplayer.disconnect.banned_ip.reason", ban.getReasonMessage());
            if (ban.getExpires() != null) {
                reason.append(Component.translatable("multiplayer.disconnect.banned_ip.expiration", BAN_DATE_FORMAT.format(ban.getExpires())));
            }
 
            return reason;
        } else {
            return this.players.size() >= this.getMaxPlayers() && !this.canBypassPlayerLimit(nameAndId)
                ? Component.translatable("multiplayer.disconnect.server_full")
                : null;
        }
    }
 
    public boolean disconnectAllPlayersWithProfile(UUID playerId) {
        Set<ServerPlayer> dupes = Sets.newIdentityHashSet();
 
        for (ServerPlayer player : this.players) {
            if (player.getUUID().equals(playerId)) {
                dupes.add(player);
            }
        }
 
        ServerPlayer serverPlayer = this.playersByUUID.get(playerId);
        if (serverPlayer != null) {
            dupes.add(serverPlayer);
        }
 
        for (ServerPlayer playerx : dupes) {
            playerx.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE);
        }
 
        return !dupes.isEmpty();
    }
 
    public ServerPlayer respawn(ServerPlayer serverPlayer, boolean keepAllPlayerData, Entity.RemovalReason removalReason) {
        TeleportTransition respawnInfo = serverPlayer.findRespawnPositionAndUseSpawnBlock(!keepAllPlayerData, TeleportTransition.DO_NOTHING);
        this.players.remove(serverPlayer);
        serverPlayer.level().removePlayerImmediately(serverPlayer, removalReason);
        ServerLevel level = respawnInfo.newLevel();
        ServerPlayer player = new ServerPlayer(this.server, level, serverPlayer.getGameProfile(), serverPlayer.clientInformation());
        player.connection = serverPlayer.connection;
        player.restoreFrom(serverPlayer, keepAllPlayerData);
        player.setId(serverPlayer.getId());
        player.setMainArm(serverPlayer.getMainArm());
        if (!respawnInfo.missingRespawnBlock()) {
            player.copyRespawnPosition(serverPlayer);
        }
 
        for (String tag : serverPlayer.entityTags()) {
            player.addTag(tag);
        }
 
        Vec3 pos = respawnInfo.position();
        player.snapTo(pos.x, pos.y, pos.z, respawnInfo.yRot(), respawnInfo.xRot());
        if (respawnInfo.missingRespawnBlock()) {
            player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F));
        }
 
        byte dataToKeep = (byte)(keepAllPlayerData ? 1 : 0);
        ServerLevel playerLevel = player.level();
        LevelData levelData = playerLevel.getLevelData();
        player.connection.send(new ClientboundRespawnPacket(player.createCommonSpawnInfo(playerLevel), dataToKeep));
        player.connection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot());
        player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData()));
        player.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked()));
        player.connection.send(new ClientboundSetExperiencePacket(player.experienceProgress, player.totalExperience, player.experienceLevel));
        this.sendActivePlayerEffects(player);
        this.sendLevelInfo(player, level);
        this.sendPlayerPermissionLevel(player);
        level.addRespawnedPlayer(player);
        this.players.add(player);
        this.playersByUUID.put(player.getUUID(), player);
        player.initInventoryMenu();
        player.setHealth(player.getHealth());
        ServerPlayer.RespawnConfig respawnConfig = player.getRespawnConfig();
        if (!keepAllPlayerData && respawnConfig != null) {
            LevelData.RespawnData respawnData = respawnConfig.respawnData();
            ServerLevel respawnLevel = this.server.getLevel(respawnData.dimension());
            if (respawnLevel != null) {
                BlockPos respawnPosition = respawnData.pos();
                BlockState blockState = respawnLevel.getBlockState(respawnPosition);
                if (blockState.is(Blocks.RESPAWN_ANCHOR)) {
                    player.connection
                        .send(
                            new ClientboundSoundPacket(
                                SoundEvents.RESPAWN_ANCHOR_DEPLETE,
                                SoundSource.BLOCKS,
                                respawnPosition.getX(),
                                respawnPosition.getY(),
                                respawnPosition.getZ(),
                                1.0F,
                                1.0F,
                                level.getRandom().nextLong()
                            )
                        );
                }
            }
        }
 
        return player;
    }
 
    public void sendActivePlayerEffects(ServerPlayer player) {
        this.sendActiveEffects(player, player.connection);
    }
 
    public void sendActiveEffects(LivingEntity livingEntity, ServerGamePacketListenerImpl connection) {
        for (MobEffectInstance effect : livingEntity.getActiveEffects()) {
            connection.send(new ClientboundUpdateMobEffectPacket(livingEntity.getId(), effect, false));
        }
    }
 
    public void sendPlayerPermissionLevel(ServerPlayer player) {
        LevelBasedPermissionSet permissions = this.server.getProfilePermissions(player.nameAndId());
        this.sendPlayerPermissionLevel(player, permissions);
    }
 
    public void tick() {
        if (++this.sendAllPlayerInfoIn > 600) {
            this.broadcastAll(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY), this.players));
            this.sendAllPlayerInfoIn = 0;
        }
    }
 
    public void broadcastAll(Packet<?> packet) {
        for (ServerPlayer player : this.players) {
            player.connection.send(packet);
        }
    }
 
    public void broadcastAll(Packet<?> packet, ResourceKey<Level> dimension) {
        for (ServerPlayer player : this.players) {
            if (player.level().dimension() == dimension) {
                player.connection.send(packet);
            }
        }
    }
 
    public void broadcastSystemToTeam(Player player, Component message) {
        Team team = player.getTeam();
        if (team != null) {
            for (String name : team.getPlayers()) {
                ServerPlayer teamPlayer = this.getPlayerByName(name);
                if (teamPlayer != null && teamPlayer != player) {
                    teamPlayer.sendSystemMessage(message);
                }
            }
        }
    }
 
    public void broadcastSystemToAllExceptTeam(Player player, Component message) {
        Team team = player.getTeam();
        if (team == null) {
            this.broadcastSystemMessage(message, false);
        } else {
            for (int i = 0; i < this.players.size(); i++) {
                ServerPlayer targetPlayer = this.players.get(i);
                if (targetPlayer.getTeam() != team) {
                    targetPlayer.sendSystemMessage(message);
                }
            }
        }
    }
 
    public String[] getPlayerNamesArray() {
        String[] names = new String[this.players.size()];
 
        for (int i = 0; i < this.players.size(); i++) {
            names[i] = this.players.get(i).getGameProfile().name();
        }
 
        return names;
    }
 
    public UserBanList getBans() {
        return this.bans;
    }
 
    public IpBanList getIpBans() {
        return this.ipBans;
    }
 
    public void op(NameAndId nameAndId) {
        this.op(nameAndId, Optional.empty(), Optional.empty());
    }
 
    public void op(NameAndId nameAndId, Optional<LevelBasedPermissionSet> permissions, Optional<Boolean> canBypassPlayerLimit) {
        this.ops
            .add(
                new ServerOpListEntry(
                    nameAndId, permissions.orElse(this.server.operatorUserPermissions()), canBypassPlayerLimit.orElse(this.ops.canBypassPlayerLimit(nameAndId))
                )
            );
        ServerPlayer player = this.getPlayer(nameAndId.id());
        if (player != null) {
            this.sendPlayerPermissionLevel(player);
        }
    }
 
    public void deop(NameAndId nameAndId) {
        if (this.ops.remove(nameAndId)) {
            ServerPlayer player = this.getPlayer(nameAndId.id());
            if (player != null) {
                this.sendPlayerPermissionLevel(player);
            }
        }
    }
 
    private void sendPlayerPermissionLevel(ServerPlayer player, LevelBasedPermissionSet permissions) {
        if (player.connection != null) {
            byte eventId = switch (permissions.level()) {
                case ALL -> 24;
                case MODERATORS -> 25;
                case GAMEMASTERS -> 26;
                case ADMINS -> 27;
                case OWNERS -> 28;
            };
            player.connection.send(new ClientboundEntityEventPacket(player, eventId));
        }
 
        this.server.getCommands().sendCommands(player);
    }
 
    public boolean isWhiteListed(NameAndId nameAndId) {
        return !this.isUsingWhitelist() || this.ops.contains(nameAndId) || this.whitelist.contains(nameAndId);
    }
 
    public boolean isOp(NameAndId nameAndId) {
        return this.ops.contains(nameAndId)
            || this.server.isSingleplayerOwner(nameAndId) && this.server.getWorldData().isAllowCommands()
            || this.allowCommandsForAllPlayers;
    }
 
    public @Nullable ServerPlayer getPlayerByName(String name) {
        int size = this.players.size();
 
        for (int i = 0; i < size; i++) {
            ServerPlayer player = this.players.get(i);
            if (player.getGameProfile().name().equalsIgnoreCase(name)) {
                return player;
            }
        }
 
        return null;
    }
 
    public void broadcast(@Nullable Player except, double x, double y, double z, double range, ResourceKey<Level> dimension, Packet<?> packet) {
        for (int i = 0; i < this.players.size(); i++) {
            ServerPlayer player = this.players.get(i);
            if (player != except && player.level().dimension() == dimension) {
                double xd = x - player.getX();
                double yd = y - player.getY();
                double zd = z - player.getZ();
                if (xd * xd + yd * yd + zd * zd < range * range) {
                    player.connection.send(packet);
                }
            }
        }
    }
 
    public void saveAll() {
        for (int i = 0; i < this.players.size(); i++) {
            this.save(this.players.get(i));
        }
    }
 
    public UserWhiteList getWhiteList() {
        return this.whitelist;
    }
 
    public String[] getWhiteListNames() {
        return this.whitelist.getUserList();
    }
 
    public ServerOpList getOps() {
        return this.ops;
    }
 
    public String[] getOpNames() {
        return this.ops.getUserList();
    }
 
    public void reloadWhiteList() {
    }
 
    public void sendLevelInfo(ServerPlayer player, ServerLevel level) {
        WorldBorder worldBorder = level.getWorldBorder();
        player.connection.send(new ClientboundInitializeBorderPacket(worldBorder));
        player.connection.send(this.server.clockManager().createFullSyncPacket());
        player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData()));
        if (level.isRaining()) {
            player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0.0F));
            player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, level.getRainLevel(1.0F)));
            player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, level.getThunderLevel(1.0F)));
        }
 
        player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F));
        this.server.tickRateManager().updateJoiningPlayer(player);
    }
 
    public void sendAllPlayerInfo(ServerPlayer player) {
        player.inventoryMenu.sendAllDataToRemote();
        player.resetSentInfo();
        player.connection.send(new ClientboundSetHeldSlotPacket(player.getInventory().getSelectedSlot()));
    }
 
    public int getPlayerCount() {
        return this.players.size();
    }
 
    public int getMaxPlayers() {
        return this.server.getMaxPlayers();
    }
 
    public boolean isUsingWhitelist() {
        return this.server.isUsingWhitelist();
    }
 
    public List<ServerPlayer> getPlayersWithAddress(String ip) {
        List<ServerPlayer> result = Lists.newArrayList();
 
        for (ServerPlayer player : this.players) {
            if (player.getIpAddress().equals(ip)) {
                result.add(player);
            }
        }
 
        return result;
    }
 
    public int getViewDistance() {
        return this.viewDistance;
    }
 
    public int getSimulationDistance() {
        return this.simulationDistance;
    }
 
    public MinecraftServer getServer() {
        return this.server;
    }
 
    public void setAllowCommandsForAllPlayers(boolean allowCommands) {
        this.allowCommandsForAllPlayers = allowCommands;
    }
 
    public void removeAll() {
        for (int i = 0; i < this.players.size(); i++) {
            this.players.get(i).connection.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown"));
        }
    }
 
    public void broadcastSystemMessage(Component message, boolean overlay) {
        this.broadcastSystemMessage(message, player -> message, overlay);
    }
 
    public void broadcastSystemMessage(Component message, Function<ServerPlayer, Component> playerMessages, boolean overlay) {
        this.server.sendSystemMessage(message);
 
        for (ServerPlayer player : this.players) {
            Component playerMessage = playerMessages.apply(player);
            if (playerMessage != null) {
                player.sendSystemMessage(playerMessage, overlay);
            }
        }
    }
 
    public void broadcastChatMessage(PlayerChatMessage message, CommandSourceStack sender, ChatType.Bound chatType) {
        this.broadcastChatMessage(message, sender::shouldFilterMessageTo, sender.getPlayer(), chatType);
    }
 
    public void broadcastChatMessage(PlayerChatMessage message, ServerPlayer sender, ChatType.Bound chatType) {
        this.broadcastChatMessage(message, sender::shouldFilterMessageTo, sender, chatType);
    }
 
    private void broadcastChatMessage(
        PlayerChatMessage message, Predicate<ServerPlayer> isFiltered, @Nullable ServerPlayer senderPlayer, ChatType.Bound chatType
    ) {
        boolean trusted = this.verifyChatTrusted(message);
        this.server.logChatMessage(message.decoratedContent(), chatType, trusted ? null : "Not Secure");
        OutgoingChatMessage tracked = OutgoingChatMessage.create(message);
        boolean wasFullyFiltered = false;
 
        for (ServerPlayer player : this.players) {
            boolean filtered = isFiltered.test(player);
            player.sendChatMessage(tracked, filtered, chatType);
            wasFullyFiltered |= filtered && message.isFullyFiltered();
        }
 
        if (wasFullyFiltered && senderPlayer != null) {
            senderPlayer.sendSystemMessage(CHAT_FILTERED_FULL);
        }
    }
 
    private boolean verifyChatTrusted(PlayerChatMessage message) {
        return message.hasSignature() && !message.hasExpiredServer(Instant.now());
    }
 
    public ServerStatsCounter getPlayerStats(Player player) {
        GameProfile gameProfile = player.getGameProfile();
        return this.stats.computeIfAbsent(gameProfile.id(), id -> {
            Path targetFile = this.locateStatsFile(gameProfile);
            return new ServerStatsCounter(this.server, targetFile);
        });
    }
 
    private Path locateStatsFile(GameProfile gameProfile) {
        Path statFolder = this.server.getWorldPath(LevelResource.PLAYER_STATS_DIR);
        Path uuidStatsFile = statFolder.resolve(gameProfile.id() + ".json");
        if (Files.exists(uuidStatsFile)) {
            return uuidStatsFile;
        } else {
            String playerNameStatsFile = gameProfile.name() + ".json";
            if (FileUtil.isValidPathSegment(playerNameStatsFile)) {
                Path playerNameStatsPath = statFolder.resolve(playerNameStatsFile);
                if (Files.isRegularFile(playerNameStatsPath)) {
                    try {
                        return Files.move(playerNameStatsPath, uuidStatsFile);
                    } catch (IOException var7) {
                        LOGGER.warn("Failed to copy file {} to {}", playerNameStatsFile, uuidStatsFile);
                        return playerNameStatsPath;
                    }
                }
            }
 
            return uuidStatsFile;
        }
    }
 
    public PlayerAdvancements getPlayerAdvancements(ServerPlayer player) {
        UUID uuid = player.getUUID();
        PlayerAdvancements result = this.advancements.get(uuid);
        if (result == null) {
            Path uuidStatsFile = this.server.getWorldPath(LevelResource.PLAYER_ADVANCEMENTS_DIR).resolve(uuid + ".json");
            result = new PlayerAdvancements(this.server.getFixerUpper(), this, this.server.getAdvancements(), uuidStatsFile, player);
            this.advancements.put(uuid, result);
        }
 
        result.setPlayer(player);
        return result;
    }
 
    public void setViewDistance(int viewDistance) {
        this.viewDistance = viewDistance;
        this.broadcastAll(new ClientboundSetChunkCacheRadiusPacket(viewDistance));
 
        for (ServerLevel level : this.server.getAllLevels()) {
            level.getChunkSource().setViewDistance(viewDistance);
        }
    }
 
    public void setSimulationDistance(int simulationDistance) {
        this.simulationDistance = simulationDistance;
        this.broadcastAll(new ClientboundSetSimulationDistancePacket(simulationDistance));
 
        for (ServerLevel level : this.server.getAllLevels()) {
            level.getChunkSource().setSimulationDistance(simulationDistance);
        }
    }
 
    public List<ServerPlayer> getPlayers() {
        return this.players;
    }
 
    public @Nullable ServerPlayer getPlayer(UUID uuid) {
        return this.playersByUUID.get(uuid);
    }
 
    public @Nullable ServerPlayer getPlayer(String playerName) {
        for (ServerPlayer player : this.players) {
            if (player.getGameProfile().name().equalsIgnoreCase(playerName)) {
                return player;
            }
        }
 
        return null;
    }
 
    public boolean canBypassPlayerLimit(NameAndId nameAndId) {
        return false;
    }
 
    public void reloadResources() {
        for (PlayerAdvancements advancements : this.advancements.values()) {
            advancements.reload(this.server.getAdvancements());
        }
 
        this.broadcastAll(new ClientboundUpdateTagsPacket(TagNetworkSerialization.serializeTagsToNetwork(this.registries)));
        RecipeManager recipeManager = this.server.getRecipeManager();
        ClientboundUpdateRecipesPacket recipes = new ClientboundUpdateRecipesPacket(
            recipeManager.getSynchronizedItemProperties(), recipeManager.getSynchronizedStonecutterRecipes()
        );
 
        for (ServerPlayer player : this.players) {
            player.connection.send(recipes);
            player.getRecipeBook().sendInitialRecipeBook(player);
        }
    }
 
    public boolean isAllowCommandsForAllPlayers() {
        return this.allowCommandsForAllPlayers;
    }
}

引用的其他类